diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index be748161c51..925b70e62b4 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -16,7 +16,7 @@ jobs: - name: checkout uses: actions/checkout@v2 - name: set up java ${{ matrix.java-version }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v1.4.3 with: java-version: ${{ matrix.java-version }} - name: cache dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43aa4660ac8..37df6f0401c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - name: checkout uses: actions/checkout@v2 - name: set up java ${{ matrix.java-version }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v1.4.3 with: java-version: ${{ matrix.java-version }} - name: cache dependencies @@ -67,7 +67,7 @@ jobs: - name: checkout uses: actions/checkout@v2 - name: set up java 8 - uses: actions/setup-java@v1 + uses: actions/setup-java@v1.4.3 with: java-version: 8 - name: cache dependencies @@ -94,7 +94,7 @@ jobs: - name: checkout uses: actions/checkout@v2 - name: set up java 8 - uses: actions/setup-java@v1 + uses: actions/setup-java@v1.4.3 with: java-version: 8 - name: cache dependencies diff --git a/.gitignore b/.gitignore index 79a88e6c4af..b11176ef0b8 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ lib/ruby/gems lib/ruby/stdlib/**/maven-metadata-local.xml lib/ruby/stdlib/*.jar lib/ruby/stdlib/ant* +lib/ruby/stdlib/bundler* lib/ruby/stdlib/cmath.rb lib/ruby/stdlib/csv* lib/ruby/stdlib/did_you_mean* diff --git a/Gemfile b/Gemfile index ed86ed5ccde..b46f2d7374a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,4 @@ source 'https://rubygems.org' gem 'rspec', '3.9.0' +gem 'rspec-expectations', '3.9.2' # pinned to work around jruby/jruby#6452 diff --git a/README.md b/README.md index 1b267654966..ac6807f5c26 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # JRuby - an implementation of the Ruby language on the JVM -Master: [![Build Status](https://travis-ci.org/jruby/jruby.svg?branch=master)](https://travis-ci.org/jruby/jruby) -9.1 branch: [![Build Status](https://travis-ci.org/jruby/jruby.svg?branch=jruby-9.1)](https://travis-ci.org/jruby/jruby/branches) +Master: [![Build Status](https://travis-ci.com/jruby/jruby.svg?branch=master)](https://travis-ci.org/jruby/jruby) +9.2 branch: [![Build Status](https://travis-ci.com/jruby/jruby.svg?branch=jruby-9.2)](https://travis-ci.org/jruby/jruby/branches) ## About @@ -36,7 +36,7 @@ version is very old. An alternative is to use one of the [Ruby version managers](https://www.ruby-lang.org/en/documentation/installation/#managers). For [`rbenv`](https://github.com/sstephenson/rbenv) you will need the -[`ruby-build`](https://github.com/sstephenson/ruby-build) plugin. You may find that your system +[`ruby-build`](https://githubcom/sstephenson/ruby-build) plugin. You may find that your system package manager can provide these. To see which versions of JRuby are available you should run: ``` @@ -46,11 +46,11 @@ $ rbenv install jruby Note: if you do not regularly git update rbenv this list of versions may be out of date. We recommend always selecting the latest version of JRuby from the list. -You can install that particular version (9.1.17.0 is just for illustration): +You can install that particular version (9.2.13.0 is just for illustration): ``` -$ rbenv install jruby-9.1.17.0 +$ rbenv install jruby-9.2.13.0 ``` For [`rvm`](https://rvm.io) you can simply do: @@ -92,6 +92,14 @@ Project Contact: Thomas E Enebo ## License -JRuby is licensed to you under three licenses - the EPL 2.0, GPL 2 and LGPL 2.1. +JRuby is licensed under a tri EPL/GPL/LGPL license. You can use it, +redistribute it and/or modify it under the terms of the: + + Eclipse Public License version 2.0 + OR + GNU General Public License version 2 + OR + GNU Lesser General Public License version 2.1 + Some components have other licenses and copyright. See the [COPYING](COPYING) file for more specifics. diff --git a/core/pom.rb b/core/pom.rb index c02f61a5099..760fb75df7d 100644 --- a/core/pom.rb +++ b/core/pom.rb @@ -43,11 +43,11 @@ # exclude jnr-ffi to avoid problems with shading and relocation of the asm packages jar 'com.github.jnr:jnr-netdb:1.2.0', :exclusions => ['com.github.jnr:jnr-ffi'] - jar 'com.github.jnr:jnr-enxio:0.32.1', :exclusions => ['com.github.jnr:jnr-ffi'] - jar 'com.github.jnr:jnr-unixsocket:0.38.3', :exclusions => ['com.github.jnr:jnr-ffi'] - jar 'com.github.jnr:jnr-posix:3.1.2', :exclusions => ['com.github.jnr:jnr-ffi'] - jar 'com.github.jnr:jnr-constants:0.10.0', :exclusions => ['com.github.jnr:jnr-ffi'] - jar 'com.github.jnr:jnr-ffi:2.2.0' + jar 'com.github.jnr:jnr-enxio:0.32.3', :exclusions => ['com.github.jnr:jnr-ffi'] + jar 'com.github.jnr:jnr-unixsocket:0.38.5', :exclusions => ['com.github.jnr:jnr-ffi'] + jar 'com.github.jnr:jnr-posix:3.1.4', :exclusions => ['com.github.jnr:jnr-ffi'] + jar 'com.github.jnr:jnr-constants:0.10.1', :exclusions => ['com.github.jnr:jnr-ffi'] + jar 'com.github.jnr:jnr-ffi:2.2.1' jar 'com.github.jnr:jffi:${jffi.version}' jar 'com.github.jnr:jffi:${jffi.version}:native' diff --git a/core/pom.xml b/core/pom.xml index 5bbfcfa88a0..b238cfcd425 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -90,7 +90,7 @@ DO NOT MODIFIY - GENERATED CODE com.github.jnr jnr-enxio - 0.32.1 + 0.32.3 jnr-ffi @@ -101,7 +101,7 @@ DO NOT MODIFIY - GENERATED CODE com.github.jnr jnr-unixsocket - 0.38.3 + 0.38.5 jnr-ffi @@ -112,7 +112,7 @@ DO NOT MODIFIY - GENERATED CODE com.github.jnr jnr-posix - 3.1.2 + 3.1.4 jnr-ffi @@ -123,7 +123,7 @@ DO NOT MODIFIY - GENERATED CODE com.github.jnr jnr-constants - 0.10.0 + 0.10.1 jnr-ffi @@ -134,7 +134,7 @@ DO NOT MODIFIY - GENERATED CODE com.github.jnr jnr-ffi - 2.2.0 + 2.2.1 com.github.jnr diff --git a/core/src/main/java/org/jruby/IncludedModuleWrapper.java b/core/src/main/java/org/jruby/IncludedModuleWrapper.java index 1723f25e4cc..c6843a44222 100644 --- a/core/src/main/java/org/jruby/IncludedModuleWrapper.java +++ b/core/src/main/java/org/jruby/IncludedModuleWrapper.java @@ -197,6 +197,16 @@ protected IRubyObject getAutoloadConstant(String name, boolean forceLoad) { return origin.getAutoloadConstant(name, forceLoad); } + @Override + protected Map getAutoloadMap() { + return origin.getAutoloadMap(); + } + + @Override + protected Map getAutoloadMapForWrite() { + return origin.getAutoloadMapForWrite(); + } + @Override protected DynamicMethod searchMethodCommon(String id) { // IncludedModuleWrapper needs to search prepended modules too, so search until we find methodLocation diff --git a/core/src/main/java/org/jruby/Ruby.java b/core/src/main/java/org/jruby/Ruby.java index 6ef25edeb27..e4795103ea1 100644 --- a/core/src/main/java/org/jruby/Ruby.java +++ b/core/src/main/java/org/jruby/Ruby.java @@ -67,7 +67,6 @@ import org.jruby.javasupport.JavaPackage; import org.jruby.javasupport.JavaSupport; import org.jruby.javasupport.JavaSupportImpl; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.management.Caches; import org.jruby.management.InlineStats; import org.jruby.parser.StaticScope; @@ -563,10 +562,10 @@ private void initBootLibraries() { } // Provide some legacy libraries - loadService.provide("enumerator", "enumerator.rb"); - loadService.provide("rational", "rational.rb"); - loadService.provide("complex", "complex.rb"); - loadService.provide("thread", "thread.rb"); + loadService.provide("enumerator.rb"); + loadService.provide("rational.rb"); + loadService.provide("complex.rb"); + loadService.provide("thread.rb"); // Load preludes initRubyPreludes(); @@ -1116,20 +1115,20 @@ public IRubyObject runWithGetsLoop(RootNode scriptNode, boolean printing, boolea // Modifies incoming source for -n, -p, and -F private RootNode addGetsLoop(RootNode oldRoot, boolean printing, boolean processLineEndings, boolean split) { - ISourcePosition pos = oldRoot.getPosition(); - BlockNode newBody = new BlockNode(pos); + int line = oldRoot.getLine(); + BlockNode newBody = new BlockNode(line); RubySymbol dollarSlash = newSymbol(CommonByteLists.DOLLAR_SLASH); - newBody.add(new GlobalAsgnNode(pos, dollarSlash, new StrNode(pos, ((RubyString) globalVariables.get("$/")).getByteList()))); + newBody.add(new GlobalAsgnNode(line, dollarSlash, new StrNode(line, ((RubyString) globalVariables.get("$/")).getByteList()))); - if (processLineEndings) newBody.add(new GlobalAsgnNode(pos, newSymbol(CommonByteLists.DOLLAR_BACKSLASH), new GlobalVarNode(pos, dollarSlash))); + if (processLineEndings) newBody.add(new GlobalAsgnNode(line, newSymbol(CommonByteLists.DOLLAR_BACKSLASH), new GlobalVarNode(line, dollarSlash))); - GlobalVarNode dollarUnderscore = new GlobalVarNode(pos, newSymbol("$_")); + GlobalVarNode dollarUnderscore = new GlobalVarNode(line, newSymbol("$_")); - BlockNode whileBody = new BlockNode(pos); - newBody.add(new WhileNode(pos, new VCallNode(pos, newSymbol("gets")), whileBody)); + BlockNode whileBody = new BlockNode(line); + newBody.add(new WhileNode(line, new VCallNode(line, newSymbol("gets")), whileBody)); - if (processLineEndings) whileBody.add(new CallNode(pos, dollarUnderscore, newSymbol("chomp!"), null, null, false)); - if (split) whileBody.add(new GlobalAsgnNode(pos, newSymbol("$F"), new CallNode(pos, dollarUnderscore, newSymbol("split"), null, null, false))); + if (processLineEndings) whileBody.add(new CallNode(line, dollarUnderscore, newSymbol("chomp!"), null, null, false)); + if (split) whileBody.add(new GlobalAsgnNode(line, newSymbol("$F"), new CallNode(line, dollarUnderscore, newSymbol("split"), null, null, false))); if (oldRoot.getBodyNode() instanceof BlockNode) { // common case n stmts whileBody.addAll(((BlockNode) oldRoot.getBodyNode())); @@ -1137,9 +1136,9 @@ private RootNode addGetsLoop(RootNode oldRoot, boolean printing, boolean process whileBody.add(oldRoot.getBodyNode()); } - if (printing) whileBody.add(new FCallNode(pos, newSymbol("puts"), new ArrayNode(pos, dollarUnderscore), null)); + if (printing) whileBody.add(new FCallNode(line, newSymbol("puts"), new ArrayNode(line, dollarUnderscore), null)); - return new RootNode(pos, oldRoot.getScope(), newBody, oldRoot.getFile()); + return new RootNode(line, oldRoot.getScope(), newBody, oldRoot.getFile()); } /** @@ -1775,8 +1774,8 @@ private void initJavaSupport() { new Java().load(this, false); new JRubyUtilLibrary().load(this, false); - loadService.provide("java", "java.rb"); - loadService.provide("jruby/util", "jruby/util.rb"); + loadService.provide("java.rb"); + loadService.provide("jruby/util.rb"); } } @@ -3538,6 +3537,10 @@ public RubyString newString(String string) { return RubyString.newString(this, string); } + public RubyString newDeduplicatedString(String string) { + return freezeAndDedupString(RubyString.newString(this, string)); + } + public RubyString newString(ByteList byteList) { return RubyString.newString(this, byteList); } diff --git a/core/src/main/java/org/jruby/RubyArray.java b/core/src/main/java/org/jruby/RubyArray.java index a0b28c0d3af..206daef6f8c 100644 --- a/core/src/main/java/org/jruby/RubyArray.java +++ b/core/src/main/java/org/jruby/RubyArray.java @@ -512,6 +512,10 @@ public IRubyObject[] toJavaArrayMaybeUnsafe() { return (!isShared && begin == 0 && values.length == realLength) ? values : toJavaArray(); } + public boolean isSharedJavaArray(RubyArray other) { + return values == other.values && begin == other.begin && realLength == other.realLength; + } + /** rb_ary_make_shared * */ @@ -4337,76 +4341,124 @@ public IRubyObject choice(ThreadContext context) { return eltOk((int) (context.runtime.getDefaultRand().genrandReal() * realLength)); } + @JRubyMethod(name = "shuffle!") public IRubyObject shuffle_bang(ThreadContext context) { - return shuffle_bang(context, IRubyObject.NULL_ARRAY); + return shuffleBang(context, context.runtime.getRandomClass()); } - @JRubyMethod(name = "shuffle!", optional = 1) - public IRubyObject shuffle_bang(ThreadContext context, IRubyObject[] args) { - modify(); - IRubyObject randgen = context.runtime.getRandomClass(); - if (args.length > 0) { - IRubyObject hash = TypeConverter.checkHashType(context.runtime, args[args.length - 1]); - if (!hash.isNil()) { - IRubyObject ret = ArgsUtil.extractKeywordArg(context, (RubyHash) hash, "random"); - if (ret != null) randgen = ret; - } + @JRubyMethod(name = "shuffle!") + public IRubyObject shuffle_bang(ThreadContext context, IRubyObject opts) { + Ruby runtime = context.runtime; + + IRubyObject hash = TypeConverter.checkHashType(runtime, opts); + + if (hash.isNil()) { + throw runtime.newArgumentError(1, 0, 0); + } + + IRubyObject ret = ArgsUtil.extractKeywordArg(context, (RubyHash) hash, "random"); + + if (ret == null) { + return shuffle(context); } + + return shuffleBang(context, ret); + } + + private IRubyObject shuffleBang(ThreadContext context, IRubyObject randgen) { + Ruby runtime = context.runtime; + + modify(); + int i = realLength; int len = i; try { while (i > 0) { int r = (int) RubyRandom.randomLongLimited(context, randgen, i - 1); if (len != realLength) { // || ptr != RARRAY_CONST_PTR(ary) - throw context.runtime.newRuntimeError("modified during shuffle"); + throw runtime.newRuntimeError("modified during shuffle"); } T tmp = eltOk(--i); eltSetOk(i, eltOk(r)); eltSetOk(r, tmp); } } catch (ArrayIndexOutOfBoundsException ex) { - throw concurrentModification(context.runtime, ex); + throw concurrentModification(runtime, ex); } return this; } + + @JRubyMethod(name = "shuffle") public IRubyObject shuffle(ThreadContext context) { - return shuffle(context, IRubyObject.NULL_ARRAY); + RubyArray ary = aryDup(); + ary.shuffle_bang(context); + return ary; } - @JRubyMethod(name = "shuffle", optional = 1) - public IRubyObject shuffle(ThreadContext context, IRubyObject[] args) { + @JRubyMethod(name = "shuffle") + public IRubyObject shuffle(ThreadContext context, IRubyObject opts) { RubyArray ary = aryDup(); - ary.shuffle_bang(context, args); + ary.shuffle_bang(context, opts); return ary; } private static final int SORTED_THRESHOLD = 10; - @JRubyMethod(name = "sample", optional = 2) - public IRubyObject sample(ThreadContext context, IRubyObject[] args) { - unpack(); - try { - IRubyObject randgen = context.runtime.getRandomClass(); - - if (args.length > 0) { - IRubyObject hash = TypeConverter.checkHashType(context.runtime, args[args.length - 1]); - if (!hash.isNil()) { - IRubyObject ret = ArgsUtil.extractKeywordArg(context, (RubyHash) hash, "random"); - if (ret != null) randgen = ret; - args = ArraySupport.newCopy(args, args.length - 1); - } - } + @JRubyMethod(name = "sample") + public IRubyObject sample(ThreadContext context) { + return sampleCommon(context, context.runtime.getRandomClass()); + } - if (args.length == 0) { - if (realLength == 0) return context.nil; - return eltOk(realLength == 1 ? 0 : RubyRandom.randomLongLimited(context, randgen, realLength - 1)); - } + @JRubyMethod(name = "sample") + public IRubyObject sample(ThreadContext context, IRubyObject sampleOrOpts) { + final Ruby runtime = context.runtime; + + IRubyObject hash = TypeConverter.checkHashType(runtime, sampleOrOpts); + + if (hash.isNil()) { + return sampleCommon(context, sampleOrOpts, runtime.getRandomClass()); + } + + IRubyObject ret = ArgsUtil.extractKeywordArg(context, (RubyHash) hash, "random"); + + return sampleCommon(context, ret != null ? ret : runtime.getRandomClass()); + } + + @JRubyMethod(name = "sample") + public IRubyObject sample(ThreadContext context, IRubyObject sample, IRubyObject opts) { + final Ruby runtime = context.runtime; + + IRubyObject hash = TypeConverter.checkHashType(runtime, opts); + + if (hash.isNil()) { + throw runtime.newArgumentError(2, 0, 1); + } + + IRubyObject ret = ArgsUtil.extractKeywordArg(context, (RubyHash) hash, "random"); + + return sampleCommon(context, sample, ret != null ? ret : runtime.getRandomClass()); + } + + /** + * Common sample logic when no sample size was specified. + */ + private IRubyObject sampleCommon(ThreadContext context, IRubyObject randgen) { + if (realLength == 0) return context.nil; + + return eltOk(realLength == 1 ? 0 : RubyRandom.randomLongLimited(context, randgen, realLength - 1)); + } + + /** + * Common sample logic when a sample size was specified. + */ + private IRubyObject sampleCommon(ThreadContext context, IRubyObject sample, IRubyObject randgen) { + Ruby runtime = context.runtime; - final Ruby runtime = context.runtime; - int n = RubyNumeric.num2int(args[0]); + int n = RubyNumeric.num2int(sample); + try { if (n < 0) throw runtime.newArgumentError("negative sample number"); if (n > realLength) n = realLength; @@ -5703,4 +5755,42 @@ public RubyArray to_a() { } return this; } + + @Deprecated + public IRubyObject shuffle(ThreadContext context, IRubyObject[] args) { + switch (args.length) { + case 0: + return shuffle(context); + case 1: + return shuffle(context, args[0]); + default: + throw context.runtime.newArgumentError(args.length, 0, 0); + } + } + + @Deprecated + public IRubyObject shuffle_bang(ThreadContext context, IRubyObject[] args) { + switch (args.length) { + case 0: + return shuffle_bang(context, context.nil); + case 1: + return shuffle_bang(context, args[0]); + default: + throw context.runtime.newArgumentError(args.length, 0, 0); + } + } + + @Deprecated + public IRubyObject sample(ThreadContext context, IRubyObject[] args) { + switch (args.length) { + case 0: + return sample(context); + case 1: + return sample(context, args[0]); + case 2: + return sample(context, args[0], args[1]); + default: + throw context.runtime.newArgumentError(args.length, 0, 1); + } + } } diff --git a/core/src/main/java/org/jruby/RubyDir.java b/core/src/main/java/org/jruby/RubyDir.java index 4eb13858943..4bc78fe9a59 100644 --- a/core/src/main/java/org/jruby/RubyDir.java +++ b/core/src/main/java/org/jruby/RubyDir.java @@ -43,6 +43,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.regex.Pattern; import jnr.posix.FileStat; @@ -1123,6 +1124,17 @@ public static RubyString getHomeDirectoryPath(ThreadContext context) { return getHomeDirectoryPath(context, context.runtime.getENV().op_aref(context, homeKey)); } + public static Optional getHomeFromEnv(Ruby runtime) { + final RubyString homeKey = RubyString.newStringShared(runtime, HOME); + final RubyHash env = runtime.getENV(); + + if (env.has_key_p(homeKey).isFalse()) { + return Optional.empty(); + } else { + return Optional.of(env.op_aref(runtime.getCurrentContext(), homeKey).toString()); + } + } + private static final ByteList user_home = new ByteList(new byte[] {'u','s','e','r','.','h','o','m','e'}, false); static RubyString getHomeDirectoryPath(ThreadContext context, IRubyObject home) { diff --git a/core/src/main/java/org/jruby/RubyFileStat.java b/core/src/main/java/org/jruby/RubyFileStat.java index 62f266b5b07..d9ba6d654ad 100644 --- a/core/src/main/java/org/jruby/RubyFileStat.java +++ b/core/src/main/java/org/jruby/RubyFileStat.java @@ -298,6 +298,7 @@ public RubyString ftype() { @JRubyMethod(name = "gid") public IRubyObject gid() { checkInitialized(); + if (Platform.IS_WINDOWS) return RubyFixnum.zero(getRuntime()); return getRuntime().newFixnum(stat.gid()); } @@ -371,6 +372,7 @@ public IRubyObject inspect() { @JRubyMethod(name = "uid") public IRubyObject uid() { checkInitialized(); + if (Platform.IS_WINDOWS) return RubyFixnum.zero(getRuntime()); return getRuntime().newFixnum(stat.uid()); } diff --git a/core/src/main/java/org/jruby/RubyHash.java b/core/src/main/java/org/jruby/RubyHash.java index 40f7170f1b0..c85cb55c58d 100644 --- a/core/src/main/java/org/jruby/RubyHash.java +++ b/core/src/main/java/org/jruby/RubyHash.java @@ -1513,7 +1513,11 @@ public RubyHash each_pairCommon(final ThreadContext context, final Block block) private static final VisitorWithState YieldKeyValueArrayVisitor = new VisitorWithState() { @Override public void visit(ThreadContext context, RubyHash self, IRubyObject key, IRubyObject value, int index, Block block) { - block.yield(context, context.runtime.newArray(key, value)); + if (block.getSignature().arityValue() > 1) { + block.yieldSpecific(context, key, value); + } else { + block.yield(context, context.runtime.newArray(key, value)); + } } }; diff --git a/core/src/main/java/org/jruby/RubyInstanceConfig.java b/core/src/main/java/org/jruby/RubyInstanceConfig.java index 96410275b8e..3c4825aa0ec 100644 --- a/core/src/main/java/org/jruby/RubyInstanceConfig.java +++ b/core/src/main/java/org/jruby/RubyInstanceConfig.java @@ -1752,10 +1752,10 @@ public boolean shouldPrecompileAll() { public static final boolean ERRNO_BACKTRACE = Options.ERRNO_BACKTRACE.load(); public static final boolean STOPITERATION_BACKTRACE = Options.STOPITERATION_BACKTRACE.load(); - public static final boolean IR_DEBUG = Options.IR_DEBUG.load(); + public static boolean IR_DEBUG = Options.IR_DEBUG.load(); // ast tool can toggle this public static final String IR_DEBUG_IGV = Options.IR_DEBUG_IGV.load(); public static final boolean IR_PROFILE = Options.IR_PROFILE.load(); - public static final boolean IR_COMPILER_DEBUG = Options.IR_COMPILER_DEBUG.load(); + public static boolean IR_COMPILER_DEBUG = Options.IR_COMPILER_DEBUG.load(); // ast tool can toggle this public static final boolean IR_WRITING = Options.IR_WRITING.load(); public static final boolean IR_READING = Options.IR_READING.load(); public static final boolean IR_READING_DEBUG = Options.IR_READING_DEBUG.load(); diff --git a/core/src/main/java/org/jruby/RubyKernel.java b/core/src/main/java/org/jruby/RubyKernel.java index b220ac6967d..03220682641 100644 --- a/core/src/main/java/org/jruby/RubyKernel.java +++ b/core/src/main/java/org/jruby/RubyKernel.java @@ -80,7 +80,6 @@ import org.jruby.util.ArraySupport; import org.jruby.util.ByteList; import org.jruby.util.ConvertBytes; -import org.jruby.util.IdUtil; import org.jruby.util.ShellLauncher; import org.jruby.util.StringSupport; import org.jruby.util.TypeConverter; @@ -170,61 +169,28 @@ public static IRubyObject at_exit(ThreadContext context, IRubyObject recv, Block return context.runtime.pushExitBlock(context.runtime.newProc(Block.Type.PROC, block)); } - @JRubyMethod(name = "autoload?", required = 1, module = true, visibility = PRIVATE) + @JRubyMethod(name = "autoload?", required = 1, module = true, visibility = PRIVATE, reads = {CLASS, SCOPE}) public static IRubyObject autoload_p(ThreadContext context, final IRubyObject recv, IRubyObject symbol) { - final Ruby runtime = context.runtime; - final RubyModule module = getModuleForAutoload(runtime, recv); - final RubyString file = module.getAutoloadFile(symbol.asJavaString()); - return file == null ? context.nil : file; - } + RubyModule module = context.getFrameKlazz(); - @JRubyMethod(required = 2, module = true, visibility = PRIVATE) - public static IRubyObject autoload(ThreadContext context, final IRubyObject recv, IRubyObject symbol, IRubyObject file) { - final Ruby runtime = context.runtime; - final String nonInternedName = symbol.asJavaString(); + if (module == null) module = context.getCurrentStaticScope().getModule(); - if (!IdUtil.isValidConstantName(nonInternedName)) { - throw runtime.newNameError("autoload must be constant name", symbol); + if (module.isNil()) { + return context.nil; } - final RubyString fileString = - StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, file)); - - if (fileString.isEmpty()) throw runtime.newArgumentError("empty file name"); - - final String baseName = nonInternedName.intern(); // interned, OK for "fast" methods - final RubyModule module = getModuleForAutoload(runtime, recv); - - IRubyObject existingValue = module.fetchConstant(baseName); - if (existingValue != null && existingValue != RubyObject.UNDEF) return context.nil; - - module.defineAutoload(baseName, new RubyModule.AutoloadMethod() { + return module.autoload_p(context, symbol); + } - public RubyString getFile() { return fileString; } + @JRubyMethod(required = 2, module = true, visibility = PRIVATE, reads = {CLASS, SCOPE}) + public static IRubyObject autoload(ThreadContext context, final IRubyObject recv, IRubyObject symbol, IRubyObject file) { + RubyModule module = context.getFrameKlazz(); - public void load(final Ruby runtime) { - final String file = getFile().asJavaString(); - if (runtime.getLoadService().autoloadRequire(file)) { - // Do not finish autoloading by cyclic autoload - module.finishAutoload(baseName); - } - } - }); - return context.nil; - } + if (module == null) module = context.getCurrentStaticScope().getModule(); - @Deprecated - public static IRubyObject autoload(final IRubyObject recv, IRubyObject symbol, IRubyObject file) { - return autoload(recv.getRuntime().getCurrentContext(), recv, symbol, file); - } + if (module.isNil()) throw context.runtime.newTypeError("Can not set autoload on singleton class"); - static RubyModule getModuleForAutoload(Ruby runtime, IRubyObject recv) { - RubyModule module = recv instanceof RubyModule ? (RubyModule) recv : recv.getMetaClass().getRealClass(); - if (module == runtime.getKernel()) { - // special behavior if calling Kernel.autoload directly - module = runtime.getObject().getSingletonClass(); - } - return module; + return module.autoload(context, symbol, file); } public static IRubyObject method_missing(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) { @@ -444,7 +410,7 @@ public static IRubyObject new_float(ThreadContext context, IRubyObject object, b if (object instanceof RubyFloat) { return object; } - if (object instanceof RubyString){ + if (object instanceof RubyString) { RubyString str = (RubyString) object; ByteList bytes = str.getByteList(); if (bytes.getRealSize() == 0){ // rb_cstr_to_dbl case @@ -2488,4 +2454,9 @@ public static IRubyObject new_integer19(ThreadContext context, IRubyObject recv, public static RubyFloat new_float19(IRubyObject recv, IRubyObject object) { return new_float(recv, object); } + + @Deprecated + public static IRubyObject autoload(final IRubyObject recv, IRubyObject symbol, IRubyObject file) { + return autoload(recv.getRuntime().getCurrentContext(), recv, symbol, file); + } } diff --git a/core/src/main/java/org/jruby/RubyModule.java b/core/src/main/java/org/jruby/RubyModule.java index 5c00cbfe53b..40218531ac0 100644 --- a/core/src/main/java/org/jruby/RubyModule.java +++ b/core/src/main/java/org/jruby/RubyModule.java @@ -70,7 +70,9 @@ import org.jruby.anno.TypePopulator; import org.jruby.common.IRubyWarnings.ID; import org.jruby.embed.Extension; +import org.jruby.exceptions.LoadError; import org.jruby.exceptions.RaiseException; +import org.jruby.exceptions.RuntimeError; import org.jruby.internal.runtime.methods.AliasMethod; import org.jruby.internal.runtime.methods.AttrReaderMethod; import org.jruby.internal.runtime.methods.AttrWriterMethod; @@ -90,6 +92,7 @@ import org.jruby.javasupport.JavaClass; import org.jruby.javasupport.binding.MethodGatherer; import org.jruby.parser.StaticScope; +import org.jruby.runtime.Arity; import org.jruby.runtime.Block; import org.jruby.runtime.CallType; import org.jruby.runtime.ClassIndex; @@ -104,15 +107,17 @@ import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.builtin.Variable; import org.jruby.runtime.callsite.CacheEntry; +import org.jruby.runtime.load.LoadService; import org.jruby.runtime.marshal.MarshalStream; import org.jruby.runtime.marshal.UnmarshalStream; import org.jruby.runtime.opto.Invalidator; import org.jruby.runtime.opto.OptoFactory; import org.jruby.runtime.profile.MethodEnhancer; -import org.jruby.util.ByteListHelper; +import org.jruby.util.ByteList; import org.jruby.util.ClassProvider; import org.jruby.util.CommonByteLists; import org.jruby.util.IdUtil; +import org.jruby.util.StringSupport; import org.jruby.util.TypeConverter; import org.jruby.util.cli.Options; import org.jruby.util.collections.WeakHashSet; @@ -205,40 +210,58 @@ void setClassIndex(ClassIndex classIndex) { this.index = classIndex.ordinal(); } - public static class ModuleKernelMethods { - @JRubyMethod - public static IRubyObject autoload(ThreadContext context, IRubyObject self, IRubyObject symbol, IRubyObject file) { - return RubyKernel.autoload(context, self, symbol, file); + @JRubyMethod + public IRubyObject autoload(ThreadContext context, IRubyObject symbol, IRubyObject file) { + final Ruby runtime = context.runtime; + + final RubyString fileString = + StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, file)); + + if (fileString.isEmpty()) throw runtime.newArgumentError("empty file name"); + + final String symbolStr = symbol.asJavaString(); + + if (!IdUtil.isValidConstantName(symbolStr)) { + throw runtime.newNameError("autoload must be constant name", symbolStr); } - @JRubyMethod(name = "autoload?") - public static IRubyObject autoload_p(ThreadContext context, IRubyObject self, IRubyObject symbol) { - final Ruby runtime = context.runtime; - final String name = TypeConverter.checkID(symbol).idString(); + IRubyObject existingValue = fetchConstant(symbolStr); - RubyModule mod = RubyKernel.getModuleForAutoload(runtime, self); - for (/* RubyModule mod = (RubyModule) self */; mod != null; mod = mod.getSuperClass()) { - final IRubyObject loadedValue = mod.fetchConstant(name); - if ( loadedValue != null && loadedValue != UNDEF ) return context.nil; + if (existingValue != null && existingValue != RubyObject.UNDEF) return context.nil; + defineAutoload(symbolStr, fileString); + + return context.nil; + } + + @JRubyMethod(name = "autoload?") + public IRubyObject autoload_p(ThreadContext context, IRubyObject symbol) { + final String name = TypeConverter.checkID(symbol).idString(); + + for (RubyModule mod = this; mod != null; mod = mod.getSuperClass()) { + final IRubyObject loadedValue = mod.fetchConstant(name); + + if (loadedValue == UNDEF) { final RubyString file; - if ( mod.isIncluded() ) { - file = mod.getNonIncludedClass().getAutoloadFile(name); - } - else { - file = mod.getAutoloadFile(name); - } - if ( file != null ) { // due explicit requires still need to : - if ( runtime.getLoadService().featureAlreadyLoaded(file.asJavaString()) ) { - // TODO in which case the auto-load never finish-es ?! - return context.nil; - } - return file; - } + Autoload autoload = mod.getAutoloadMap().get(name); + + // autoload has been evacuated + if (autoload == null) return context.nil; + + // autoload has been completed + if (autoload.getValue() != null) return context.nil; + + file = autoload.getFile(); + + // autoload is in progress on another thread + if (autoload.ctx != null && !autoload.isSelf(context)) return file; + + // file load is in progress or file is already loaded + if (!getRuntime().getLoadService().featureAlreadyLoaded(file.asJavaString())) return file; } - return context.nil; } + return context.nil; } @Override @@ -308,11 +331,11 @@ public Map getConstantMapForWrite() { * For looking up constant, check constantMap first then try to get an Autoload object from autoloadMap. * For setting constant, update constantMap first and remove an Autoload object from autoloadMap. */ - private Map getAutoloadMap() { + protected Map getAutoloadMap() { return autoloads; } - private Map getAutoloadMapForWrite() { + protected Map getAutoloadMapForWrite() { Map autoloads = this.autoloads; if (autoloads == Collections.EMPTY_MAP) { synchronized (this) { @@ -2475,6 +2498,10 @@ public void syncConstants(RubyModule other) { if (other.getConstantMap() != Collections.EMPTY_MAP) { getConstantMapForWrite().putAll(other.getConstantMap()); } + Map autoloadMap = other.getAutoloadMap(); + if (!autoloadMap.isEmpty()) { + this.autoloads = autoloadMap; + } } public void syncClassVariables(RubyModule other) { @@ -2769,7 +2796,7 @@ public IRubyObject attr(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; if (args.length == 2 && (args[1] == runtime.getTrue() || args[1] == runtime.getFalse())) { - runtime.getWarnings().warn(ID.OBSOLETE_ARGUMENT, "optional boolean argument is obsoleted"); + runtime.getWarnings().warning(ID.OBSOLETE_ARGUMENT, "optional boolean argument is obsoleted"); addAccessor(context, TypeConverter.checkID(args[0]), context.getCurrentVisibility(), args[0].isTrue(), args[1].isTrue()); return runtime.getNil(); } @@ -3665,51 +3692,95 @@ private Collection classVariablesCommon(boolean inherit) { ////////////////// CONSTANT RUBY METHODS //////////////// // - /** rb_mod_const_defined - * + /** + * rb_mod_const_defined */ - public RubyBoolean const_defined_p(ThreadContext context, IRubyObject symbol) { - return const_defined_p19(context, new IRubyObject[]{symbol}); + @JRubyMethod(name = "const_defined?") + public RubyBoolean const_defined_p(ThreadContext context, IRubyObject name) { + + return constDefined(context.runtime, name, true) ? context.tru : context.fals; } - private RubyBoolean constantDefined(Ruby runtime, RubySymbol symbol, boolean inherit) { - if (symbol.validConstantName()) { - return runtime.newBoolean(getConstantSkipAutoload(symbol.idString(), inherit, inherit) != null); + @JRubyMethod(name = "const_defined?") + public RubyBoolean const_defined_p(ThreadContext context, IRubyObject name, IRubyObject recurse) { + return constDefined(context.runtime, name, recurse.isTrue()) ? context.tru : context.fals; + } + + private boolean constDefined(Ruby runtime, IRubyObject name, boolean inherit) { + if (name instanceof RubySymbol) { + RubySymbol sym = (RubySymbol) name; + + if (!sym.validConstantName()) { + throw runtime.newNameError(str(runtime, "wrong constant name", ids(runtime, sym)), sym); + } + + String id = sym.idString(); + + return inherit ? constDefined(id) : constDefinedAt(id); } - throw runtime.newNameError(str(runtime, "wrong constant name", ids(runtime, symbol)), symbol); - } + RubyString fullName = name.convertToString(); + ByteList value = fullName.getByteList(); - @JRubyMethod(name = "const_defined?", required = 1, optional = 1) - public RubyBoolean const_defined_p19(ThreadContext context, IRubyObject[] args) { - Ruby runtime = context.runtime; - boolean inherit = args.length == 1 || (!args[1].isNil() && args[1].isTrue()); + ByteList pattern = CommonByteLists.COLON_COLON; - if (args[0] instanceof RubySymbol) return constantDefined(runtime, ((RubySymbol) args[0]), inherit); + Encoding enc = pattern.getEncoding(); + byte[] bytes = value.getUnsafeBytes(); + int begin = value.getBegin(); + int realSize = value.getRealSize(); + int end = begin + realSize; + int currentOffset = 0; + int patternIndex; + int index = 0; + RubyModule mod = this; - RubyString fullName = args[0].convertToString(); + if (value.startsWith(pattern)) { + mod = runtime.getObject(); + currentOffset += 2; + } - IRubyObject value = ByteListHelper.split(fullName.getByteList(), CommonByteLists.COLON_COLON, (index, segment, module) -> { - if (index == 0) { - if (segment.realSize() == 0) return runtime.getObject(); // '::Foo...' - module = this; + for (; currentOffset < realSize && (patternIndex = value.indexOf(pattern, currentOffset)) >= 0; index++) { + int t = enc.rightAdjustCharHead(bytes, currentOffset + begin, patternIndex + begin, end) - begin; + if (t != patternIndex) { + currentOffset = t; + continue; } + ByteList segment = value.makeShared(currentOffset, patternIndex - currentOffset); String id = RubySymbol.newConstantSymbol(runtime, fullName, segment).idString(); - IRubyObject obj = ((RubyModule) module).getConstantNoConstMissing(id, inherit, inherit); - if (obj == null) return null; + IRubyObject obj; + + if (!inherit) { + if (!mod.constDefinedAt(id)) { + return false; + } + obj = mod.getConstantAt(id); + } else if (index == 0 && segment.realSize() == 0) { + if (!mod.constDefined(id)) { + return false; + } + obj = mod.getConstant(id); + } else { + if (!mod.constDefinedFrom(id)) { + return false; + } + obj = mod.getConstantFrom(id); + } + if (!(obj instanceof RubyModule)) throw runtime.newTypeError(segment + " does not refer to class/module"); - return obj; - }, (index, segment, module) -> { - if (module == null) module = this; // Bare 'Foo' + mod = (RubyModule) obj; + currentOffset = patternIndex + pattern.getRealSize(); + } - String id = RubySymbol.newConstantSymbol(runtime, fullName, segment).idString(); - return ((RubyModule) module).getConstantSkipAutoload(id, inherit, inherit); - }); + if (mod == null) mod = this; // Bare 'Foo' - return runtime.newBoolean(value != null); + ByteList lastSegment = value.makeShared(currentOffset, realSize - currentOffset); + + String id = RubySymbol.newConstantSymbol(runtime, fullName, lastSegment).idString(); + + return mod.getConstantSkipAutoload(id, inherit, inherit) != null; } public IRubyObject const_get(IRubyObject symbol) { @@ -4219,7 +4290,7 @@ public IRubyObject getConstantNoConstMissingSKipAutoload(String name) { return getConstantSkipAutoload(name, true, true); } - // returns UNDEF for un-loaded autoload constants + // returns null for autoloads that have failed private IRubyObject getConstantSkipAutoload(String name, boolean inherit, boolean includeObject) { IRubyObject constant = iterateConstantNoConstMissing(name, this, inherit, false); @@ -4233,9 +4304,14 @@ private IRubyObject getConstantSkipAutoload(String name, boolean inherit, boolea private static IRubyObject iterateConstantNoConstMissing(String name, RubyModule init, boolean inherit, boolean loadConstant) { for (RubyModule mod = init; mod != null; mod = mod.getSuperClass()) { - final IRubyObject value = mod.fetchConstant(name, true); + IRubyObject value = + loadConstant ? + mod.getConstantWithAutoload(name, null, true) : + mod.fetchConstant(name, true); + + // if it's UNDEF and we're not loading and there's no autoload set up, consider it undefined + if ( value == UNDEF && !loadConstant && mod.getAutoloadMap().get(name) == null) return null; - if ( value == UNDEF ) return mod.getAutoloadConstant(name, loadConstant); if ( value != null ) return value; if ( ! inherit ) break; @@ -4250,6 +4326,36 @@ public IRubyObject getConstantFrom(String name) { return value != null ? value : getConstantFromConstMissing(name); } + /** + * Search just this class for a constant value, or trigger autoloading. + * + * @param name + * @return + */ + public IRubyObject getConstantWithAutoload(String name, IRubyObject failedAutoloadValue, boolean includePrivate) { + RubyModule autoloadModule = null; + IRubyObject result; + + while ((result = fetchConstant(name, includePrivate)) != null) { // loop for autoload + if (result == RubyObject.UNDEF) { + if (autoloadModule == this) return failedAutoloadValue; + autoloadModule = this; + + final RubyModule.Autoload autoload = getAutoloadMap().get(name); + + if (autoload == null) return null; + if (autoload.getValue() != null) return autoload.getValue(); + + autoload.load(getRuntime().getCurrentContext()); + continue; + } + + return result; + } + + return autoloadModule != null ? failedAutoloadValue : null; + } + @Deprecated public IRubyObject fastGetConstantFrom(String internedName) { return getConstantFrom(internedName); @@ -4263,20 +4369,22 @@ public IRubyObject getConstantFromNoConstMissing(String name, boolean includePri final Ruby runtime = getRuntime(); final RubyClass objectClass = runtime.getObject(); - RubyModule mod = this; IRubyObject value; + RubyModule mod = this; - while ( mod != null ) { - if ( ( value = mod.fetchConstant(name, includePrivate) ) != null ) { - if ( value == UNDEF ) return mod.resolveUndefConstant(name); + while (mod != null) { + IRubyObject result = mod.getConstantWithAutoload(name, null, includePrivate); + if (result != null) { if ( mod == objectClass && this != objectClass ) { return null; } - return value; + return result; } + mod = mod.getSuperClass(); } + return null; } @@ -4345,7 +4453,11 @@ private IRubyObject setConstantCommon(String name, IRubyObject value, boolean hi boolean notAutoload = oldValue != UNDEF; if (notAutoload || !setAutoloadConstant(name, value)) { if (warn && notAutoload) { - getRuntime().getWarnings().warn(ID.CONSTANT_ALREADY_INITIALIZED, "already initialized constant " + name); + if (this.equals(getRuntime().getObject())) { + getRuntime().getWarnings().warn(ID.CONSTANT_ALREADY_INITIALIZED, "already initialized constant " + name); + } else { + getRuntime().getWarnings().warn(ID.CONSTANT_ALREADY_INITIALIZED, "already initialized constant " + this + "::" + name); + } } // might just call storeConstant(name, value, hidden) but to maintain // backwards compatibility with calling #storeConstant overrides @@ -4392,70 +4504,132 @@ public void defineConstant(String name, IRubyObject value) { setConstant(name, value); } + public boolean isConstantDefined(String name, boolean inherit) { + return constDefinedInner(name, false, inherit, false); + } + + // rb_const_defined + public boolean constDefined(String name) { + return constDefinedInner(name, false, true, false); + } + + // rb_const_defined_at + public boolean constDefinedAt(String name) { + return constDefinedInner(name, true, false, false); + } + + // rb_const_defined_from + public boolean constDefinedFrom(String name) { + return constDefinedInner(name, true, true, false); + } + + // rb_public_const_defined_from + public boolean publicConstDefinedFrom(String name) { + return constDefinedInner(name, true, true, true); + } + // Fix for JRUBY-1339 - search hierarchy for constant - /** rb_const_defined_at - * + /** + * rb_const_defined_0 */ - public boolean isConstantDefined(String name) { - assert IdUtil.isConstant(name); - boolean isObject = this == getRuntime().getObject(); + private boolean constDefinedInner(String name, boolean exclude, boolean recurse, boolean visibility) { + Ruby runtime = getRuntime(); + + RubyClass object = runtime.getObject(); + boolean moduleRetry = false; RubyModule module = this; - do { - Object value; - if ((value = module.constantTableFetch(name)) != null) { - if (value != UNDEF) return true; - return getAutoloadMap().get(name) != null; - } + retry: while (true) { + while (module != null) { + ConstantEntry entry; + if ((entry = module.constantEntryFetch(name)) != null) { + if (visibility && entry.hidden) { + return false; + } - } while (isObject && (module = module.getSuperClass()) != null ); + IRubyObject value = entry.value; - return false; - } + // autoload is not in progress and should not appear defined + if (value == UNDEF && module.checkAutoloadRequired(runtime, name, null) == null && + !module.autoloadingValue(runtime, name)) { + return false; + } - @Deprecated - public boolean fastIsConstantDefined(String internedName) { - assert internedName.equals(internedName.intern()) : internedName + " is not interned"; - assert IdUtil.isConstant(internedName); - boolean isObject = this == getRuntime().getObject(); + if (exclude && module == object && this != object) { + return false; + } - RubyModule module = this; + return true; + } - do { - Object value; - if ((value = module.constantTableFetch(internedName)) != null) { - if (value != UNDEF) return true; - return getAutoloadMap().get(internedName) != null; + if (!recurse) break; + + module = module.getSuperClass(); } - } while (isObject && (module = module.getSuperClass()) != null ); + if (!exclude && !moduleRetry && this.isModule()) { + moduleRetry = true; + module = object; + continue retry; + } - return false; + return false; + } } - @Deprecated - public boolean fastIsConstantDefined19(String internedName) { - return fastIsConstantDefined19(internedName, true); - } + // MRI: rb_autoloading_value + public boolean autoloadingValue(Ruby runtime, String name) { + final Autoload autoload = getAutoloadMap().get(name); - @Deprecated - public boolean fastIsConstantDefined19(String internedName, boolean inherit) { - assert internedName.equals(internedName.intern()) : internedName + " is not interned"; - assert IdUtil.isConstant(internedName); + // autoload has been evacuated + if (autoload == null) return false; - for (RubyModule module = this; module != null; module = module.getSuperClass()) { - Object value; - if ((value = module.constantTableFetch(internedName)) != null) { - if (value != UNDEF) return true; - return getAutoloadMap().get(internedName) != null; - } - if (!inherit) { - break; + // autoload is in progress on this thread and has updated the value + if (autoload.isSelf(runtime.getCurrentContext())) { + if (autoload.getValue() != null) { + return true; } } - return false; + return false; // autoload has yet to run + } + + // MRI: check_autoload_required + private RubyString checkAutoloadRequired(Ruby runtime, String name, String[] autoloadPath) { + final Autoload autoload = getAutoloadMap().get(name); + + // autoload has been evacuated + if (autoload == null) return null; + + RubyString file = autoload.getFile(); + + // autoload filename is empty + if (file.length() == 0) { + throw runtime.newArgumentError("empty file name"); + } + + // autoload is in progress on anther thread + if (autoload.ctx != null && !autoload.isSelf(runtime.getCurrentContext())) { + return file; + } + + String[] loading = {null}; + + // feature has not been loaded yet + if (!runtime.getLoadService().featureAlreadyLoaded(file.asJavaString(), loading)) return file; + + // feature is currently loading + if (autoloadPath != null && loading[0] != null) { + autoloadPath[0] = loading[0]; + return file; + } + + return null; // autoload has yet to run + } + + public boolean isConstantDefined(String name) { + return constDefinedInner(name, false, true, false); } // @@ -4875,11 +5049,11 @@ protected IRubyObject constantTableRemove(String name) { /** * Define an autoload. ConstantMap holds UNDEF for the name as an autoload marker. */ - protected final void defineAutoload(String name, AutoloadMethod loadMethod) { - final Autoload existingAutoload = getAutoloadMap().get(name); + protected final void defineAutoload(String symbol, RubyString path) { + final Autoload existingAutoload = getAutoloadMap().get(symbol); if (existingAutoload == null || existingAutoload.getValue() == null) { - storeConstant(name, RubyObject.UNDEF); - getAutoloadMapForWrite().put(name, new Autoload(loadMethod)); + storeConstant(symbol, RubyObject.UNDEF); + getAutoloadMapForWrite().put(symbol, new Autoload(symbol, path)); } } @@ -4890,11 +5064,14 @@ protected final IRubyObject finishAutoload(String name) { final Autoload autoload = getAutoloadMap().get(name); if ( autoload == null ) return null; final IRubyObject value = autoload.getValue(); - if ( value != null ) { + + if (value != null && value != UNDEF) { storeConstant(name, value); + invalidateConstantCache(name); } + removeAutoload(name); - invalidateConstantCache(name); + return value; } @@ -4911,7 +5088,7 @@ protected IRubyObject getAutoloadConstant(String name, boolean loadConstant) { final Autoload autoload = getAutoloadMap().get(name); if ( autoload == null ) return null; if ( ! loadConstant ) return RubyObject.UNDEF; - return autoload.getConstant( getRuntime().getCurrentContext() ); + return autoload.load( getRuntime().getCurrentContext() ); } /** @@ -5058,6 +5235,7 @@ public ConstantEntry dup() { } } + @Deprecated public interface AutoloadMethod { void load(Ruby runtime); RubyString getFile(); @@ -5069,58 +5247,76 @@ public interface AutoloadMethod { * 'Module#autoload' creates this object and stores it in autoloadMap. * This object can be shared with multiple threads so take care to change volatile and synchronized definitions. */ - private static final class Autoload { + public final class Autoload { // A ThreadContext which is executing autoload. private volatile ThreadContext ctx; - // The lock for test-and-set the ctx. - private final Object ctxLock = new Object(); // An object defined for the constant while autoloading. private volatile IRubyObject value; - // A method which actually requires a defined feature. - private final AutoloadMethod loadMethod; + // The symbol ID for the autoload constant + private final String symbol; + // The Ruby string representing the path to load + private final RubyString path; - Autoload(AutoloadMethod loadMethod) { + Autoload(String symbol, RubyString path) { this.ctx = null; this.value = null; - this.loadMethod = loadMethod; + this.symbol = symbol; + this.path = path; } // Returns an object for the constant if the caller is the autoloading thread. // Otherwise, try to start autoloading and returns the defined object by autoload. - IRubyObject getConstant(ThreadContext ctx) { - synchronized (ctxLock) { - if (this.ctx == null) { - this.ctx = ctx; - } else if (isSelf(ctx)) { - return getValue(); - } + synchronized IRubyObject load(ThreadContext ctx) { + if (this.ctx == null) { + this.ctx = ctx; + } else if (isSelf(ctx)) { + return getValue(); + } + + try { // This method needs to be synchronized for removing Autoload // from autoloadMap when it's loaded. - loadMethod.load(ctx.runtime); + load(ctx.runtime); + } catch (LoadError | RuntimeError lre) { + // reset ctx to null for a future attempt to load + this.ctx = null; + throw lre; } + return getValue(); } // Update an object for the constant if the caller is the autoloading thread. - boolean setConstant(ThreadContext ctx, IRubyObject newValue) { - synchronized(ctxLock) { - boolean isSelf = isSelf(ctx); + synchronized boolean setConstant(ThreadContext ctx, IRubyObject newValue) { + boolean isSelf = isSelf(ctx); - if (isSelf) value = newValue; + if (isSelf) value = newValue; - return isSelf; - } + return isSelf; } // Returns an object for the constant defined by autoload. - IRubyObject getValue() { + synchronized IRubyObject getValue() { return value; } + private void load(Ruby runtime) { + LoadService loadService = runtime.getLoadService(); + if (!loadService.featureAlreadyLoaded(path.asJavaString())) { + if (loadService.autoloadRequire(path)) { + // Do not finish autoloading by cyclic autoload + finishAutoload(symbol); + } + } + } + // Returns the assigned feature. - RubyString getFile() { return loadMethod.getFile(); } + RubyString getFile() { + return path; + } private boolean isSelf(ThreadContext rhs) { + ThreadContext ctx = this.ctx; return ctx != null && ctx.getThread() == rhs.getThread(); } } @@ -5254,6 +5450,47 @@ public void setRefinements(Map refinements) { "local_variables" )); + @Deprecated + public boolean fastIsConstantDefined(String internedName){ + return isConstantDefined(internedName); + } + + @Deprecated + public boolean fastIsConstantDefined19(String internedName) { + return isConstantDefined(internedName, true); + } + + @Deprecated + public boolean fastIsConstantDefined19(String internedName, boolean inherit) { + return isConstantDefined(internedName, inherit); + } + + @Deprecated + public RubyBoolean const_defined_p19(ThreadContext context, IRubyObject[] args) { + switch (args.length) { + case 1: + return const_defined_p(context, args[0]); + case 2: + return const_defined_p(context, args[0], args[1]); + } + + Arity.checkArgumentCount(context, args, 1, 2); + return null; // not reached + } + + @Deprecated + public static class ModuleKernelMethods { + @Deprecated + public static IRubyObject autoload(ThreadContext context, IRubyObject self, IRubyObject symbol, IRubyObject file) { + return ((RubyModule) self).autoload(context, symbol, file); + } + + @Deprecated + public static IRubyObject autoload_p(ThreadContext context, IRubyObject self, IRubyObject symbol) { + return ((RubyModule) self).autoload_p(context, symbol); + } + } + protected ClassIndex classIndex = ClassIndex.NO_INDEX; private volatile Map classVariables = Collections.EMPTY_MAP; diff --git a/core/src/main/java/org/jruby/RubyNumeric.java b/core/src/main/java/org/jruby/RubyNumeric.java index 0cd419e1b79..1f103bf3a55 100644 --- a/core/src/main/java/org/jruby/RubyNumeric.java +++ b/core/src/main/java/org/jruby/RubyNumeric.java @@ -464,8 +464,7 @@ public static IRubyObject str2fnum(Ruby runtime, RubyString arg, boolean strict, try { double value = ConvertDouble.byteListToDouble19(arg.getByteList(), strict); return RubyFloat.newFloat(runtime, value); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { if (strict) { if (!exception) return runtime.getNil(); throw runtime.newArgumentError("invalid value for Float(): " diff --git a/core/src/main/java/org/jruby/RubyProcess.java b/core/src/main/java/org/jruby/RubyProcess.java index 64685e0a0a8..36cb499f994 100644 --- a/core/src/main/java/org/jruby/RubyProcess.java +++ b/core/src/main/java/org/jruby/RubyProcess.java @@ -105,10 +105,17 @@ public static RubyModule createProcessModule(Ruby runtime) { process_sys.defineAnnotatedMethods(Sys.class); runtime.loadConstantSet(process, jnr.constants.platform.PRIO.class); - runtime.loadConstantSet(process, jnr.constants.platform.RLIM.class); - for (RLIMIT r : RLIMIT.values()) { - if (!r.defined()) continue; - process.defineConstant(r.name(), runtime.newFixnum(r.intValue())); + + if (Platform.IS_WINDOWS) { + // mark rlimit methods as not implemented and skip defining the constants (GH-6491) + process.getSingletonClass().retrieveMethod("getrlimit").setNotImplemented(true); + process.getSingletonClass().retrieveMethod("setrlimit").setNotImplemented(true); + } else { + runtime.loadConstantSet(process, jnr.constants.platform.RLIM.class); + for (RLIMIT r : RLIMIT.values()) { + if (!r.defined()) continue; + process.defineConstant(r.name(), runtime.newFixnum(r.intValue())); + } } process.defineConstant("WNOHANG", runtime.newFixnum(1)); @@ -627,6 +634,15 @@ public static IRubyObject setrlimit(ThreadContext context, IRubyObject recv, IRu public static IRubyObject setrlimit(ThreadContext context, IRubyObject recv, IRubyObject resource, IRubyObject rlimCur, IRubyObject rlimMax) { Ruby runtime = context.runtime; + if (Platform.IS_WINDOWS) { + throw runtime.newNotImplementedError("Process#setrlimit is not implemented on Windows"); + } + + if (!runtime.getPosix().isNative()) { + runtime.getWarnings().warn("Process#setrlimit not supported on this platform"); + return context.nil; + } + RLimit rlim = runtime.getPosix().getrlimit(0); if (rlimMax == context.nil) @@ -916,7 +932,7 @@ public static long waitpid(Ruby runtime, long pid, int flags) { int res = pthreadKillable(context, ctx -> posix.waitpid(pid, status, flags)); - raiseErrnoIfSet(runtime, ECHILD); + checkErrno(runtime, res, ECHILD); if (res > 0) { context.setLastExitStatus(RubyProcess.RubyStatus.newProcessStatus(runtime, status[0], res)); @@ -1023,7 +1039,7 @@ public static IRubyObject wait(Ruby runtime, IRubyObject[] args) { int pid = pthreadKillable(context, ctx -> posix.wait(status)); - raiseErrnoIfSet(runtime, ECHILD); + checkErrno(runtime, pid, ECHILD); context.setLastExitStatus(RubyProcess.RubyStatus.newProcessStatus(runtime, status[0], pid)); return runtime.newFixnum(pid); @@ -1293,7 +1309,11 @@ public static IRubyObject getrlimit(ThreadContext context, IRubyObject recv, IRu return getrlimit(context.runtime, arg); } public static IRubyObject getrlimit(Ruby runtime, IRubyObject arg) { - if (!runtime.getPosix().isNative() || Platform.IS_WINDOWS) { + if (Platform.IS_WINDOWS) { + throw runtime.newNotImplementedError("Process#getrlimit is not implemented on Windows"); + } + + if (!runtime.getPosix().isNative()) { runtime.getWarnings().warn("Process#getrlimit not supported on this platform"); RubyFixnum max = runtime.newFixnum(Long.MAX_VALUE); return runtime.newArray(max, max); @@ -1444,15 +1464,10 @@ public static IRubyObject detach(ThreadContext context, IRubyObject recv, IRubyO final int pid = (int)arg.convertToInteger().getLongValue(); Ruby runtime = context.runtime; - BlockCallback callback = new BlockCallback() { - @Override - public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block) { - int[] status = new int[1]; - Ruby runtime = context.runtime; - int result = checkErrno(runtime, runtime.getPosix().waitpid(pid, status, 0)); + BlockCallback callback = (ctx, args, block) -> { + while (waitpid(ctx.runtime, pid, 0) == 0) {} - return RubyStatus.newProcessStatus(runtime, status[0], pid); - } + return last_status(ctx, recv); }; return RubyThread.startWaiterThread( diff --git a/core/src/main/java/org/jruby/RubySignal.java b/core/src/main/java/org/jruby/RubySignal.java index 77aa0f45b14..62ca459a287 100644 --- a/core/src/main/java/org/jruby/RubySignal.java +++ b/core/src/main/java/org/jruby/RubySignal.java @@ -143,9 +143,9 @@ public static IRubyObject list(ThreadContext context, IRubyObject recv) { if (names == null) { names = RubyHash.newHash(runtime); for (Map.Entry sig : RubySignal.list().entrySet()) { - names.op_aset(context, runtime.freezeAndDedupString(runtime.newString(sig.getKey())), runtime.newFixnum(sig.getValue())); + names.op_aset(context, runtime.newDeduplicatedString(sig.getKey()), runtime.newFixnum(sig.getValue())); } - names.op_aset(context, runtime.freezeAndDedupString(runtime.newString("EXIT")), runtime.newFixnum(0)); + names.op_aset(context, runtime.newDeduplicatedString("EXIT"), runtime.newFixnum(0)); recv.getInternalVariables().setInternalVariable("signal_list", names); } else { names.dup(context); diff --git a/core/src/main/java/org/jruby/RubyTime.java b/core/src/main/java/org/jruby/RubyTime.java index 0ec3b325463..188698d0917 100644 --- a/core/src/main/java/org/jruby/RubyTime.java +++ b/core/src/main/java/org/jruby/RubyTime.java @@ -2038,7 +2038,7 @@ private static long extractTime(ThreadContext context, IRubyObject time) { long t; if (time instanceof RubyTime) { - return ((RubyTime) time).getDateTime().getMillis(); + return ((RubyTime) time).getDateTime().withZoneRetainFields(DateTimeZone.UTC).getMillis(); } else if (time instanceof RubyStruct) { t = ((RubyStruct) time).aref(context.runtime.newSymbol("to_i")).convertToInteger().getLongValue(); } else { diff --git a/core/src/main/java/org/jruby/ast/AliasNode.java b/core/src/main/java/org/jruby/ast/AliasNode.java index e733c766749..767443bfc48 100644 --- a/core/src/main/java/org/jruby/ast/AliasNode.java +++ b/core/src/main/java/org/jruby/ast/AliasNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** Represents an alias statement (alias newName oldName). */ @@ -43,8 +42,8 @@ public class AliasNode extends Node { private final Node oldName; private final Node newName; - public AliasNode(ISourcePosition position, Node newName, Node oldName) { - super(position, newName.containsVariableAssignment() || oldName.containsVariableAssignment()); + public AliasNode(int line, Node newName, Node oldName) { + super(line, newName.containsVariableAssignment() || oldName.containsVariableAssignment()); this.oldName = oldName; this.newName = newName; } diff --git a/core/src/main/java/org/jruby/ast/AndNode.java b/core/src/main/java/org/jruby/ast/AndNode.java index 20987affd6f..38fd6c5d422 100644 --- a/core/src/main/java/org/jruby/ast/AndNode.java +++ b/core/src/main/java/org/jruby/ast/AndNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a && (and) operator. @@ -44,10 +43,9 @@ public class AndNode extends Node implements BinaryOperatorNode { private final Node firstNode; private final Node secondNode; - public AndNode(ISourcePosition position, Node firstNode, Node secondNode) { - super(position, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); + public AndNode(int line, Node firstNode, Node secondNode) { + super(line, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); - assert firstNode != null : "AndNode.first == null"; assert secondNode != null : "AndNode.second == null"; this.firstNode = firstNode; diff --git a/core/src/main/java/org/jruby/ast/ArgsCatNode.java b/core/src/main/java/org/jruby/ast/ArgsCatNode.java index afe4abc242d..5b41559f429 100644 --- a/core/src/main/java/org/jruby/ast/ArgsCatNode.java +++ b/core/src/main/java/org/jruby/ast/ArgsCatNode.java @@ -35,16 +35,14 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class ArgsCatNode extends Node { private final Node firstNode; private final Node secondNode; - public ArgsCatNode(ISourcePosition position, Node firstNode, Node secondNode) { - super(position, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); + public ArgsCatNode(int line, Node firstNode, Node secondNode) { + super(line, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); - assert firstNode != null : "ArgsCatNode.first == null"; assert secondNode != null : "ArgsCatNode.second == null"; this.firstNode = firstNode; diff --git a/core/src/main/java/org/jruby/ast/ArgsNode.java b/core/src/main/java/org/jruby/ast/ArgsNode.java index 9aea702c89e..c9b64d4cb1d 100644 --- a/core/src/main/java/org/jruby/ast/ArgsNode.java +++ b/core/src/main/java/org/jruby/ast/ArgsNode.java @@ -37,7 +37,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.runtime.Helpers; /** @@ -66,17 +65,17 @@ public class ArgsNode extends Node { /** * Construct a new ArgsNode with no keyword arguments. */ - public ArgsNode(ISourcePosition position, ListNode pre, ListNode optionalArguments, + public ArgsNode(int line, ListNode pre, ListNode optionalArguments, RestArgNode rest, ListNode post, BlockArgNode blockArgNode) { - this(position, pre, optionalArguments, rest, post, null, null, blockArgNode); + this(line, pre, optionalArguments, rest, post, null, null, blockArgNode); } /** * Construct a new ArgsNode with keyword arguments. */ - public ArgsNode(ISourcePosition position, ListNode pre, ListNode optionalArguments, + public ArgsNode(int line, ListNode pre, ListNode optionalArguments, RestArgNode rest, ListNode post, ListNode keywords, KeywordRestArgNode keyRest, BlockArgNode blockArgNode) { - super(position, pre != null && pre.containsVariableAssignment() || + super(line, pre != null && pre.containsVariableAssignment() || optionalArguments != null && optionalArguments.containsVariableAssignment() || rest != null && rest.containsVariableAssignment() || post != null && post.containsVariableAssignment() || @@ -91,7 +90,7 @@ public ArgsNode(ISourcePosition position, ListNode pre, ListNode optionalArgumen int size = preSize + optSize + postSize + keywordsSize; args = size > 0 ? new Node[size] : NO_ARGS; - optIndex = (short) (preSize != 0 ? preSize : 0); + optIndex = (short) preSize; postIndex = (short) (optSize != 0 ? optIndex + optSize : optIndex); keywordsIndex = (short) (postSize != 0 ? postIndex + postSize : postIndex); @@ -130,23 +129,6 @@ public boolean hasKwargs() { boolean keywords = getKeywordCount() > 0; return keywords || keyRest != null; } - - public int countKeywords() { - if (hasKwargs()) { - boolean keywords = args.length - keywordsIndex > 0; - if (keywords) { - // Rest keyword argument - return 0; - } - return args.length - keywordsIndex; - } else { - return 0; - } - } - - public boolean hasRestArg() { - return restArgNode != null; - } /** * Accept for the visitor pattern. @@ -161,7 +143,7 @@ public T accept(NodeVisitor iVisitor) { * Gets the required arguments at the beginning of the argument definition */ public ListNode getPre() { - return new ListNode(getPosition()).addAll(args, 0, getPreCount()); + return new ListNode(getLine()).addAll(args, 0, getPreCount()); } public int getRequiredArgsCount() { @@ -173,11 +155,7 @@ public int getOptionalArgsCount() { } public ListNode getPost() { - return new ListNode(getPosition()).addAll(args, postIndex, getPostCount()); - } - - public int getMaxArgumentsCount() { - return hasRestArg() ? -1 : getRequiredArgsCount() + getOptionalArgsCount(); + return new ListNode(getLine()).addAll(args, postIndex, getPostCount()); } /** @@ -185,7 +163,7 @@ public int getMaxArgumentsCount() { * @return Returns a ListNode */ public ListNode getOptArgs() { - return new ListNode(getPosition()).addAll(args, optIndex, getOptionalArgsCount()); + return new ListNode(getLine()).addAll(args, optIndex, getOptionalArgsCount()); } /** @@ -196,6 +174,11 @@ public RestArgNode getRestArgNode() { return restArgNode; } + // Used by jrubyc/jit (Ruby code) + public boolean hasRestArg() { + return restArgNode != null; + } + /** * Gets the explicit block argument of the parameter list (&block). * @@ -214,7 +197,7 @@ public int getPreCount() { } public ListNode getKeywords() { - return new ListNode(getPosition()).addAll(args, keywordsIndex, getKeywordCount()); + return new ListNode(getLine()).addAll(args, keywordsIndex, getKeywordCount()); } public KeywordRestArgNode getKeyRest() { diff --git a/core/src/main/java/org/jruby/ast/ArgsPushNode.java b/core/src/main/java/org/jruby/ast/ArgsPushNode.java index b7d0462a404..da789574302 100644 --- a/core/src/main/java/org/jruby/ast/ArgsPushNode.java +++ b/core/src/main/java/org/jruby/ast/ArgsPushNode.java @@ -33,16 +33,14 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class ArgsPushNode extends Node { private Node firstNode; private Node secondNode; - public ArgsPushNode(ISourcePosition position, Node firstNode, Node secondNode) { - super(position, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); + public ArgsPushNode(int line, Node firstNode, Node secondNode) { + super(line, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); - assert firstNode != null : "ArgsPushNode.first == null"; assert secondNode != null : "ArgsPushNode.second == null"; this.firstNode = firstNode; diff --git a/core/src/main/java/org/jruby/ast/ArgumentNode.java b/core/src/main/java/org/jruby/ast/ArgumentNode.java index 31ebd07bcbf..a84a45acc19 100644 --- a/core/src/main/java/org/jruby/ast/ArgumentNode.java +++ b/core/src/main/java/org/jruby/ast/ArgumentNode.java @@ -34,7 +34,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Simple Node for named entities. Things like the name of a method will make a node @@ -45,8 +44,8 @@ public class ArgumentNode extends Node implements INameNode { private final RubySymbol identifier; private final int location; - public ArgumentNode(ISourcePosition position, RubySymbol identifier, int location) { - super(position, false); + public ArgumentNode(int line, RubySymbol identifier, int location) { + super(line, false); this.identifier = identifier; this.location = location; // All variables should be depth 0 in this case diff --git a/core/src/main/java/org/jruby/ast/ArrayNode.java b/core/src/main/java/org/jruby/ast/ArrayNode.java index 21c7ea205a3..5ed25ce74a8 100644 --- a/core/src/main/java/org/jruby/ast/ArrayNode.java +++ b/core/src/main/java/org/jruby/ast/ArrayNode.java @@ -35,20 +35,19 @@ import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents an array. This could be an array literal, quoted words or some args stuff. */ public class ArrayNode extends ListNode implements ILiteralNode { - public ArrayNode(ISourcePosition position, Node firstNode) { - super(position, firstNode); + public ArrayNode(int line, Node firstNode) { + super(line, firstNode); assert firstNode != null : "ArrayNode.first == null"; } - public ArrayNode(ISourcePosition position) { - super(position); + public ArrayNode(int line) { + super(line); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/AssignableNode.java b/core/src/main/java/org/jruby/ast/AssignableNode.java index b206bee27d0..03976f5acd0 100644 --- a/core/src/main/java/org/jruby/ast/AssignableNode.java +++ b/core/src/main/java/org/jruby/ast/AssignableNode.java @@ -31,20 +31,18 @@ package org.jruby.ast; -import org.jruby.lexer.yacc.ISourcePosition; - /** * Base class of any node which can be assigned to. */ public abstract class AssignableNode extends Node { private Node valueNode; - public AssignableNode(ISourcePosition position) { - super(position, true); + public AssignableNode(int line) { + super(line, true); } - public AssignableNode(ISourcePosition position, Node valueNode, boolean containsAssignment) { - super(position, containsAssignment); + public AssignableNode(int line, Node valueNode, boolean containsAssignment) { + super(line, containsAssignment); this.valueNode = valueNode; } diff --git a/core/src/main/java/org/jruby/ast/AttrAssignNode.java b/core/src/main/java/org/jruby/ast/AttrAssignNode.java index 6a61caf291f..894264a929d 100644 --- a/core/src/main/java/org/jruby/ast/AttrAssignNode.java +++ b/core/src/main/java/org/jruby/ast/AttrAssignNode.java @@ -34,7 +34,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Node that represents an assignment of either an array element or attribute. @@ -46,8 +45,8 @@ public class AttrAssignNode extends Node implements INameNode, IArgumentNode { private final Node blockNode; private final boolean isLazy; - public AttrAssignNode(ISourcePosition position, Node receiverNode, RubySymbol name, Node argsNode, Node blockNode, boolean isLazy) { - super(position, receiverNode != null && receiverNode.containsVariableAssignment() || argsNode != null && argsNode.containsVariableAssignment()); + public AttrAssignNode(int line, Node receiverNode, RubySymbol name, Node argsNode, Node blockNode, boolean isLazy) { + super(line, receiverNode != null && receiverNode.containsVariableAssignment() || argsNode != null && argsNode.containsVariableAssignment()); assert receiverNode != null : "receiverNode is not null"; // TODO: At least ParserSupport.attrset passes argsNode as null. ImplicitNil is wrong magic for diff --git a/core/src/main/java/org/jruby/ast/BackRefNode.java b/core/src/main/java/org/jruby/ast/BackRefNode.java index 1d631a0b251..29fb0122fd7 100644 --- a/core/src/main/java/org/jruby/ast/BackRefNode.java +++ b/core/src/main/java/org/jruby/ast/BackRefNode.java @@ -36,7 +36,6 @@ import org.jcodings.specific.USASCIIEncoding; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; import org.jruby.util.DefinedMessage; @@ -53,8 +52,8 @@ public class BackRefNode extends Node { **/ private final char type; - public BackRefNode(ISourcePosition position, int type) { - super(position, false); + public BackRefNode(int line, int type) { + super(line, false); this.type = (char) type; DefinedMessage.byText("$" + (char)type); } diff --git a/core/src/main/java/org/jruby/ast/BeginNode.java b/core/src/main/java/org/jruby/ast/BeginNode.java index 61c22275b4a..c87bbce5062 100644 --- a/core/src/main/java/org/jruby/ast/BeginNode.java +++ b/core/src/main/java/org/jruby/ast/BeginNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Begin/End block. A Begin ... End block without rescue. @@ -43,10 +42,8 @@ public class BeginNode extends Node { private final Node bodyNode; - public BeginNode(ISourcePosition position, Node bodyNode) { - super(position, bodyNode.containsVariableAssignment()); - - assert bodyNode != null : "bodyNode is not null"; + public BeginNode(int line, Node bodyNode) { + super(line, bodyNode.containsVariableAssignment()); this.bodyNode = bodyNode; } diff --git a/core/src/main/java/org/jruby/ast/BignumNode.java b/core/src/main/java/org/jruby/ast/BignumNode.java index bbda335762d..14dc3ef1a93 100644 --- a/core/src/main/java/org/jruby/ast/BignumNode.java +++ b/core/src/main/java/org/jruby/ast/BignumNode.java @@ -37,7 +37,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a big integer literal. @@ -45,8 +44,8 @@ public class BignumNode extends NumericNode implements SideEffectFree { private BigInteger value; - public BignumNode(ISourcePosition position, BigInteger value) { - super(position); + public BignumNode(int line, BigInteger value) { + super(line); this.value = value; } @@ -60,7 +59,7 @@ public T accept(NodeVisitor iVisitor) { @Override public NumericNode negate() { - return new BignumNode(getPosition(), value.negate()); + return new BignumNode(getLine(), value.negate()); } /** diff --git a/core/src/main/java/org/jruby/ast/BinaryOperatorNode.java b/core/src/main/java/org/jruby/ast/BinaryOperatorNode.java index c9f571751d4..35bd45a087f 100644 --- a/core/src/main/java/org/jruby/ast/BinaryOperatorNode.java +++ b/core/src/main/java/org/jruby/ast/BinaryOperatorNode.java @@ -38,11 +38,11 @@ public interface BinaryOperatorNode { * Gets the firstNode. * @return Returns a Node */ - public abstract Node getFirstNode(); + Node getFirstNode(); /** * Gets the secondNode. * @return Returns a Node */ - public abstract Node getSecondNode(); + Node getSecondNode(); } \ No newline at end of file diff --git a/core/src/main/java/org/jruby/ast/BlockAcceptingNode.java b/core/src/main/java/org/jruby/ast/BlockAcceptingNode.java index 4d22b21d92b..44b67cb078b 100644 --- a/core/src/main/java/org/jruby/ast/BlockAcceptingNode.java +++ b/core/src/main/java/org/jruby/ast/BlockAcceptingNode.java @@ -40,7 +40,6 @@ * the callable node during construction. */ public interface BlockAcceptingNode { - public Node getIterNode(); - - public Node setIterNode(Node iterNode); + Node getIterNode(); + Node setIterNode(Node iterNode); } \ No newline at end of file diff --git a/core/src/main/java/org/jruby/ast/BlockArgNode.java b/core/src/main/java/org/jruby/ast/BlockArgNode.java index 199a4c0574c..f5fd87e5d75 100644 --- a/core/src/main/java/org/jruby/ast/BlockArgNode.java +++ b/core/src/main/java/org/jruby/ast/BlockArgNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * An explicit block argument (&my_block) in parameter list. @@ -46,14 +45,14 @@ public class BlockArgNode extends Node implements INameNode { private final int count; private final RubySymbol name; - public BlockArgNode(ISourcePosition position, int count, RubySymbol name) { - super(position, false); + public BlockArgNode(int line, int count, RubySymbol name) { + super(line, false); this.count = count; this.name = name; } public BlockArgNode(ArgumentNode argNode) { - this(argNode.getPosition(), argNode.getIndex(), argNode.getName()); + this(argNode.getLine(), argNode.getIndex(), argNode.getName()); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/BlockNode.java b/core/src/main/java/org/jruby/ast/BlockNode.java index 220f83a799e..df3d402c42b 100644 --- a/core/src/main/java/org/jruby/ast/BlockNode.java +++ b/core/src/main/java/org/jruby/ast/BlockNode.java @@ -35,14 +35,13 @@ package org.jruby.ast; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a block of nodes (read that as list). */ public class BlockNode extends ListNode { - public BlockNode(ISourcePosition position) { - super(position); + public BlockNode(int line) { + super(line); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/BlockPassNode.java b/core/src/main/java/org/jruby/ast/BlockPassNode.java index 351141d2f84..09242bde65a 100644 --- a/core/src/main/java/org/jruby/ast/BlockPassNode.java +++ b/core/src/main/java/org/jruby/ast/BlockPassNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Explicit block argument (on caller side): @@ -54,8 +53,8 @@ public class BlockPassNode extends Node { */ private Node argsNode; - public BlockPassNode(ISourcePosition position, Node bodyNode) { - super(position, bodyNode != null && bodyNode.containsVariableAssignment()); + public BlockPassNode(int line, Node bodyNode) { + super(line, bodyNode != null && bodyNode.containsVariableAssignment()); this.bodyNode = bodyNode; } diff --git a/core/src/main/java/org/jruby/ast/BreakNode.java b/core/src/main/java/org/jruby/ast/BreakNode.java index d3c81a6b369..497342fc44b 100644 --- a/core/src/main/java/org/jruby/ast/BreakNode.java +++ b/core/src/main/java/org/jruby/ast/BreakNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a 'break' statement. @@ -43,8 +42,8 @@ public class BreakNode extends Node implements NonLocalControlFlowNode { private final Node valueNode; - public BreakNode(ISourcePosition position, Node valueNode) { - super(position, valueNode != null && valueNode.containsVariableAssignment()); + public BreakNode(int line, Node valueNode) { + super(line, valueNode != null && valueNode.containsVariableAssignment()); assert valueNode != null : "valueNode is not null"; diff --git a/core/src/main/java/org/jruby/ast/CallNode.java b/core/src/main/java/org/jruby/ast/CallNode.java index 380de622994..758b4fbeabf 100644 --- a/core/src/main/java/org/jruby/ast/CallNode.java +++ b/core/src/main/java/org/jruby/ast/CallNode.java @@ -38,7 +38,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * A method or operator call. @@ -50,14 +49,12 @@ public class CallNode extends Node implements INameNode, IArgumentNode, BlockAcc private RubySymbol name; private final boolean isLazy; - public CallNode(ISourcePosition position, Node receiverNode, RubySymbol name, Node argsNode, + public CallNode(int line, Node receiverNode, RubySymbol name, Node argsNode, Node iterNode, boolean isLazy) { - super(position, receiverNode.containsVariableAssignment() || + super(line, receiverNode.containsVariableAssignment() || argsNode != null && argsNode.containsVariableAssignment() || iterNode != null && iterNode.containsVariableAssignment()); - assert receiverNode != null : "receiverNode is not null"; - this.name = name; this.receiverNode = receiverNode; this.argsNode = argsNode; diff --git a/core/src/main/java/org/jruby/ast/CaseNode.java b/core/src/main/java/org/jruby/ast/CaseNode.java index 695938aac0c..a46ab7f73b2 100644 --- a/core/src/main/java/org/jruby/ast/CaseNode.java +++ b/core/src/main/java/org/jruby/ast/CaseNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * A Case statement. Represents a complete case statement, including the body with its @@ -52,8 +51,8 @@ public class CaseNode extends Node { private final ListNode cases; private Node elseNode = null; - public CaseNode(ISourcePosition position, Node caseNode, ListNode cases) { - super(position, caseNode != null && caseNode.containsVariableAssignment() || cases.containsVariableAssignment()); + public CaseNode(int line, Node caseNode, ListNode cases) { + super(line, caseNode != null && caseNode.containsVariableAssignment() || cases.containsVariableAssignment()); assert cases != null : "caseBody is not null"; // TODO: Rewriter and compiler assume case when empty expression. In MRI this is just diff --git a/core/src/main/java/org/jruby/ast/ClassNode.java b/core/src/main/java/org/jruby/ast/ClassNode.java index dccf74445df..6a5c2060d4f 100644 --- a/core/src/main/java/org/jruby/ast/ClassNode.java +++ b/core/src/main/java/org/jruby/ast/ClassNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** @@ -48,8 +47,8 @@ public class ClassNode extends Node implements IScopingNode { private final Node superNode; private final int endLine; - public ClassNode(ISourcePosition position, Colon3Node cpath, StaticScope scope, Node bodyNode, Node superNode, int endLine) { - super(position, cpath.containsVariableAssignment() || bodyNode.containsVariableAssignment() || superNode != null && superNode.containsVariableAssignment()); + public ClassNode(int line, Colon3Node cpath, StaticScope scope, Node bodyNode, Node superNode, int endLine) { + super(line, cpath.containsVariableAssignment() || bodyNode.containsVariableAssignment() || superNode != null && superNode.containsVariableAssignment()); assert scope != null : "scope is not null"; assert bodyNode != null : "bodyNode is not null"; diff --git a/core/src/main/java/org/jruby/ast/ClassVarAsgnNode.java b/core/src/main/java/org/jruby/ast/ClassVarAsgnNode.java index ca5a056c714..e8093e9b0c0 100644 --- a/core/src/main/java/org/jruby/ast/ClassVarAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/ClassVarAsgnNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Class variable assignment node. @@ -49,8 +48,8 @@ public class ClassVarAsgnNode extends AssignableNode implements INameNode { * @param name id of the class variable to assign to * @param valueNode Node used to compute the new value when the assignment is evaled */ - public ClassVarAsgnNode(ISourcePosition position, RubySymbol name, Node valueNode) { - super(position, valueNode, valueNode != null && valueNode.containsVariableAssignment()); + public ClassVarAsgnNode(int line, RubySymbol name, Node valueNode) { + super(line, valueNode, valueNode != null && valueNode.containsVariableAssignment()); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/ClassVarDeclNode.java b/core/src/main/java/org/jruby/ast/ClassVarDeclNode.java index c703dba738a..fe20c7377dd 100644 --- a/core/src/main/java/org/jruby/ast/ClassVarDeclNode.java +++ b/core/src/main/java/org/jruby/ast/ClassVarDeclNode.java @@ -38,7 +38,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Class variable declaration. @@ -47,8 +46,8 @@ public class ClassVarDeclNode extends AssignableNode implements INameNode { private final RubySymbol name; - public ClassVarDeclNode(ISourcePosition position, RubySymbol name, Node valueNode) { - super(position, valueNode, valueNode != null && valueNode.containsVariableAssignment()); + public ClassVarDeclNode(int line, RubySymbol name, Node valueNode) { + super(line, valueNode, valueNode != null && valueNode.containsVariableAssignment()); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/ClassVarNode.java b/core/src/main/java/org/jruby/ast/ClassVarNode.java index 303aea5c0ed..1d5e382d387 100644 --- a/core/src/main/java/org/jruby/ast/ClassVarNode.java +++ b/core/src/main/java/org/jruby/ast/ClassVarNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Access to a class variable. @@ -45,8 +44,8 @@ public class ClassVarNode extends Node implements INameNode, SideEffectFree { private final RubySymbol name; - public ClassVarNode(ISourcePosition position, RubySymbol name) { - super(position, false); + public ClassVarNode(int line, RubySymbol name) { + super(line, false); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/Colon2ConstNode.java b/core/src/main/java/org/jruby/ast/Colon2ConstNode.java index 9980498381c..02fa43565ee 100644 --- a/core/src/main/java/org/jruby/ast/Colon2ConstNode.java +++ b/core/src/main/java/org/jruby/ast/Colon2ConstNode.java @@ -6,15 +6,14 @@ package org.jruby.ast; import org.jruby.RubySymbol; -import org.jruby.lexer.yacc.ISourcePosition; /** * * @author enebo */ public class Colon2ConstNode extends Colon2Node { - public Colon2ConstNode(ISourcePosition position, Node leftNode, RubySymbol name) { - super(position, leftNode, name); + public Colon2ConstNode(int line, Node leftNode, RubySymbol name) { + super(line, leftNode, name); assert leftNode != null: "Colon2ConstNode cannot have null leftNode"; } diff --git a/core/src/main/java/org/jruby/ast/Colon2ImplicitNode.java b/core/src/main/java/org/jruby/ast/Colon2ImplicitNode.java index c95db0956dc..db61ce3fe6f 100644 --- a/core/src/main/java/org/jruby/ast/Colon2ImplicitNode.java +++ b/core/src/main/java/org/jruby/ast/Colon2ImplicitNode.java @@ -30,7 +30,6 @@ package org.jruby.ast; import org.jruby.RubySymbol; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a bare class declaration (e.g. class Foo/module Foo). This is slightly misnamed @@ -38,7 +37,7 @@ * In JRuby 2, we will rename this. */ public class Colon2ImplicitNode extends Colon2Node { - public Colon2ImplicitNode(ISourcePosition position, RubySymbol name) { - super(position, null, name); + public Colon2ImplicitNode(int line, RubySymbol name) { + super(line, null, name); } } diff --git a/core/src/main/java/org/jruby/ast/Colon2Node.java b/core/src/main/java/org/jruby/ast/Colon2Node.java index 1f0acbcc525..2e49f408911 100644 --- a/core/src/main/java/org/jruby/ast/Colon2Node.java +++ b/core/src/main/java/org/jruby/ast/Colon2Node.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a '::' constant access or method call (Java::JavaClass). @@ -45,8 +44,8 @@ public abstract class Colon2Node extends Colon3Node implements INameNode { protected final Node leftNode; - public Colon2Node(ISourcePosition position, Node leftNode, RubySymbol name) { - super(position, name, leftNode != null && leftNode.containsVariableAssignment); + public Colon2Node(int line, Node leftNode, RubySymbol name) { + super(line, name, leftNode != null && leftNode.containsVariableAssignment); this.leftNode = leftNode; } diff --git a/core/src/main/java/org/jruby/ast/Colon3Node.java b/core/src/main/java/org/jruby/ast/Colon3Node.java index 50a5671d52b..7a878d98f51 100644 --- a/core/src/main/java/org/jruby/ast/Colon3Node.java +++ b/core/src/main/java/org/jruby/ast/Colon3Node.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Global scope node (::FooBar). This is used to gain access to the global scope (that of the @@ -46,12 +45,12 @@ public class Colon3Node extends Node implements INameNode { protected final RubySymbol name; - public Colon3Node(ISourcePosition position, RubySymbol name) { - this(position, name, false); + public Colon3Node(int line, RubySymbol name) { + this(line, name, false); } - protected Colon3Node(ISourcePosition position, RubySymbol name, boolean containsAssignment) { - super(position, containsAssignment); + protected Colon3Node(int line, RubySymbol name, boolean containsAssignment) { + super(line, containsAssignment); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/ComplexNode.java b/core/src/main/java/org/jruby/ast/ComplexNode.java index c3b10100b34..4da67c5d065 100644 --- a/core/src/main/java/org/jruby/ast/ComplexNode.java +++ b/core/src/main/java/org/jruby/ast/ComplexNode.java @@ -8,7 +8,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * @@ -17,8 +16,8 @@ public class ComplexNode extends NumericNode implements SideEffectFree { private NumericNode y; - public ComplexNode(ISourcePosition position, NumericNode y) { - super(position); + public ComplexNode(int line, NumericNode y) { + super(line); this.y = y; } diff --git a/core/src/main/java/org/jruby/ast/ConstDeclNode.java b/core/src/main/java/org/jruby/ast/ConstDeclNode.java index ce99bc71d1e..705018f09af 100644 --- a/core/src/main/java/org/jruby/ast/ConstDeclNode.java +++ b/core/src/main/java/org/jruby/ast/ConstDeclNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Declaration (and assignment) of a Constant. @@ -46,9 +45,9 @@ public class ConstDeclNode extends AssignableNode implements INameNode { private final RubySymbol name; private final INameNode constNode; - // TODO: Split this into two sub-classes so that name and constNode can be specified separately. - public ConstDeclNode(ISourcePosition position, RubySymbol name, INameNode constNode, Node valueNode) { - super(position, valueNode, valueNode != null && valueNode.containsVariableAssignment()); + // FIXME: Split this into two sub-classes so that name and constNode can be specified separately. + public ConstDeclNode(int line, RubySymbol name, INameNode constNode, Node valueNode) { + super(line, valueNode, valueNode != null && valueNode.containsVariableAssignment()); this.name = name; this.constNode = constNode; diff --git a/core/src/main/java/org/jruby/ast/ConstNode.java b/core/src/main/java/org/jruby/ast/ConstNode.java index e07e9310fdd..8280e2c470c 100644 --- a/core/src/main/java/org/jruby/ast/ConstNode.java +++ b/core/src/main/java/org/jruby/ast/ConstNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * The access to a Constant. @@ -45,8 +44,8 @@ public class ConstNode extends Node implements INameNode { private final RubySymbol name; - public ConstNode(ISourcePosition position, RubySymbol name) { - super(position, false); + public ConstNode(int line, RubySymbol name) { + super(line, false); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/DAsgnNode.java b/core/src/main/java/org/jruby/ast/DAsgnNode.java index 7f85ce2e57d..ada9de9d4ae 100644 --- a/core/src/main/java/org/jruby/ast/DAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/DAsgnNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * An assignment to a dynamic variable (e.g. block scope local variable). @@ -50,8 +49,8 @@ public class DAsgnNode extends AssignableNode implements INameNode, IScopedNode // is what index in the right scope to set the value. private final int location; - public DAsgnNode(ISourcePosition position, RubySymbol name, int location, Node valueNode) { - super(position, valueNode, true); + public DAsgnNode(int line, RubySymbol name, int location, Node valueNode) { + super(line, valueNode, true); this.name = name; this.location = location; } diff --git a/core/src/main/java/org/jruby/ast/DNode.java b/core/src/main/java/org/jruby/ast/DNode.java index 16b4df4b316..00163f4e29c 100644 --- a/core/src/main/java/org/jruby/ast/DNode.java +++ b/core/src/main/java/org/jruby/ast/DNode.java @@ -2,7 +2,6 @@ import org.jcodings.Encoding; import org.jcodings.specific.ASCIIEncoding; -import org.jruby.lexer.yacc.ISourcePosition; /** * Base class for all D (e.g. Dynamic) node types like DStrNode, DSymbolNode, etc... @@ -10,15 +9,15 @@ public abstract class DNode extends ListNode { protected Encoding encoding; - public DNode(ISourcePosition position) { + public DNode(int line) { // FIXME: I believe this possibly should be default parsed encoding but this is // what we currently default to if we happen to receive a null encoding. This is // an attempt to at least always have a valid encoding set to something. - this(position, ASCIIEncoding.INSTANCE); + this(line, ASCIIEncoding.INSTANCE); } - public DNode(ISourcePosition position, Encoding encoding) { - super(position); + public DNode(int line, Encoding encoding) { + super(line); assert encoding != null: getClass().getName() + " passed in a null encoding"; diff --git a/core/src/main/java/org/jruby/ast/DRegexpNode.java b/core/src/main/java/org/jruby/ast/DRegexpNode.java index b93f3760bd2..4df6e7a49e6 100644 --- a/core/src/main/java/org/jruby/ast/DRegexpNode.java +++ b/core/src/main/java/org/jruby/ast/DRegexpNode.java @@ -36,7 +36,6 @@ import org.jcodings.Encoding; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.RegexpOptions; /** @@ -47,8 +46,8 @@ public class DRegexpNode extends DNode implements ILiteralNode { private final RegexpOptions options; // 1.9 constructor - public DRegexpNode(ISourcePosition position, RegexpOptions options, Encoding encoding) { - super(position, encoding); + public DRegexpNode(int line, RegexpOptions options, Encoding encoding) { + super(line, encoding); this.options = options; } diff --git a/core/src/main/java/org/jruby/ast/DStrNode.java b/core/src/main/java/org/jruby/ast/DStrNode.java index 5533a37b3d8..e7fac02d128 100644 --- a/core/src/main/java/org/jruby/ast/DStrNode.java +++ b/core/src/main/java/org/jruby/ast/DStrNode.java @@ -36,7 +36,6 @@ import org.jcodings.Encoding; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * A string which contains some dynamic elements which needs to be evaluated (introduced by #). @@ -44,8 +43,8 @@ public class DStrNode extends DNode implements ILiteralNode { private boolean frozen; - public DStrNode(ISourcePosition position, Encoding encoding) { - super(position, encoding); + public DStrNode(int line, Encoding encoding) { + super(line, encoding); } @Override diff --git a/core/src/main/java/org/jruby/ast/DSymbolNode.java b/core/src/main/java/org/jruby/ast/DSymbolNode.java index ab948365535..51b7cc80617 100644 --- a/core/src/main/java/org/jruby/ast/DSymbolNode.java +++ b/core/src/main/java/org/jruby/ast/DSymbolNode.java @@ -30,7 +30,6 @@ package org.jruby.ast; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Node representing symbol in a form like ':"3jane"'. @@ -41,16 +40,14 @@ public class DSymbolNode extends DNode { * * @param node to be copied */ - public DSymbolNode(ISourcePosition position, DStrNode node) { - super(position, node.getEncoding()); - - assert node != null : "node is not null"; + public DSymbolNode(int line, DStrNode node) { + super(line, node.getEncoding()); addAll(node); } - public DSymbolNode(ISourcePosition position) { - super(position); + public DSymbolNode(int line) { + super(line); } @Override diff --git a/core/src/main/java/org/jruby/ast/DVarNode.java b/core/src/main/java/org/jruby/ast/DVarNode.java index 73ec6b1e98b..2b7cfb616d6 100644 --- a/core/src/main/java/org/jruby/ast/DVarNode.java +++ b/core/src/main/java/org/jruby/ast/DVarNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Access a dynamic variable (e.g. block scope local variable). @@ -50,8 +49,8 @@ public class DVarNode extends Node implements INameNode, IScopedNode, SideEffect // is what index in the right scope to set the value. private final int location; - public DVarNode(ISourcePosition position, int location, RubySymbol name) { - super(position, false); + public DVarNode(int line, int location, RubySymbol name) { + super(line, false); this.location = location; this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/DXStrNode.java b/core/src/main/java/org/jruby/ast/DXStrNode.java index 2ab70c25fea..a0558ca34d4 100644 --- a/core/src/main/java/org/jruby/ast/DXStrNode.java +++ b/core/src/main/java/org/jruby/ast/DXStrNode.java @@ -35,24 +35,23 @@ import org.jcodings.Encoding; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Dynamic backquote string. Backquote strings are eXecuted using the shell, hence the X * or maybe the X is due to the %x general quote syntax? */ public class DXStrNode extends DNode implements ILiteralNode { - public DXStrNode(ISourcePosition position, DStrNode node) { - super(position, node.getEncoding()); + public DXStrNode(int line, DStrNode node) { + super(line, node.getEncoding()); addAll(node); } - public DXStrNode(ISourcePosition position, Encoding encoding) { - super(position, encoding); + public DXStrNode(int line, Encoding encoding) { + super(line, encoding); } - public DXStrNode(ISourcePosition position) { - super(position); + public DXStrNode(int line) { + super(line); } @Override diff --git a/core/src/main/java/org/jruby/ast/DefinedNode.java b/core/src/main/java/org/jruby/ast/DefinedNode.java index 9f787bb8f4e..c301d819a15 100644 --- a/core/src/main/java/org/jruby/ast/DefinedNode.java +++ b/core/src/main/java/org/jruby/ast/DefinedNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * a defined statement. @@ -44,10 +43,8 @@ public class DefinedNode extends Node { private final Node expressionNode; - public DefinedNode(ISourcePosition position, Node expressionNode) { - super(position, expressionNode.containsVariableAssignment()); - - assert expressionNode != null : "expressionNode is not null"; + public DefinedNode(int line, Node expressionNode) { + super(line, expressionNode != null && expressionNode.containsVariableAssignment()); this.expressionNode = expressionNode; } diff --git a/core/src/main/java/org/jruby/ast/DefnNode.java b/core/src/main/java/org/jruby/ast/DefnNode.java index e135805a54e..7eda6c0693c 100644 --- a/core/src/main/java/org/jruby/ast/DefnNode.java +++ b/core/src/main/java/org/jruby/ast/DefnNode.java @@ -38,16 +38,14 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** * method definition node. */ public class DefnNode extends MethodDefNode implements INameNode { - public DefnNode(ISourcePosition position, RubySymbol name, ArgsNode argsNode, - StaticScope scope, Node bodyNode, int endLine) { - super(position, name, argsNode, scope, bodyNode, endLine); + public DefnNode(int line, RubySymbol name, ArgsNode argsNode, StaticScope scope, Node bodyNode, int endLine) { + super(line, name, argsNode, scope, bodyNode, endLine); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/DefsNode.java b/core/src/main/java/org/jruby/ast/DefsNode.java index e917f305d63..dea6315fae6 100644 --- a/core/src/main/java/org/jruby/ast/DefsNode.java +++ b/core/src/main/java/org/jruby/ast/DefsNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** @@ -46,9 +45,9 @@ public class DefsNode extends MethodDefNode implements INameNode { private final Node receiverNode; - public DefsNode(ISourcePosition position, Node receiverNode, RubySymbol name, ArgsNode argsNode, + public DefsNode(int line, Node receiverNode, RubySymbol name, ArgsNode argsNode, StaticScope scope, Node bodyNode, int endLine) { - super(position, name, argsNode, scope, bodyNode, endLine); + super(line, name, argsNode, scope, bodyNode, endLine); assert receiverNode != null : "receiverNode is not null"; diff --git a/core/src/main/java/org/jruby/ast/DotNode.java b/core/src/main/java/org/jruby/ast/DotNode.java index 59e4b0e6b34..15c9825b52c 100644 --- a/core/src/main/java/org/jruby/ast/DotNode.java +++ b/core/src/main/java/org/jruby/ast/DotNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a range literal. @@ -47,11 +46,9 @@ public class DotNode extends Node { private final boolean exclusive; private final boolean isLiteral; - public DotNode(ISourcePosition position, Node beginNode, Node endNode, boolean exclusive, - boolean isLiteral) { - super(position, beginNode.containsVariableAssignment() || endNode.containsVariableAssignment()); + public DotNode(int line, Node beginNode, Node endNode, boolean exclusive, boolean isLiteral) { + super(line, beginNode.containsVariableAssignment() || endNode.containsVariableAssignment()); - assert beginNode != null : "beginNode is not null"; assert endNode != null : "endNode is not null"; this.beginNode = beginNode; diff --git a/core/src/main/java/org/jruby/ast/EncodingNode.java b/core/src/main/java/org/jruby/ast/EncodingNode.java index af107143bcd..b37b5874c60 100644 --- a/core/src/main/java/org/jruby/ast/EncodingNode.java +++ b/core/src/main/java/org/jruby/ast/EncodingNode.java @@ -32,7 +32,6 @@ import java.util.List; import org.jcodings.Encoding; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents __ENCODING__. @@ -40,8 +39,8 @@ public class EncodingNode extends Node { private final Encoding encoding; - public EncodingNode(ISourcePosition position, Encoding encoding) { - super(position, false); + public EncodingNode(int line, Encoding encoding) { + super(line, false); this.encoding = encoding; } diff --git a/core/src/main/java/org/jruby/ast/EnsureNode.java b/core/src/main/java/org/jruby/ast/EnsureNode.java index 179d792e840..6e11867701b 100644 --- a/core/src/main/java/org/jruby/ast/EnsureNode.java +++ b/core/src/main/java/org/jruby/ast/EnsureNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * An 'ensure' statement. @@ -44,10 +43,8 @@ public class EnsureNode extends Node { private final Node bodyNode; private final Node ensureNode; - public EnsureNode(ISourcePosition position, Node bodyNode, Node ensureNode) { - super(position, bodyNode.containsVariableAssignment() || ensureNode != null && ensureNode.containsVariableAssignment()); - - assert bodyNode != null : "bodyNode is not null"; + public EnsureNode(int line, Node bodyNode, Node ensureNode) { + super(line, bodyNode.containsVariableAssignment() || ensureNode != null && ensureNode.containsVariableAssignment()); this.bodyNode = bodyNode; this.ensureNode = ensureNode; diff --git a/core/src/main/java/org/jruby/ast/EvStrNode.java b/core/src/main/java/org/jruby/ast/EvStrNode.java index d197786ddf7..62eadc4196c 100644 --- a/core/src/main/java/org/jruby/ast/EvStrNode.java +++ b/core/src/main/java/org/jruby/ast/EvStrNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** Represents an #{} expression in a string. This Node is always a subnode * of a DStrNode, DXStrNode or a DRegexpNode. @@ -47,8 +46,8 @@ public class EvStrNode extends Node { private final Node body; - public EvStrNode(ISourcePosition position, Node body) { - super(position, body != null && body.containsVariableAssignment()); + public EvStrNode(int line, Node body) { + super(line, body != null && body.containsVariableAssignment()); this.body = body; } diff --git a/core/src/main/java/org/jruby/ast/FCallNode.java b/core/src/main/java/org/jruby/ast/FCallNode.java index ee65dc01758..abf9c06ab52 100644 --- a/core/src/main/java/org/jruby/ast/FCallNode.java +++ b/core/src/main/java/org/jruby/ast/FCallNode.java @@ -38,7 +38,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a method call with self as an implicit receiver. @@ -48,12 +47,12 @@ public class FCallNode extends Node implements INameNode, IArgumentNode, BlockAc protected Node argsNode; protected Node iterNode; - public FCallNode(ISourcePosition position, RubySymbol name) { - this(position, name, null, null); + public FCallNode(int line, RubySymbol name) { + this(line, name, null, null); } - public FCallNode(ISourcePosition position, RubySymbol name, Node argsNode, Node iterNode) { - super(position, argsNode != null && argsNode.containsVariableAssignment() || iterNode != null && iterNode.containsVariableAssignment()); + public FCallNode(int line, RubySymbol name, Node argsNode, Node iterNode) { + super(line, argsNode != null && argsNode.containsVariableAssignment() || iterNode != null && iterNode.containsVariableAssignment()); this.name = name; this.argsNode = argsNode; this.iterNode = iterNode; diff --git a/core/src/main/java/org/jruby/ast/FalseNode.java b/core/src/main/java/org/jruby/ast/FalseNode.java index d534f3954fb..61df9fa1acc 100644 --- a/core/src/main/java/org/jruby/ast/FalseNode.java +++ b/core/src/main/java/org/jruby/ast/FalseNode.java @@ -35,14 +35,13 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a false literal. */ public class FalseNode extends Node implements SideEffectFree { - public FalseNode(ISourcePosition position) { - super(position, false); + public FalseNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/FileNode.java b/core/src/main/java/org/jruby/ast/FileNode.java index ae82109c116..9af7859f49c 100644 --- a/core/src/main/java/org/jruby/ast/FileNode.java +++ b/core/src/main/java/org/jruby/ast/FileNode.java @@ -29,14 +29,13 @@ package org.jruby.ast; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; /** * Represents __FILE__ nodes */ public class FileNode extends StrNode implements SideEffectFree { - public FileNode(ISourcePosition position, ByteList value) { - super(position, value); + public FileNode(int line, ByteList value) { + super(line, value); } } diff --git a/core/src/main/java/org/jruby/ast/FixnumNode.java b/core/src/main/java/org/jruby/ast/FixnumNode.java index 4468eaf8783..f3ca0b7166d 100644 --- a/core/src/main/java/org/jruby/ast/FixnumNode.java +++ b/core/src/main/java/org/jruby/ast/FixnumNode.java @@ -36,7 +36,6 @@ import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents an integer literal. @@ -44,8 +43,8 @@ public class FixnumNode extends NumericNode implements ILiteralNode, SideEffectFree { private long value; - public FixnumNode(ISourcePosition position, long value) { - super(position); + public FixnumNode(int line, long value) { + super(line); this.value = value; } @@ -59,7 +58,7 @@ public NodeType getNodeType() { @Override public NumericNode negate() { - return new FixnumNode(getPosition(), -value); + return new FixnumNode(getLine(), -value); } /** diff --git a/core/src/main/java/org/jruby/ast/FlipNode.java b/core/src/main/java/org/jruby/ast/FlipNode.java index d482165a7eb..eb491b6cd80 100644 --- a/core/src/main/java/org/jruby/ast/FlipNode.java +++ b/core/src/main/java/org/jruby/ast/FlipNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * A Range in a boolean expression (named after a FlipFlop component in electronic?). @@ -49,10 +48,9 @@ public class FlipNode extends Node { // is what index in the right scope to set the value. private final int location; - public FlipNode(ISourcePosition position, Node beginNode, Node endNode, boolean exclusive, int location) { - super(position, beginNode.containsVariableAssignment() || endNode.containsVariableAssignment()); + public FlipNode(int line, Node beginNode, Node endNode, boolean exclusive, int location) { + super(line, beginNode.containsVariableAssignment() || endNode.containsVariableAssignment()); - assert beginNode != null : "beginNode is not null"; assert endNode != null : "endNode is not null"; this.beginNode = beginNode; diff --git a/core/src/main/java/org/jruby/ast/FloatNode.java b/core/src/main/java/org/jruby/ast/FloatNode.java index fd84c7fa7d9..92d9cea845b 100644 --- a/core/src/main/java/org/jruby/ast/FloatNode.java +++ b/core/src/main/java/org/jruby/ast/FloatNode.java @@ -36,7 +36,6 @@ import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a float literal. @@ -44,8 +43,8 @@ public class FloatNode extends NumericNode implements ILiteralNode, SideEffectFree { private double value; - public FloatNode(ISourcePosition position, double value) { - super(position); + public FloatNode(int line, double value) { + super(line); this.value = value; } @@ -59,7 +58,7 @@ public T accept(NodeVisitor iVisitor) { @Override public NumericNode negate() { - return new FloatNode(getPosition(), -value); + return new FloatNode(getLine(), -value); } /** diff --git a/core/src/main/java/org/jruby/ast/ForNode.java b/core/src/main/java/org/jruby/ast/ForNode.java index e5c3c05f39f..2b615d02201 100644 --- a/core/src/main/java/org/jruby/ast/ForNode.java +++ b/core/src/main/java/org/jruby/ast/ForNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** @@ -47,12 +46,12 @@ public class ForNode extends IterNode { private Node iterNode; - public ForNode(ISourcePosition position, Node varNode, Node bodyNode, Node iterNode, StaticScope scope, int endLine) { + public ForNode(int line, Node varNode, Node bodyNode, Node iterNode, StaticScope scope, int endLine) { // For nodes do not have their own scope so we pass null to indicate this. // 'For's are implemented as blocks in evaluation, but they have no scope so we // just deal with this lack of scope throughout its lifespan. We should probably // change the way this works to get rid of multiple null checks. - super(position, varNode, scope, bodyNode, endLine); + super(line, varNode, scope, bodyNode, endLine); assert iterNode != null : "iterNode is not null"; diff --git a/core/src/main/java/org/jruby/ast/GlobalAsgnNode.java b/core/src/main/java/org/jruby/ast/GlobalAsgnNode.java index a3b3051f2e7..f8f690fcc87 100644 --- a/core/src/main/java/org/jruby/ast/GlobalAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/GlobalAsgnNode.java @@ -39,7 +39,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents an assignment to a global variable. @@ -47,8 +46,8 @@ public class GlobalAsgnNode extends AssignableNode implements INameNode { private final RubySymbol name; - public GlobalAsgnNode(ISourcePosition position, RubySymbol name, Node valueNode) { - super(position, valueNode, valueNode != null && valueNode.containsVariableAssignment()); + public GlobalAsgnNode(int line, RubySymbol name, Node valueNode) { + super(line, valueNode, valueNode != null && valueNode.containsVariableAssignment()); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/GlobalVarNode.java b/core/src/main/java/org/jruby/ast/GlobalVarNode.java index e5b3f69905d..087da4fd46e 100644 --- a/core/src/main/java/org/jruby/ast/GlobalVarNode.java +++ b/core/src/main/java/org/jruby/ast/GlobalVarNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * access to a global variable. @@ -45,8 +44,8 @@ public class GlobalVarNode extends Node implements INameNode, SideEffectFree { private final RubySymbol name; - public GlobalVarNode(ISourcePosition position, RubySymbol name) { - super(position, false); + public GlobalVarNode(int line, RubySymbol name) { + super(line, false); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/HashNode.java b/core/src/main/java/org/jruby/ast/HashNode.java index 32a014351ea..665e51e0c75 100644 --- a/core/src/main/java/org/jruby/ast/HashNode.java +++ b/core/src/main/java/org/jruby/ast/HashNode.java @@ -37,7 +37,6 @@ import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.KeyValuePair; /** @@ -48,14 +47,14 @@ public class HashNode extends Node implements ILiteralNode { private final List> pairs; private boolean hasOnlySymbolKeys = true; - public HashNode(ISourcePosition position) { - super(position, false); + public HashNode(int line) { + super(line, false); - pairs = new ArrayList>(); + pairs = new ArrayList<>(); } - public HashNode(ISourcePosition position, KeyValuePair pair) { - this(position); + public HashNode(int line, KeyValuePair pair) { + this(line); add(pair); } @@ -101,7 +100,7 @@ public List> getPairs() { } public List childNodes() { - List children = new ArrayList(); + List children = new ArrayList<>(); for (KeyValuePair pair: pairs) { children.add(pair.getKey()); diff --git a/core/src/main/java/org/jruby/ast/IArgumentNode.java b/core/src/main/java/org/jruby/ast/IArgumentNode.java index 9452de31ee2..e595b815d4d 100644 --- a/core/src/main/java/org/jruby/ast/IArgumentNode.java +++ b/core/src/main/java/org/jruby/ast/IArgumentNode.java @@ -33,6 +33,6 @@ * Does the node contain an argument list? */ public interface IArgumentNode { - public Node getArgsNode(); - public Node setArgsNode(Node argsNode); + Node getArgsNode(); + Node setArgsNode(Node argsNode); } diff --git a/core/src/main/java/org/jruby/ast/IScopedNode.java b/core/src/main/java/org/jruby/ast/IScopedNode.java index 8e42cc3349d..878729a0abc 100644 --- a/core/src/main/java/org/jruby/ast/IScopedNode.java +++ b/core/src/main/java/org/jruby/ast/IScopedNode.java @@ -7,10 +7,10 @@ public interface IScopedNode { /** * How many scopes down we should look for this variable */ - public int getDepth(); + int getDepth(); /** * Which index (or slot) this variable is located at in the scope it is stored in. */ - public int getIndex(); + int getIndex(); } diff --git a/core/src/main/java/org/jruby/ast/IfNode.java b/core/src/main/java/org/jruby/ast/IfNode.java index 5a19ace5070..ef06d93a51e 100644 --- a/core/src/main/java/org/jruby/ast/IfNode.java +++ b/core/src/main/java/org/jruby/ast/IfNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * an 'if' statement. @@ -46,15 +45,14 @@ public class IfNode extends Node { private final Node thenBody; private final Node elseBody; - public IfNode(ISourcePosition position, Node condition, Node thenBody, Node elseBody) { - super(position, condition.containsVariableAssignment || thenBody != null && thenBody.containsVariableAssignment || + public IfNode(int line, Node condition, Node thenBody, Node elseBody) { + super(line, condition.containsVariableAssignment || thenBody != null && thenBody.containsVariableAssignment || elseBody != null && elseBody.containsVariableAssignment); - - assert condition != null : "condition is not null"; this.condition = condition; this.thenBody = thenBody; this.elseBody = elseBody; + setNewline(); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/InstAsgnNode.java b/core/src/main/java/org/jruby/ast/InstAsgnNode.java index 2e64b62db65..28c0eeb8511 100644 --- a/core/src/main/java/org/jruby/ast/InstAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/InstAsgnNode.java @@ -38,7 +38,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents an instance variable assignment. @@ -47,11 +46,12 @@ public class InstAsgnNode extends AssignableNode implements INameNode { private final RubySymbol name; /** - * @param name the name of the instance variable + * @param line location of this instance variable + * @param name the name of this instance variable * @param valueNode the value of the variable **/ - public InstAsgnNode(ISourcePosition position, RubySymbol name, Node valueNode) { - super(position, valueNode, valueNode != null && valueNode.containsVariableAssignment()); + public InstAsgnNode(int line, RubySymbol name, Node valueNode) { + super(line, valueNode, valueNode != null && valueNode.containsVariableAssignment()); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/InstVarNode.java b/core/src/main/java/org/jruby/ast/InstVarNode.java index ee8cebe7a5a..5737267e576 100644 --- a/core/src/main/java/org/jruby/ast/InstVarNode.java +++ b/core/src/main/java/org/jruby/ast/InstVarNode.java @@ -38,7 +38,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents an instance variable accessor. @@ -46,8 +45,8 @@ public class InstVarNode extends Node implements INameNode, SideEffectFree { private final RubySymbol name; - public InstVarNode(ISourcePosition position, RubySymbol name) { - super(position, false); + public InstVarNode(int line, RubySymbol name) { + super(line, false); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/IterNode.java b/core/src/main/java/org/jruby/ast/IterNode.java index 6bf9c3c543a..b52c90a6bf2 100644 --- a/core/src/main/java/org/jruby/ast/IterNode.java +++ b/core/src/main/java/org/jruby/ast/IterNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** @@ -53,8 +52,8 @@ public class IterNode extends Node implements DefNode { * Used by ForNode only. * This is to support 1.8-style assignments which only 'for' expressions use. */ - public IterNode(ISourcePosition position, Node args, StaticScope scope, Node body, int endLine) { - super(position, args != null && args.containsVariableAssignment || body != null && body.containsVariableAssignment); + public IterNode(int line, Node args, StaticScope scope, Node body, int endLine) { + super(line, args != null && args.containsVariableAssignment || body != null && body.containsVariableAssignment); this.varNode = args; this.scope = scope; @@ -65,8 +64,8 @@ public IterNode(ISourcePosition position, Node args, StaticScope scope, Node bod /** * Used for all non-for types of blocks. */ - public IterNode(ISourcePosition position, ArgsNode args, Node body, StaticScope scope, int endLine) { - super(position, args != null && args.containsVariableAssignment || body != null && body.containsVariableAssignment); + public IterNode(int line, ArgsNode args, Node body, StaticScope scope, int endLine) { + super(line, args != null && args.containsVariableAssignment || body != null && body.containsVariableAssignment); this.varNode = args; this.bodyNode = body == null ? NilImplicitNode.NIL : body; diff --git a/core/src/main/java/org/jruby/ast/KeywordArgNode.java b/core/src/main/java/org/jruby/ast/KeywordArgNode.java index 7cd26549b60..f5e283931a3 100644 --- a/core/src/main/java/org/jruby/ast/KeywordArgNode.java +++ b/core/src/main/java/org/jruby/ast/KeywordArgNode.java @@ -6,7 +6,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * @@ -15,8 +14,8 @@ public class KeywordArgNode extends Node { private final AssignableNode assignable; - public KeywordArgNode(ISourcePosition position, AssignableNode assignable) { - super(position, true); + public KeywordArgNode(int line, AssignableNode assignable) { + super(line, true); this.assignable = assignable; } diff --git a/core/src/main/java/org/jruby/ast/KeywordRestArgNode.java b/core/src/main/java/org/jruby/ast/KeywordRestArgNode.java index e737d0c7889..8160b78e06b 100644 --- a/core/src/main/java/org/jruby/ast/KeywordRestArgNode.java +++ b/core/src/main/java/org/jruby/ast/KeywordRestArgNode.java @@ -2,14 +2,13 @@ import org.jruby.RubySymbol; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * */ public class KeywordRestArgNode extends ArgumentNode { - public KeywordRestArgNode(ISourcePosition position, RubySymbol name, int index) { - super(position, name, index); + public KeywordRestArgNode(int line, RubySymbol name, int index) { + super(line, name, index); } @Override diff --git a/core/src/main/java/org/jruby/ast/LambdaNode.java b/core/src/main/java/org/jruby/ast/LambdaNode.java index a7ebf7771b8..1772b7c982d 100644 --- a/core/src/main/java/org/jruby/ast/LambdaNode.java +++ b/core/src/main/java/org/jruby/ast/LambdaNode.java @@ -1,4 +1,5 @@ -/***** BEGIN LICENSE BLOCK ***** +/* + **** BEGIN LICENSE BLOCK ***** * Version: EPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Eclipse Public @@ -30,15 +31,14 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** * Stubby lambda node (1.9 only) */ public class LambdaNode extends IterNode { - public LambdaNode(ISourcePosition position, ArgsNode args, Node body, StaticScope scope, int endLine) { - super(position, args, body, scope, endLine); + public LambdaNode(int line, ArgsNode args, Node body, StaticScope scope, int endLine) { + super(line, args, body, scope, endLine); } @Override diff --git a/core/src/main/java/org/jruby/ast/ListNode.java b/core/src/main/java/org/jruby/ast/ListNode.java index 1b818691078..34b37170d0f 100644 --- a/core/src/main/java/org/jruby/ast/ListNode.java +++ b/core/src/main/java/org/jruby/ast/ListNode.java @@ -35,7 +35,6 @@ import java.util.Iterator; import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * All Nodes which have a list representation inherit this. This is also used @@ -59,18 +58,18 @@ public class ListNode extends Node implements Iterable { /** * Create a new ListNode. * - * @param position where list is + * @param line where list is * @param firstNode first element of the list */ - public ListNode(ISourcePosition position, Node firstNode) { - super(position, firstNode != null && firstNode.containsVariableAssignment); + public ListNode(int line, Node firstNode) { + super(line, firstNode != null && firstNode.containsVariableAssignment); single = firstNode; size = 1; } - public ListNode(ISourcePosition position) { - super(position, false); + public ListNode(int line) { + super(line, false); } public NodeType getNodeType() { @@ -153,8 +152,6 @@ public ListNode add(Node node) { if (node.containsVariableAssignment()) containsVariableAssignment = true; addInternal(node); - if (getPosition() == null) setPosition(node.getPosition()); - return this; } @@ -173,9 +170,8 @@ public ListNode addAll(ListNode other) { if (other != null && other.size() > 0) { if (other.containsVariableAssignment()) containsVariableAssignment = true; addAllInternal(other); - - if (getPosition() == null) setPosition(other.getPosition()); } + return this; } diff --git a/core/src/main/java/org/jruby/ast/LiteralNode.java b/core/src/main/java/org/jruby/ast/LiteralNode.java index 4ca222f2a54..8b323702e9d 100644 --- a/core/src/main/java/org/jruby/ast/LiteralNode.java +++ b/core/src/main/java/org/jruby/ast/LiteralNode.java @@ -5,7 +5,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; /** @@ -21,8 +20,8 @@ public class LiteralNode extends Node implements InvisibleNode { private final RubySymbol name; - public LiteralNode(ISourcePosition position, RubySymbol name) { - super(position, false); + public LiteralNode(int line, RubySymbol name) { + super(line, false); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/LocalAsgnNode.java b/core/src/main/java/org/jruby/ast/LocalAsgnNode.java index 8397cb9bb1d..41ea3992cc0 100644 --- a/core/src/main/java/org/jruby/ast/LocalAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/LocalAsgnNode.java @@ -38,7 +38,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * An assignment to a local variable. @@ -51,8 +50,8 @@ public class LocalAsgnNode extends AssignableNode implements INameNode, IScopedN // is what index in the right scope to set the value. private final int location; - public LocalAsgnNode(ISourcePosition position, RubySymbol name, int location, Node valueNode) { - super(position, valueNode, true); + public LocalAsgnNode(int line, RubySymbol name, int location, Node valueNode) { + super(line, valueNode, true); this.name = name; this.location = location; } diff --git a/core/src/main/java/org/jruby/ast/LocalVarNode.java b/core/src/main/java/org/jruby/ast/LocalVarNode.java index bdd17af74b4..25dc37e3fb7 100644 --- a/core/src/main/java/org/jruby/ast/LocalVarNode.java +++ b/core/src/main/java/org/jruby/ast/LocalVarNode.java @@ -37,7 +37,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Access a local variable @@ -50,8 +49,8 @@ public class LocalVarNode extends Node implements INameNode, IScopedNode, SideEf // is what index in the right scope to set the value. private final int location; - public LocalVarNode(ISourcePosition position, int location, RubySymbol name) { - super(position, false); + public LocalVarNode(int line, int location, RubySymbol name) { + super(line, false); this.location = location; this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/Match2CaptureNode.java b/core/src/main/java/org/jruby/ast/Match2CaptureNode.java index d964ee0d90b..7032fec994b 100644 --- a/core/src/main/java/org/jruby/ast/Match2CaptureNode.java +++ b/core/src/main/java/org/jruby/ast/Match2CaptureNode.java @@ -1,14 +1,12 @@ package org.jruby.ast; -import org.jruby.lexer.yacc.ISourcePosition; - public class Match2CaptureNode extends Match2Node { // Allocated locals that the regexp will assign after performing a match private final int[] scopeOffsets; - public Match2CaptureNode(ISourcePosition position, Node receiverNode, Node valueNode, + public Match2CaptureNode(int line, Node receiverNode, Node valueNode, int[] scopeOffsets) { - super(position, receiverNode, valueNode); + super(line, receiverNode, valueNode); this.scopeOffsets = scopeOffsets; } diff --git a/core/src/main/java/org/jruby/ast/Match2Node.java b/core/src/main/java/org/jruby/ast/Match2Node.java index df6195c648b..fa5bc205da8 100644 --- a/core/src/main/java/org/jruby/ast/Match2Node.java +++ b/core/src/main/java/org/jruby/ast/Match2Node.java @@ -35,16 +35,14 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class Match2Node extends Node { private final Node receiverNode; private final Node valueNode; - public Match2Node(ISourcePosition position, Node receiverNode, Node valueNode) { - super(position, receiverNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); + public Match2Node(int line, Node receiverNode, Node valueNode) { + super(line, receiverNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); - assert receiverNode != null : "receiverNode is not null"; assert valueNode != null : "valueNode is not null"; this.receiverNode = receiverNode; diff --git a/core/src/main/java/org/jruby/ast/Match3Node.java b/core/src/main/java/org/jruby/ast/Match3Node.java index de5d26ad168..4fb7ece6133 100644 --- a/core/src/main/java/org/jruby/ast/Match3Node.java +++ b/core/src/main/java/org/jruby/ast/Match3Node.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Used when a Regexp literal is the RHS of a match call. E.g., "abc" =~ /.+/ @@ -44,10 +43,9 @@ public class Match3Node extends Node { private final Node receiverNode; private final Node valueNode; - public Match3Node(ISourcePosition position, Node receiverNode, Node valueNode) { - super(position, receiverNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); + public Match3Node(int line, Node receiverNode, Node valueNode) { + super(line, receiverNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); - assert receiverNode != null : "receiverNode is not null"; assert valueNode != null : "valueNode is not null"; this.receiverNode = receiverNode; diff --git a/core/src/main/java/org/jruby/ast/MatchNode.java b/core/src/main/java/org/jruby/ast/MatchNode.java index a5bdb85a8ee..57a7a56de2a 100644 --- a/core/src/main/java/org/jruby/ast/MatchNode.java +++ b/core/src/main/java/org/jruby/ast/MatchNode.java @@ -35,15 +35,12 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class MatchNode extends Node { private final Node regexpNode; - public MatchNode(ISourcePosition position, Node regexpNode) { - super(position, regexpNode.containsVariableAssignment()); - - assert regexpNode != null : "regexpNode is not null"; + public MatchNode(int line, Node regexpNode) { + super(line, regexpNode.containsVariableAssignment()); this.regexpNode = regexpNode; } diff --git a/core/src/main/java/org/jruby/ast/MethodDefNode.java b/core/src/main/java/org/jruby/ast/MethodDefNode.java index 99a04966087..23573613142 100644 --- a/core/src/main/java/org/jruby/ast/MethodDefNode.java +++ b/core/src/main/java/org/jruby/ast/MethodDefNode.java @@ -31,7 +31,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** @@ -43,10 +42,12 @@ public abstract class MethodDefNode extends Node implements INameNode, DefNode { protected final StaticScope scope; protected final Node bodyNode; protected final int endLine; + // We lazily compile methods in IR but Ruby expects next and break to raise syntax error so we will eagerly + // build methods which contain those two keywords. + protected boolean containsNextBreak = false; - public MethodDefNode(ISourcePosition position, RubySymbol name, ArgsNode argsNode, - StaticScope scope, Node bodyNode, int endLine) { - super(position, bodyNode.containsVariableAssignment()); + public MethodDefNode(int line, RubySymbol name, ArgsNode argsNode, StaticScope scope, Node bodyNode, int endLine) { + super(line, bodyNode.containsVariableAssignment()); this.name = name; this.argsNode = argsNode; @@ -55,7 +56,6 @@ public MethodDefNode(ISourcePosition position, RubySymbol name, ArgsNode argsNod this.endLine = endLine; } - /** * Gets the argsNode. * @return Returns a Node @@ -97,4 +97,12 @@ public RubySymbol getName() { public int getEndLine() { return endLine; } + + public void setContainsNextBreak() { + containsNextBreak = true; + } + + public boolean containsBreakNext() { + return containsNextBreak; + } } diff --git a/core/src/main/java/org/jruby/ast/ModuleNode.java b/core/src/main/java/org/jruby/ast/ModuleNode.java index f5bbd23307f..ccb71750559 100644 --- a/core/src/main/java/org/jruby/ast/ModuleNode.java +++ b/core/src/main/java/org/jruby/ast/ModuleNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** @@ -47,8 +46,8 @@ public class ModuleNode extends Node implements IScopingNode { private final Node bodyNode; private final int endLine; - public ModuleNode(ISourcePosition position, Colon3Node cpath, StaticScope scope, Node bodyNode, int endLine) { - super(position, cpath.containsVariableAssignment() || bodyNode.containsVariableAssignment()); + public ModuleNode(int line, Colon3Node cpath, StaticScope scope, Node bodyNode, int endLine) { + super(line, cpath.containsVariableAssignment() || bodyNode.containsVariableAssignment()); assert scope != null : "scope is not null"; assert bodyNode != null : "bodyNode is not null"; diff --git a/core/src/main/java/org/jruby/ast/MultipleAsgnNode.java b/core/src/main/java/org/jruby/ast/MultipleAsgnNode.java index 544610cc507..eb904bba793 100644 --- a/core/src/main/java/org/jruby/ast/MultipleAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/MultipleAsgnNode.java @@ -1,4 +1,5 @@ -/***** BEGIN LICENSE BLOCK ***** +/* + **** BEGIN LICENSE BLOCK ***** * Version: EPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Eclipse Public @@ -31,7 +32,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * @@ -41,8 +41,8 @@ public class MultipleAsgnNode extends AssignableNode { private final Node rest; private final ListNode post; - public MultipleAsgnNode(ISourcePosition position, ListNode pre, Node rest, ListNode post) { - super(position); + public MultipleAsgnNode(int line, ListNode pre, Node rest, ListNode post) { + super(line); this.pre = pre; this.rest = rest; this.post = post; diff --git a/core/src/main/java/org/jruby/ast/NewlineNode.java b/core/src/main/java/org/jruby/ast/NewlineNode.java index ca5bf7b07c2..a969200a74b 100644 --- a/core/src/main/java/org/jruby/ast/NewlineNode.java +++ b/core/src/main/java/org/jruby/ast/NewlineNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Note: This is a dead class but we leave it because people write against Visitor @@ -54,11 +53,9 @@ public class NewlineNode extends Node { private final Node nextNode; @Deprecated - public NewlineNode(ISourcePosition position, Node nextNode) { - super(position, nextNode.containsVariableAssignment()); + public NewlineNode(int line, Node nextNode) { + super(line, nextNode.containsVariableAssignment()); - assert nextNode != null : "nextNode is not null"; - this.nextNode = nextNode; } diff --git a/core/src/main/java/org/jruby/ast/NextNode.java b/core/src/main/java/org/jruby/ast/NextNode.java index 9c0389f12c9..7b1c66afa5e 100644 --- a/core/src/main/java/org/jruby/ast/NextNode.java +++ b/core/src/main/java/org/jruby/ast/NextNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a 'next' statement. @@ -43,11 +42,9 @@ public class NextNode extends Node implements NonLocalControlFlowNode { private final Node valueNode; - public NextNode(ISourcePosition position, Node valueNode) { - super(position, valueNode.containsVariableAssignment()); - - assert valueNode != null : "valueNode is not null"; - + public NextNode(int line, Node valueNode) { + super(line, valueNode.containsVariableAssignment()); + this.valueNode = valueNode; } diff --git a/core/src/main/java/org/jruby/ast/NilImplicitNode.java b/core/src/main/java/org/jruby/ast/NilImplicitNode.java index 937bd3fa289..bc47a582404 100644 --- a/core/src/main/java/org/jruby/ast/NilImplicitNode.java +++ b/core/src/main/java/org/jruby/ast/NilImplicitNode.java @@ -1,7 +1,5 @@ package org.jruby.ast; -import org.jruby.lexer.yacc.InvalidSourcePosition; - /** * A node which behaves like a nil node, but is not actually present in the AST as a syntactical * element (e.g. IDE's should ignore occurrences of this node. We have this as separate subclass @@ -11,7 +9,7 @@ public class NilImplicitNode extends NilNode implements InvisibleNode { public static final NilImplicitNode NIL = new NilImplicitNode(); public NilImplicitNode() { - super(InvalidSourcePosition.INSTANCE); + super(-1); } public boolean isNil() { diff --git a/core/src/main/java/org/jruby/ast/NilNode.java b/core/src/main/java/org/jruby/ast/NilNode.java index d3c2b96a1d3..e1110dd276f 100644 --- a/core/src/main/java/org/jruby/ast/NilNode.java +++ b/core/src/main/java/org/jruby/ast/NilNode.java @@ -35,15 +35,14 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * represents 'nil' */ public class NilNode extends Node implements SideEffectFree { - public NilNode(ISourcePosition position) { - super(position, false); + public NilNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/Node.java b/core/src/main/java/org/jruby/ast/Node.java index c4844917be0..5021a0bb50f 100644 --- a/core/src/main/java/org/jruby/ast/Node.java +++ b/core/src/main/java/org/jruby/ast/Node.java @@ -41,13 +41,11 @@ import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.AbstractNodeVisitor; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; -import org.jruby.lexer.yacc.ISourcePositionHolder; /** * Base class for all Nodes in the AST */ -public abstract class Node implements ISourcePositionHolder, ISourcePosition { +public abstract class Node { // We define an actual list to get around bug in java integration (1387115) static final List EMPTY_LIST = new ArrayList<>(); @@ -61,8 +59,8 @@ public abstract class Node implements ISourcePositionHolder, ISourcePosition { protected boolean containsVariableAssignment; protected boolean newline; - public Node(ISourcePosition position, boolean containsAssignment) { - this.line = position.getLine(); + public Node(int line, boolean containsAssignment) { + this.line = line; this.containsVariableAssignment = containsAssignment; } @@ -70,15 +68,13 @@ public void setNewline() { this.newline = true; } - public boolean isNewline() { - return newline; + // Used by heredoc dedent processing. It gets unset so we do not liter line events because of it. + public void unsetNewline() { + this.newline = false; } - /** - * Location of this node within the source - */ - public ISourcePosition getPosition() { - return this; + public boolean isNewline() { + return newline; } public int getLine() { @@ -89,8 +85,8 @@ public String getFile() { return null; } - public void setPosition(ISourcePosition position) { - this.line = position.getLine(); + public void setLine(int line) { + this.line = line; } public abstract T accept(NodeVisitor visitor); @@ -150,7 +146,9 @@ public String toString(boolean indent, int indentation) { if (indent) indent(indentation, builder); - builder.append("(").append(getNodeName()); + builder.append('(').append(getNodeName()); + + if (isNewline()) builder.append('*'); String moreState = toStringInternal(); @@ -158,7 +156,7 @@ public String toString(boolean indent, int indentation) { if (this instanceof INameNode) builder.append(":").append(((INameNode) this).getName()); - builder.append(" line: ").append(getPosition().getLine()); + builder.append(" line: ").append(getLine()); String extraInfo = toStringExtraInfo(); if (extraInfo != null) builder.append(", ").append(extraInfo); diff --git a/core/src/main/java/org/jruby/ast/NonLocalControlFlowNode.java b/core/src/main/java/org/jruby/ast/NonLocalControlFlowNode.java index 8b74bf45f0f..3072fc5048e 100644 --- a/core/src/main/java/org/jruby/ast/NonLocalControlFlowNode.java +++ b/core/src/main/java/org/jruby/ast/NonLocalControlFlowNode.java @@ -9,6 +9,6 @@ * Marker interface for return, break, next, redo, retry */ public interface NonLocalControlFlowNode { - public Node getValueNode(); - public boolean hasValue(); + Node getValueNode(); + boolean hasValue(); } diff --git a/core/src/main/java/org/jruby/ast/NthRefNode.java b/core/src/main/java/org/jruby/ast/NthRefNode.java index 3673794c737..db7cdff542a 100644 --- a/core/src/main/java/org/jruby/ast/NthRefNode.java +++ b/core/src/main/java/org/jruby/ast/NthRefNode.java @@ -35,8 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; -import org.jruby.util.DefinedMessage; /** * Represents a $number ($0..$9) variable. @@ -44,8 +42,8 @@ public class NthRefNode extends Node { private final int matchNumber; - public NthRefNode(ISourcePosition position, int matchNumber) { - super(position, false); + public NthRefNode(int line, int matchNumber) { + super(line, false); this.matchNumber = matchNumber; } diff --git a/core/src/main/java/org/jruby/ast/NumericNode.java b/core/src/main/java/org/jruby/ast/NumericNode.java index 74633db36da..f874814cbc2 100644 --- a/core/src/main/java/org/jruby/ast/NumericNode.java +++ b/core/src/main/java/org/jruby/ast/NumericNode.java @@ -1,15 +1,13 @@ package org.jruby.ast; import org.jruby.ast.types.ILiteralNode; -import org.jruby.lexer.yacc.ISourcePosition; -import org.jruby.lexer.yacc.SyntaxException; /** * Any node representing a numeric value. */ public abstract class NumericNode extends Node implements ILiteralNode { - public NumericNode(ISourcePosition position) { - super(position, false); + public NumericNode(int line) { + super(line, false); } public NumericNode negate() { diff --git a/core/src/main/java/org/jruby/ast/OpAsgnAndNode.java b/core/src/main/java/org/jruby/ast/OpAsgnAndNode.java index 792ab7ad338..32fe47345c6 100644 --- a/core/src/main/java/org/jruby/ast/OpAsgnAndNode.java +++ b/core/src/main/java/org/jruby/ast/OpAsgnAndNode.java @@ -35,16 +35,14 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class OpAsgnAndNode extends Node implements BinaryOperatorNode { private final Node firstNode; private final Node secondNode; - public OpAsgnAndNode(ISourcePosition position, Node headNode, Node valueNode) { - super(position, headNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); + public OpAsgnAndNode(int line, Node headNode, Node valueNode) { + super(line, headNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); - assert headNode != null : "headNode is not null"; assert valueNode != null : "valueNode is not null"; firstNode = headNode; diff --git a/core/src/main/java/org/jruby/ast/OpAsgnConstDeclNode.java b/core/src/main/java/org/jruby/ast/OpAsgnConstDeclNode.java index faf1ce0e63b..1fac79e9c19 100644 --- a/core/src/main/java/org/jruby/ast/OpAsgnConstDeclNode.java +++ b/core/src/main/java/org/jruby/ast/OpAsgnConstDeclNode.java @@ -4,7 +4,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; import org.jruby.util.CommonByteLists; @@ -16,8 +15,8 @@ public class OpAsgnConstDeclNode extends Node implements BinaryOperatorNode { private final RubySymbol operator; private final Node rhs; - public OpAsgnConstDeclNode(ISourcePosition position, Node lhs, RubySymbol operator, Node rhs) { - super(position, lhs.containsVariableAssignment() || rhs.containsVariableAssignment()); + public OpAsgnConstDeclNode(int line, Node lhs, RubySymbol operator, Node rhs) { + super(line, lhs.containsVariableAssignment() || rhs.containsVariableAssignment()); this.lhs = lhs; this.operator = operator; @@ -62,7 +61,7 @@ public T accept(NodeVisitor visitor) { @Override public List childNodes() { - return createList(lhs, new LiteralNode(getPosition(), operator), rhs); + return createList(lhs, new LiteralNode(getLine(), operator), rhs); } @Override diff --git a/core/src/main/java/org/jruby/ast/OpAsgnNode.java b/core/src/main/java/org/jruby/ast/OpAsgnNode.java index 986930edb2a..82feeaff515 100644 --- a/core/src/main/java/org/jruby/ast/OpAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/OpAsgnNode.java @@ -36,7 +36,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; import org.jruby.util.CommonByteLists; @@ -51,11 +50,10 @@ public class OpAsgnNode extends Node { private final RubySymbol variableNameAsgn; private final boolean isLazy; - public OpAsgnNode(ISourcePosition position, Node receiverNode, Node valueNode, RubySymbol variableName, + public OpAsgnNode(int line, Node receiverNode, Node valueNode, RubySymbol variableName, RubySymbol operatorName, boolean isLazy) { - super(position, receiverNode.containsVariableAssignment()); + super(line, receiverNode.containsVariableAssignment()); - assert receiverNode != null : "receiverNode is not null"; assert valueNode != null : "valueNode is not null"; this.receiverNode = receiverNode; diff --git a/core/src/main/java/org/jruby/ast/OpAsgnOrNode.java b/core/src/main/java/org/jruby/ast/OpAsgnOrNode.java index 8f217e21ed9..42383d17a7b 100644 --- a/core/src/main/java/org/jruby/ast/OpAsgnOrNode.java +++ b/core/src/main/java/org/jruby/ast/OpAsgnOrNode.java @@ -35,16 +35,14 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class OpAsgnOrNode extends Node implements BinaryOperatorNode { private final Node firstNode; private final Node secondNode; - public OpAsgnOrNode(ISourcePosition position, Node headNode, Node valueNode) { - super(position, headNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); + public OpAsgnOrNode(int line, Node headNode, Node valueNode) { + super(line, headNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); - assert headNode != null : "headNode is not null"; assert valueNode != null : "valueNode is not null"; firstNode = headNode; diff --git a/core/src/main/java/org/jruby/ast/OpElementAsgnNode.java b/core/src/main/java/org/jruby/ast/OpElementAsgnNode.java index 7987b8fb9ac..e2ca1ae43fd 100644 --- a/core/src/main/java/org/jruby/ast/OpElementAsgnNode.java +++ b/core/src/main/java/org/jruby/ast/OpElementAsgnNode.java @@ -36,7 +36,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; import org.jruby.util.CommonByteLists; @@ -56,11 +55,10 @@ public class OpElementAsgnNode extends Node { private final Node blockNode; private final RubySymbol operatorName; - public OpElementAsgnNode(ISourcePosition position, Node receiverNode, RubySymbol operatorName, Node argsNode, + public OpElementAsgnNode(int line, Node receiverNode, RubySymbol operatorName, Node argsNode, Node valueNode, Node blockNode) { - super(position, receiverNode.containsVariableAssignment() || argsNode != null && argsNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); + super(line, receiverNode.containsVariableAssignment() || argsNode != null && argsNode.containsVariableAssignment() || valueNode.containsVariableAssignment()); - assert receiverNode != null : "receiverNode is not null"; assert valueNode != null : "valueNode is not null"; this.receiverNode = receiverNode; diff --git a/core/src/main/java/org/jruby/ast/OptArgNode.java b/core/src/main/java/org/jruby/ast/OptArgNode.java index b246292c399..f37adcf24cf 100644 --- a/core/src/main/java/org/jruby/ast/OptArgNode.java +++ b/core/src/main/java/org/jruby/ast/OptArgNode.java @@ -33,7 +33,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * @@ -42,8 +41,8 @@ public class OptArgNode extends Node implements INameNode { private final Node value; - public OptArgNode(ISourcePosition position, Node value) { - super(position, value != null && value.containsVariableAssignment()); + public OptArgNode(int line, Node value) { + super(line, value != null && value.containsVariableAssignment()); this.value = value; } diff --git a/core/src/main/java/org/jruby/ast/OrNode.java b/core/src/main/java/org/jruby/ast/OrNode.java index c16bd3348a8..a640b557401 100644 --- a/core/src/main/java/org/jruby/ast/OrNode.java +++ b/core/src/main/java/org/jruby/ast/OrNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * represents '||' (or) statements @@ -44,10 +43,9 @@ public class OrNode extends Node implements BinaryOperatorNode { private final Node firstNode; private final Node secondNode; - public OrNode(ISourcePosition position, Node firstNode, Node secondNode) { - super(position, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); + public OrNode(int line, Node firstNode, Node secondNode) { + super(line, firstNode.containsVariableAssignment() || secondNode.containsVariableAssignment()); - assert firstNode != null : "firstNode is not null"; assert secondNode != null : "secondNode is not null"; this.firstNode = firstNode; diff --git a/core/src/main/java/org/jruby/ast/PostExeNode.java b/core/src/main/java/org/jruby/ast/PostExeNode.java index c644a07a1d2..3c7bf2042e0 100644 --- a/core/src/main/java/org/jruby/ast/PostExeNode.java +++ b/core/src/main/java/org/jruby/ast/PostExeNode.java @@ -33,14 +33,13 @@ package org.jruby.ast; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Captures END statements (END {...}) */ public class PostExeNode extends IterNode { - public PostExeNode(ISourcePosition position, Node body, int endLine) { - super(position, new ArgsNode(position, null, null, null, null, null, null, null), body, null, endLine); + public PostExeNode(int line, Node body, int endLine) { + super(line, new ArgsNode(line, null, null, null, null, null, null, null), body, null, endLine); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/PreExe19Node.java b/core/src/main/java/org/jruby/ast/PreExe19Node.java index 6bdd04ad45f..773d5329d17 100644 --- a/core/src/main/java/org/jruby/ast/PreExe19Node.java +++ b/core/src/main/java/org/jruby/ast/PreExe19Node.java @@ -30,15 +30,14 @@ package org.jruby.ast; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** * A pre-execution construction (BEGIN { ... }). */ public class PreExe19Node extends PreExeNode { - public PreExe19Node(ISourcePosition position, StaticScope scope, Node body, int endLine) { - super(position, scope, body, endLine); + public PreExe19Node(int line, StaticScope scope, Node body, int endLine) { + super(line, scope, body, endLine); } @Override diff --git a/core/src/main/java/org/jruby/ast/PreExeNode.java b/core/src/main/java/org/jruby/ast/PreExeNode.java index 43cf121b029..52084c88518 100644 --- a/core/src/main/java/org/jruby/ast/PreExeNode.java +++ b/core/src/main/java/org/jruby/ast/PreExeNode.java @@ -30,15 +30,14 @@ package org.jruby.ast; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** * A pre-execution construction (BEGIN { ... }). */ public class PreExeNode extends IterNode { - public PreExeNode(ISourcePosition position, StaticScope scope, Node body, int endLine) { - super(position, new ArgsNode(position, null, null, null, null, null, null, null), body, scope, endLine); + public PreExeNode(int line, StaticScope scope, Node body, int endLine) { + super(line, new ArgsNode(line, null, null, null, null, null, null, null), body, scope, endLine); } @Override diff --git a/core/src/main/java/org/jruby/ast/RationalNode.java b/core/src/main/java/org/jruby/ast/RationalNode.java index 431bde1155a..74b1e37914b 100644 --- a/core/src/main/java/org/jruby/ast/RationalNode.java +++ b/core/src/main/java/org/jruby/ast/RationalNode.java @@ -8,7 +8,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * @@ -18,8 +17,8 @@ public class RationalNode extends NumericNode implements SideEffectFree { private final NumericNode numerator; private final NumericNode denominator; - public RationalNode(ISourcePosition position, NumericNode numerator, NumericNode denominator) { - super(position); + public RationalNode(int line, NumericNode numerator, NumericNode denominator) { + super(line); this.numerator = numerator; this.denominator = denominator; @@ -32,7 +31,7 @@ public T accept(NodeVisitor visitor) { @Override public NumericNode negate() { - return new RationalNode(getPosition(), numerator.negate(), denominator); + return new RationalNode(getLine(), numerator.negate(), denominator); } @Override diff --git a/core/src/main/java/org/jruby/ast/RedoNode.java b/core/src/main/java/org/jruby/ast/RedoNode.java index 9246bc29bfe..a3a3cc0f393 100644 --- a/core/src/main/java/org/jruby/ast/RedoNode.java +++ b/core/src/main/java/org/jruby/ast/RedoNode.java @@ -35,14 +35,13 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a 'redo' */ public class RedoNode extends Node implements NonLocalControlFlowNode { - public RedoNode(ISourcePosition position) { - super(position, false); + public RedoNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/RegexpNode.java b/core/src/main/java/org/jruby/ast/RegexpNode.java index e63800ffb9c..7c06097a82e 100644 --- a/core/src/main/java/org/jruby/ast/RegexpNode.java +++ b/core/src/main/java/org/jruby/ast/RegexpNode.java @@ -37,7 +37,6 @@ import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; import org.jruby.util.RegexpOptions; @@ -48,8 +47,8 @@ public class RegexpNode extends Node implements ILiteralNode { private final ByteList value; private final RegexpOptions options; - public RegexpNode(ISourcePosition position, ByteList value, RegexpOptions options) { - super(position, false); + public RegexpNode(int line, ByteList value, RegexpOptions options) { + super(line, false); this.value = value; this.options = options; diff --git a/core/src/main/java/org/jruby/ast/RequiredKeywordArgumentValueNode.java b/core/src/main/java/org/jruby/ast/RequiredKeywordArgumentValueNode.java index df521d298e6..023b86f27db 100644 --- a/core/src/main/java/org/jruby/ast/RequiredKeywordArgumentValueNode.java +++ b/core/src/main/java/org/jruby/ast/RequiredKeywordArgumentValueNode.java @@ -2,7 +2,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.InvalidSourcePosition; /** * Marker to indicate that rather than assigning nil (where in multiple @@ -14,7 +13,7 @@ */ public class RequiredKeywordArgumentValueNode extends Node implements InvisibleNode { public RequiredKeywordArgumentValueNode() { - super(InvalidSourcePosition.INSTANCE, false); + super(-1, false); } @Override diff --git a/core/src/main/java/org/jruby/ast/RescueBodyNode.java b/core/src/main/java/org/jruby/ast/RescueBodyNode.java index fd3f6559f76..0a09d454465 100644 --- a/core/src/main/java/org/jruby/ast/RescueBodyNode.java +++ b/core/src/main/java/org/jruby/ast/RescueBodyNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents the contents of a rescue to be evaluated @@ -45,8 +44,8 @@ public class RescueBodyNode extends Node { private final Node bodyNode; private final RescueBodyNode optRescueNode; - public RescueBodyNode(ISourcePosition position, Node exceptionNodes, Node bodyNode, RescueBodyNode optRescueNode) { - super(position, exceptionNodes != null && exceptionNodes.containsVariableAssignment() || + public RescueBodyNode(int line, Node exceptionNodes, Node bodyNode, RescueBodyNode optRescueNode) { + super(line, exceptionNodes != null && exceptionNodes.containsVariableAssignment() || bodyNode.containsVariableAssignment() || optRescueNode != null && optRescueNode.containsVariableAssignment()); assert bodyNode != null : "bodyNode is not null"; diff --git a/core/src/main/java/org/jruby/ast/RescueModNode.java b/core/src/main/java/org/jruby/ast/RescueModNode.java index afb0bbb2848..a0e931d5b6b 100644 --- a/core/src/main/java/org/jruby/ast/RescueModNode.java +++ b/core/src/main/java/org/jruby/ast/RescueModNode.java @@ -1,12 +1,10 @@ package org.jruby.ast; -import org.jruby.lexer.yacc.ISourcePosition; - /** * f rescue nil */ public class RescueModNode extends RescueNode { - public RescueModNode(ISourcePosition position, Node bodyNode, RescueBodyNode rescueNode) { - super(position, bodyNode, rescueNode, null /* else */); + public RescueModNode(int line, Node bodyNode, RescueBodyNode rescueNode) { + super(line, bodyNode, rescueNode, null /* else */); } } diff --git a/core/src/main/java/org/jruby/ast/RescueNode.java b/core/src/main/java/org/jruby/ast/RescueNode.java index bd581bb16cb..dbdf34c1fd9 100644 --- a/core/src/main/java/org/jruby/ast/RescueNode.java +++ b/core/src/main/java/org/jruby/ast/RescueNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a rescue statement @@ -46,8 +45,8 @@ public class RescueNode extends Node { private final RescueBodyNode rescueNode; private final Node elseNode; - public RescueNode(ISourcePosition position, Node bodyNode, RescueBodyNode rescueNode, Node elseNode) { - super(position, bodyNode != null && bodyNode.containsVariableAssignment() || + public RescueNode(int line, Node bodyNode, RescueBodyNode rescueNode, Node elseNode) { + super(line, bodyNode != null && bodyNode.containsVariableAssignment() || rescueNode != null && rescueNode.containsVariableAssignment() || elseNode != null && elseNode.containsVariableAssignment()); this.bodyNode = bodyNode; diff --git a/core/src/main/java/org/jruby/ast/RestArgNode.java b/core/src/main/java/org/jruby/ast/RestArgNode.java index 175a92d6977..d61926c4921 100644 --- a/core/src/main/java/org/jruby/ast/RestArgNode.java +++ b/core/src/main/java/org/jruby/ast/RestArgNode.java @@ -32,19 +32,18 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /* * The rest argument for a method (def foo(a, *b, c)). */ public class RestArgNode extends ArgumentNode implements INameNode { - public RestArgNode(ISourcePosition position, RubySymbol name, int index) { - super(position, name, index); + public RestArgNode(int line, RubySymbol name, int index) { + super(line, name, index); } // 1.9 only - lvar assign logic returns an Argument node public RestArgNode(ArgumentNode argNode) { - this(argNode.getPosition(), argNode.getName(), argNode.getIndex()); + this(argNode.getLine(), argNode.getName(), argNode.getIndex()); } public boolean isAnonymous() { diff --git a/core/src/main/java/org/jruby/ast/RetryNode.java b/core/src/main/java/org/jruby/ast/RetryNode.java index 70a3454afc4..2c90433eee5 100644 --- a/core/src/main/java/org/jruby/ast/RetryNode.java +++ b/core/src/main/java/org/jruby/ast/RetryNode.java @@ -34,14 +34,13 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a 'retry' statement. */ public class RetryNode extends Node implements NonLocalControlFlowNode { - public RetryNode(ISourcePosition position) { - super(position, false); + public RetryNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/ReturnNode.java b/core/src/main/java/org/jruby/ast/ReturnNode.java index 5a55ee68c1a..0f13127d566 100644 --- a/core/src/main/java/org/jruby/ast/ReturnNode.java +++ b/core/src/main/java/org/jruby/ast/ReturnNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a return statement. @@ -43,11 +42,9 @@ public class ReturnNode extends Node implements NonLocalControlFlowNode { private final Node valueNode; - public ReturnNode(ISourcePosition position, Node valueNode) { - super(position, valueNode.containsVariableAssignment()); - - assert valueNode != null : "valueNode is not null"; - + public ReturnNode(int line, Node valueNode) { + super(line, valueNode.containsVariableAssignment()); + this.valueNode = valueNode; } diff --git a/core/src/main/java/org/jruby/ast/RootNode.java b/core/src/main/java/org/jruby/ast/RootNode.java index f29c7c92026..811023554b2 100644 --- a/core/src/main/java/org/jruby/ast/RootNode.java +++ b/core/src/main/java/org/jruby/ast/RootNode.java @@ -34,7 +34,6 @@ import org.jruby.ParseResult; import org.jruby.ast.visitor.NodeVisitor; import org.jruby.ext.coverage.CoverageData; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; import org.jruby.runtime.DynamicScope; @@ -51,31 +50,24 @@ public class RootNode extends Node implements ParseResult { private final StaticScope staticScope; private final Node bodyNode; private final String file; - private int endPosition; private final int coverageMode; - public RootNode(ISourcePosition position, DynamicScope scope, Node bodyNode, String file) { - this(position, scope, bodyNode, file, -1, CoverageData.NONE); + public RootNode(int line, DynamicScope scope, Node bodyNode, String file) { + this(line, scope, bodyNode, file, CoverageData.NONE); } - public RootNode(ISourcePosition position, DynamicScope scope, Node bodyNode, String file, int endPosition, int coverageMode) { - super(position, bodyNode.containsVariableAssignment()); + public RootNode(int line, DynamicScope scope, Node bodyNode, String file, int coverageMode) { + super(line, bodyNode.containsVariableAssignment()); this.scope = scope; this.staticScope = scope.getStaticScope(); this.bodyNode = bodyNode; this.file = file; - this.endPosition = endPosition; this.coverageMode = coverageMode; staticScope.setFile(file); } - @Deprecated - public RootNode(ISourcePosition position, DynamicScope scope, Node bodyNode, String file, int endPosition) { - this(position, scope, bodyNode, file, endPosition, CoverageData.NONE); - } - public NodeType getNodeType() { return NodeType.ROOTNODE; } @@ -125,14 +117,6 @@ public List childNodes() { return createList(bodyNode); } - public boolean hasEndPosition() { - return endPosition != -1; - } - - public int getEndPosition() { - return endPosition; - } - // Is coverage enabled and is this a valid source file for coverage to apply? public int coverageMode() { return coverageMode; diff --git a/core/src/main/java/org/jruby/ast/SClassNode.java b/core/src/main/java/org/jruby/ast/SClassNode.java index 9f4f66a1739..3f95b798c9c 100644 --- a/core/src/main/java/org/jruby/ast/SClassNode.java +++ b/core/src/main/java/org/jruby/ast/SClassNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.parser.StaticScope; /** @@ -53,8 +52,8 @@ public class SClassNode extends Node { private final Node bodyNode; private final int endLine; - public SClassNode(ISourcePosition position, Node recvNode, StaticScope scope, Node bodyNode, int endLine) { - super(position, recvNode.containsVariableAssignment() || bodyNode.containsVariableAssignment()); + public SClassNode(int line, Node recvNode, StaticScope scope, Node bodyNode, int endLine) { + super(line, recvNode.containsVariableAssignment() || bodyNode.containsVariableAssignment()); assert scope != null : "scope is not null"; diff --git a/core/src/main/java/org/jruby/ast/SValueNode.java b/core/src/main/java/org/jruby/ast/SValueNode.java index b09daa76241..df7e9d9e779 100644 --- a/core/src/main/java/org/jruby/ast/SValueNode.java +++ b/core/src/main/java/org/jruby/ast/SValueNode.java @@ -32,15 +32,12 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class SValueNode extends Node { protected final Node node; - public SValueNode(ISourcePosition position, Node node) { - super(position, node.containsVariableAssignment()); - - assert node != null : "node is not null"; + public SValueNode(int line, Node node) { + super(line, node.containsVariableAssignment()); this.node = node; } diff --git a/core/src/main/java/org/jruby/ast/SelfNode.java b/core/src/main/java/org/jruby/ast/SelfNode.java index 070bb2f4629..7087e803376 100644 --- a/core/src/main/java/org/jruby/ast/SelfNode.java +++ b/core/src/main/java/org/jruby/ast/SelfNode.java @@ -35,14 +35,13 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents 'self' keyword */ public class SelfNode extends Node implements SideEffectFree { - public SelfNode(ISourcePosition position) { - super(position, false); + public SelfNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/SplatNode.java b/core/src/main/java/org/jruby/ast/SplatNode.java index 5953c62820e..2e6bdacb4de 100644 --- a/core/src/main/java/org/jruby/ast/SplatNode.java +++ b/core/src/main/java/org/jruby/ast/SplatNode.java @@ -33,15 +33,12 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; public class SplatNode extends Node { protected final Node node; - public SplatNode(ISourcePosition position, Node node) { - super(position, node.containsVariableAssignment()); - - assert node != null : "node is not null"; + public SplatNode(int line, Node node) { + super(line, node.containsVariableAssignment()); this.node = node; } diff --git a/core/src/main/java/org/jruby/ast/StarNode.java b/core/src/main/java/org/jruby/ast/StarNode.java index 1c90edeb5d7..d455ae935a6 100644 --- a/core/src/main/java/org/jruby/ast/StarNode.java +++ b/core/src/main/java/org/jruby/ast/StarNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents the unassignable star in a multiple assignent (e.g. a,b,* = arr). @@ -44,8 +43,8 @@ public class StarNode extends Node { /** * Constructor for StarNode. */ - public StarNode(ISourcePosition position) { - super(position, false); + public StarNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/StrNode.java b/core/src/main/java/org/jruby/ast/StrNode.java index f6226f37ab5..f65f3b4ac77 100644 --- a/core/src/main/java/org/jruby/ast/StrNode.java +++ b/core/src/main/java/org/jruby/ast/StrNode.java @@ -36,7 +36,6 @@ import java.util.List; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; import org.jruby.util.StringSupport; @@ -48,19 +47,19 @@ public class StrNode extends Node implements ILiteralNode, SideEffectFree { private final int codeRange; private boolean frozen; - public StrNode(ISourcePosition position, ByteList value) { - this(position, value, StringSupport.codeRangeScan(value.getEncoding(), value)); + public StrNode(int line, ByteList value) { + this(line, value, StringSupport.codeRangeScan(value.getEncoding(), value)); } - public StrNode(ISourcePosition position, ByteList value, int codeRange) { - super(position, false); + public StrNode(int line, ByteList value, int codeRange) { + super(line, false); this.value = value; this.codeRange = codeRange; } - public StrNode(ISourcePosition position, StrNode head, StrNode tail) { - super(position, false); + public StrNode(int line, StrNode head, StrNode tail) { + super(line, false); ByteList headBL = head.getValue(); ByteList tailBL = tail.getValue(); diff --git a/core/src/main/java/org/jruby/ast/SuperNode.java b/core/src/main/java/org/jruby/ast/SuperNode.java index ec5aad8864e..ead08f02f89 100644 --- a/core/src/main/java/org/jruby/ast/SuperNode.java +++ b/core/src/main/java/org/jruby/ast/SuperNode.java @@ -34,7 +34,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * A call to super(...) with arguments to a method. @@ -43,12 +42,12 @@ public class SuperNode extends Node implements BlockAcceptingNode { private final Node argsNode; private Node iterNode; - public SuperNode(ISourcePosition position, Node argsNode) { - this(position, argsNode, null); + public SuperNode(int line, Node argsNode) { + this(line, argsNode, null); } - public SuperNode(ISourcePosition position, Node argsNode, Node iterNode) { - super(position, argsNode != null && argsNode.containsVariableAssignment() || + public SuperNode(int line, Node argsNode, Node iterNode) { + super(line, argsNode != null && argsNode.containsVariableAssignment() || iterNode != null && iterNode.containsVariableAssignment()); this.argsNode = argsNode; this.iterNode = iterNode; diff --git a/core/src/main/java/org/jruby/ast/SymbolNode.java b/core/src/main/java/org/jruby/ast/SymbolNode.java index 2bda357c95d..18be8a91841 100644 --- a/core/src/main/java/org/jruby/ast/SymbolNode.java +++ b/core/src/main/java/org/jruby/ast/SymbolNode.java @@ -35,13 +35,10 @@ import java.util.List; -import org.jcodings.Encoding; - import org.jruby.RubySymbol; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a symbol (:symbol_name). @@ -49,8 +46,8 @@ public class SymbolNode extends Node implements ILiteralNode, INameNode, SideEffectFree { private final RubySymbol name; - public SymbolNode(ISourcePosition position, RubySymbol value) { - super(position, false); + public SymbolNode(int line, RubySymbol value) { + super(line, false); this.name = value; } diff --git a/core/src/main/java/org/jruby/ast/TrueNode.java b/core/src/main/java/org/jruby/ast/TrueNode.java index 53de5242450..142c3a9fb01 100644 --- a/core/src/main/java/org/jruby/ast/TrueNode.java +++ b/core/src/main/java/org/jruby/ast/TrueNode.java @@ -34,14 +34,13 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents 'true'. */ public class TrueNode extends Node implements SideEffectFree { - public TrueNode(ISourcePosition position) { - super(position, false); + public TrueNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/UndefNode.java b/core/src/main/java/org/jruby/ast/UndefNode.java index 3842a349369..c1c647cd228 100644 --- a/core/src/main/java/org/jruby/ast/UndefNode.java +++ b/core/src/main/java/org/jruby/ast/UndefNode.java @@ -34,14 +34,7 @@ import java.util.List; -import org.jruby.Ruby; -import org.jruby.RubyModule; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.runtime.Helpers; -import org.jruby.lexer.yacc.ISourcePosition; -import org.jruby.runtime.Block; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; /** * Represents an 'undef' statement. @@ -50,8 +43,8 @@ public class UndefNode extends Node { private final Node name; // name can be SymbolNode/DSymbolNode/LiteralNdoe - public UndefNode(ISourcePosition position, Node name) { - super(position, false); + public UndefNode(int line, Node name) { + super(line, false); this.name = name; } diff --git a/core/src/main/java/org/jruby/ast/UnnamedRestArgNode.java b/core/src/main/java/org/jruby/ast/UnnamedRestArgNode.java index e195f525a06..753ee1ecea7 100644 --- a/core/src/main/java/org/jruby/ast/UnnamedRestArgNode.java +++ b/core/src/main/java/org/jruby/ast/UnnamedRestArgNode.java @@ -30,14 +30,13 @@ package org.jruby.ast; import org.jruby.RubySymbol; -import org.jruby.lexer.yacc.ISourcePosition; /** * a bare '*' or nothing. Name is "" if it is '*' and null if it is nothing. */ public class UnnamedRestArgNode extends RestArgNode { - public UnnamedRestArgNode(ISourcePosition position, RubySymbol name, int index) { - super(position, name, index); + public UnnamedRestArgNode(int line, RubySymbol name, int index) { + super(line, name, index); } public boolean isStar() { diff --git a/core/src/main/java/org/jruby/ast/UntilNode.java b/core/src/main/java/org/jruby/ast/UntilNode.java index 8bfc704ec9b..a23c5549d44 100644 --- a/core/src/main/java/org/jruby/ast/UntilNode.java +++ b/core/src/main/java/org/jruby/ast/UntilNode.java @@ -34,7 +34,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents an until statement. @@ -44,18 +43,17 @@ public class UntilNode extends Node { private final Node bodyNode; private final boolean evaluateAtStart; - public UntilNode(ISourcePosition position, Node conditionNode, Node bodyNode) { - this(position, conditionNode, bodyNode, true); + public UntilNode(int line, Node conditionNode, Node bodyNode) { + this(line, conditionNode, bodyNode, true); } public NodeType getNodeType() { return NodeType.UNTILNODE; } - public UntilNode(ISourcePosition position, Node conditionNode, Node bodyNode, boolean evaluateAtStart) { - super(position, conditionNode.containsVariableAssignment() || bodyNode.containsVariableAssignment()); + public UntilNode(int line, Node conditionNode, Node bodyNode, boolean evaluateAtStart) { + super(line, conditionNode.containsVariableAssignment() || bodyNode.containsVariableAssignment()); - assert conditionNode != null : "conditionNode is not null"; assert bodyNode != null : "bodyNode is not null"; this.conditionNode = conditionNode; diff --git a/core/src/main/java/org/jruby/ast/VAliasNode.java b/core/src/main/java/org/jruby/ast/VAliasNode.java index 95ed60240bd..4f3242bf0f3 100644 --- a/core/src/main/java/org/jruby/ast/VAliasNode.java +++ b/core/src/main/java/org/jruby/ast/VAliasNode.java @@ -36,9 +36,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; -import org.jruby.util.ByteList; -import org.jruby.util.StringSupport; /** * Represents an alias of a global variable. @@ -47,8 +44,8 @@ public class VAliasNode extends Node { private final RubySymbol oldName; private final RubySymbol newName; - public VAliasNode(ISourcePosition position, RubySymbol newName, RubySymbol oldName) { - super(position, false); + public VAliasNode(int line, RubySymbol newName, RubySymbol oldName) { + super(line, false); this.oldName = oldName; this.newName = newName; } diff --git a/core/src/main/java/org/jruby/ast/VCallNode.java b/core/src/main/java/org/jruby/ast/VCallNode.java index ad9b166f312..b3aa88f87c0 100644 --- a/core/src/main/java/org/jruby/ast/VCallNode.java +++ b/core/src/main/java/org/jruby/ast/VCallNode.java @@ -38,7 +38,6 @@ import org.jruby.RubySymbol; import org.jruby.ast.types.INameNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * RubyMethod call without any arguments @@ -47,8 +46,8 @@ public class VCallNode extends Node implements INameNode { private final RubySymbol name; - public VCallNode(ISourcePosition position, RubySymbol name) { - super(position, false); + public VCallNode(int line, RubySymbol name) { + super(line, false); this.name = name; setNewline(); diff --git a/core/src/main/java/org/jruby/ast/WhenNode.java b/core/src/main/java/org/jruby/ast/WhenNode.java index 401f68814a4..77c6b52604c 100644 --- a/core/src/main/java/org/jruby/ast/WhenNode.java +++ b/core/src/main/java/org/jruby/ast/WhenNode.java @@ -34,7 +34,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a when condition @@ -44,8 +43,8 @@ public class WhenNode extends Node { protected final Node bodyNode; private final Node nextCase; - public WhenNode(ISourcePosition position, Node expressionNodes, Node bodyNode, Node nextCase) { - super(position, expressionNodes != null && expressionNodes.containsVariableAssignment() || + public WhenNode(int line, Node expressionNodes, Node bodyNode, Node nextCase) { + super(line, expressionNodes != null && expressionNodes.containsVariableAssignment() || bodyNode != null && bodyNode.containsVariableAssignment() || nextCase != null && nextCase.containsVariableAssignment()); diff --git a/core/src/main/java/org/jruby/ast/WhenOneArgNode.java b/core/src/main/java/org/jruby/ast/WhenOneArgNode.java index 99d80ab6eec..61bdd7feab6 100644 --- a/core/src/main/java/org/jruby/ast/WhenOneArgNode.java +++ b/core/src/main/java/org/jruby/ast/WhenOneArgNode.java @@ -5,14 +5,12 @@ package org.jruby.ast; -import org.jruby.lexer.yacc.ISourcePosition; - /** * * @author enebo */ public class WhenOneArgNode extends WhenNode { - public WhenOneArgNode(ISourcePosition position, Node expressionNode, Node bodyNode, Node nextCase) { - super(position, expressionNode, bodyNode, nextCase); + public WhenOneArgNode(int line, Node expressionNode, Node bodyNode, Node nextCase) { + super(line, expressionNode, bodyNode, nextCase); } } diff --git a/core/src/main/java/org/jruby/ast/WhileNode.java b/core/src/main/java/org/jruby/ast/WhileNode.java index 5f0aab320d8..a42a06abaa5 100644 --- a/core/src/main/java/org/jruby/ast/WhileNode.java +++ b/core/src/main/java/org/jruby/ast/WhileNode.java @@ -34,7 +34,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a while statement. This could be the both versions: @@ -52,15 +51,13 @@ public class WhileNode extends Node { private final Node bodyNode; private final boolean evaluateAtStart; - public WhileNode(ISourcePosition position, Node conditionNode, Node bodyNode) { - this(position, conditionNode, bodyNode, true); + public WhileNode(int line, Node conditionNode, Node bodyNode) { + this(line, conditionNode, bodyNode, true); } - public WhileNode(ISourcePosition position, Node conditionNode, Node bodyNode, - boolean evalAtStart) { - super(position, conditionNode.containsVariableAssignment() || bodyNode.containsVariableAssignment()); + public WhileNode(int line, Node conditionNode, Node bodyNode, boolean evalAtStart) { + super(line, conditionNode.containsVariableAssignment() || bodyNode.containsVariableAssignment()); - assert conditionNode != null : "conditionNode is not null"; assert bodyNode != null : "bodyNode is not null"; this.conditionNode = conditionNode; diff --git a/core/src/main/java/org/jruby/ast/XStrNode.java b/core/src/main/java/org/jruby/ast/XStrNode.java index 4951409ec53..95416b2f77e 100644 --- a/core/src/main/java/org/jruby/ast/XStrNode.java +++ b/core/src/main/java/org/jruby/ast/XStrNode.java @@ -35,7 +35,6 @@ import java.util.List; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.util.ByteList; /** @@ -45,9 +44,8 @@ public class XStrNode extends Node implements ILiteralNode { private final ByteList value; private final int coderange; - public XStrNode(ISourcePosition position, ByteList value, int coderange) { - // FIXME: Shouldn't this have codeRange like StrNode? - super(position, false); + public XStrNode(int line, ByteList value, int coderange) { + super(line, false); this.value = (value == null ? ByteList.create("") : value); this.coderange = coderange; } diff --git a/core/src/main/java/org/jruby/ast/YieldNode.java b/core/src/main/java/org/jruby/ast/YieldNode.java index 0f03c5f2423..cdde596eb2e 100644 --- a/core/src/main/java/org/jruby/ast/YieldNode.java +++ b/core/src/main/java/org/jruby/ast/YieldNode.java @@ -34,7 +34,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * Represents a yield statement. @@ -45,11 +44,11 @@ public class YieldNode extends Node { /** * Construct a new YieldNode. * - * @param position position of the node in the source + * @param line position of the node in the source * @param argsNode the arguments to the yield (null == no args) */ - public YieldNode(ISourcePosition position, Node argsNode) { - super(position, argsNode != null && argsNode.containsVariableAssignment()); + public YieldNode(int line, Node argsNode) { + super(line, argsNode != null && argsNode.containsVariableAssignment()); this.argsNode = argsNode; } diff --git a/core/src/main/java/org/jruby/ast/ZArrayNode.java b/core/src/main/java/org/jruby/ast/ZArrayNode.java index b4b3928df0a..282f57b42fb 100644 --- a/core/src/main/java/org/jruby/ast/ZArrayNode.java +++ b/core/src/main/java/org/jruby/ast/ZArrayNode.java @@ -32,10 +32,8 @@ package org.jruby.ast; -import java.util.List; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * @@ -43,8 +41,8 @@ * */ public class ZArrayNode extends ListNode implements ILiteralNode { - public ZArrayNode(ISourcePosition position) { - super(position); + public ZArrayNode(int line) { + super(line); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/ZSuperNode.java b/core/src/main/java/org/jruby/ast/ZSuperNode.java index 4b81c1e10d0..73eca3cf83c 100644 --- a/core/src/main/java/org/jruby/ast/ZSuperNode.java +++ b/core/src/main/java/org/jruby/ast/ZSuperNode.java @@ -34,7 +34,6 @@ import java.util.List; import org.jruby.ast.visitor.NodeVisitor; -import org.jruby.lexer.yacc.ISourcePosition; /** * a call to 'super' with no arguments in a method. @@ -42,8 +41,8 @@ public class ZSuperNode extends Node implements BlockAcceptingNode { private Node iterNode; - public ZSuperNode(ISourcePosition position) { - super(position, false); + public ZSuperNode(int line) { + super(line, false); } public NodeType getNodeType() { diff --git a/core/src/main/java/org/jruby/ast/visitor/AbstractNodeVisitor.java b/core/src/main/java/org/jruby/ast/visitor/AbstractNodeVisitor.java index f1454a14360..3b95c7f5996 100644 --- a/core/src/main/java/org/jruby/ast/visitor/AbstractNodeVisitor.java +++ b/core/src/main/java/org/jruby/ast/visitor/AbstractNodeVisitor.java @@ -394,6 +394,11 @@ public T visitNthRefNode(NthRefNode node) { return defaultVisit(node); } + @Override + public T visitOperatorCallNode(OperatorCallNode node) { + return defaultVisit(node); + } + @Override public T visitOpElementAsgnNode(OpElementAsgnNode node) { return defaultVisit(node); diff --git a/core/src/main/java/org/jruby/ast/visitor/NodeVisitor.java b/core/src/main/java/org/jruby/ast/visitor/NodeVisitor.java index 321f48a72ac..4d9093fa75e 100644 --- a/core/src/main/java/org/jruby/ast/visitor/NodeVisitor.java +++ b/core/src/main/java/org/jruby/ast/visitor/NodeVisitor.java @@ -109,6 +109,7 @@ public interface NodeVisitor { T visitNextNode(NextNode iVisited); T visitNilNode(NilNode iVisited); T visitNthRefNode(NthRefNode iVisited); + T visitOperatorCallNode(OperatorCallNode iVisited); T visitOpElementAsgnNode(OpElementAsgnNode iVisited); T visitOpAsgnNode(OpAsgnNode iVisited); T visitOpAsgnAndNode(OpAsgnAndNode iVisited); diff --git a/core/src/main/java/org/jruby/ast/visitor/OperatorCallNode.java b/core/src/main/java/org/jruby/ast/visitor/OperatorCallNode.java new file mode 100644 index 00000000000..a38afb9de05 --- /dev/null +++ b/core/src/main/java/org/jruby/ast/visitor/OperatorCallNode.java @@ -0,0 +1,19 @@ +package org.jruby.ast.visitor; + +import org.jruby.RubySymbol; +import org.jruby.ast.CallNode; +import org.jruby.ast.Node; + +public class OperatorCallNode extends CallNode { + public OperatorCallNode(int line, Node receiverNode, RubySymbol name, Node argsNode, Node iterNode, boolean isLazy) { + super(line, receiverNode, name, argsNode, iterNode, isLazy); + } + + /** + * Accept for the visitor pattern. + * @param iVisitor the visitor + **/ + public T accept(NodeVisitor iVisitor) { + return iVisitor.visitOperatorCallNode(this); + } +} diff --git a/core/src/main/java/org/jruby/common/IRubyWarnings.java b/core/src/main/java/org/jruby/common/IRubyWarnings.java index fff2bda5a7e..01336f8a30c 100644 --- a/core/src/main/java/org/jruby/common/IRubyWarnings.java +++ b/core/src/main/java/org/jruby/common/IRubyWarnings.java @@ -32,7 +32,6 @@ package org.jruby.common; import org.jruby.Ruby; -import org.jruby.lexer.yacc.ISourcePosition; // FIXME: Document difference between warn and warning (or rename one better) /** @@ -110,11 +109,9 @@ public String getID() { Ruby getRuntime(); boolean isVerbose(); - @Deprecated void warn(ID id, ISourcePosition position, String message); void warn(ID id, String fileName, int lineNumber, String message); void warn(ID id, String fileName, String message); void warn(ID id, String message); void warning(ID id, String message); - @Deprecated void warning(ID id, ISourcePosition position, String message); void warning(ID id, String fileName, int lineNumber, String message); } diff --git a/core/src/main/java/org/jruby/common/NullWarnings.java b/core/src/main/java/org/jruby/common/NullWarnings.java index 222001b4586..2e24bcfa123 100644 --- a/core/src/main/java/org/jruby/common/NullWarnings.java +++ b/core/src/main/java/org/jruby/common/NullWarnings.java @@ -30,7 +30,6 @@ package org.jruby.common; import org.jruby.Ruby; -import org.jruby.lexer.yacc.ISourcePosition; /** * A Warnings implementation which silently ignores everything. @@ -49,14 +48,10 @@ public org.jruby.Ruby getRuntime() { return runtime; } - @Deprecated - public void warn(ID id, ISourcePosition position, String message) {} public void warn(ID id, String fileName, int lineNumber, String message) {} public void warn(ID id, String fileName, String message) {} public void warn(ID id, String message) {} public void warning(ID id, String message) {} - @Deprecated - public void warning(ID id, ISourcePosition position, String message) {} public void warning(ID id, String fileName, int lineNumber, String message) {} @Deprecated @@ -64,11 +59,7 @@ public void warn(ID id, String message, Object... data) {} @Deprecated public void warning(ID id, String message, Object... data) {} @Deprecated - public void warn(ID id, ISourcePosition position, String message, Object... data) {} - @Deprecated public void warn(ID id, String fileName, int lineNumber, String message, Object... data) {} @Deprecated - public void warning(ID id, ISourcePosition position, String message, Object... data) {} - @Deprecated public void warning(ID id, String fileName, int lineNumber, String message, Object...data) {} } diff --git a/core/src/main/java/org/jruby/common/RubyWarnings.java b/core/src/main/java/org/jruby/common/RubyWarnings.java index ac544f61766..efe630635f6 100644 --- a/core/src/main/java/org/jruby/common/RubyWarnings.java +++ b/core/src/main/java/org/jruby/common/RubyWarnings.java @@ -1,4 +1,5 @@ -/***** BEGIN LICENSE BLOCK ***** +/* + **** BEGIN LICENSE BLOCK ***** * Version: EPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Eclipse Public @@ -35,7 +36,6 @@ import org.jruby.RubyModule; import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; -import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.runtime.JavaSites; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.backtrace.RubyStackTraceElement; @@ -77,17 +77,6 @@ public boolean isVerbose() { return runtime.isVerbose(); } - /** - * Prints a warning, unless $VERBOSE is nil. - */ - @Override - @Deprecated - public void warn(ID id, ISourcePosition position, String message) { - if (!runtime.warningsEnabled()) return; - - warn(id, position.getFile(), position.getLine(), message); - } - /** * Prints a warning, unless $VERBOSE is nil. */ @@ -95,11 +84,8 @@ public void warn(ID id, ISourcePosition position, String message) { public void warn(ID id, String fileName, int lineNumber, String message) { if (!runtime.warningsEnabled()) return; - StringBuilder buffer = new StringBuilder(100); - - buffer.append(fileName).append(':').append(lineNumber + 1).append(": "); - buffer.append("warning: ").append(message).append('\n'); - RubyString errorString = runtime.newString(buffer.toString()); + String buffer = fileName + ':' + (lineNumber + 1) + ": warning: " + message + '\n'; + RubyString errorString = runtime.newString(buffer); writeWarningDyncall(runtime.getCurrentContext(), errorString); } @@ -144,10 +130,7 @@ public void warn(ID id, String message) { public void warn(String filename, String message) { if (!runtime.warningsEnabled()) return; - StringBuilder buffer = new StringBuilder(100); - - buffer.append(filename).append(": ").append(message).append('\n'); - RubyString errorString = runtime.newString(buffer.toString()); + RubyString errorString = runtime.newString(filename + ": " + message + '\n'); writeWarningDyncall(runtime.getCurrentContext(), errorString); } @@ -194,15 +177,6 @@ private static void writeWarning(Ruby runtime, ID id, String message) { runtime.getWarnings().warning(id, file, line, message); } - /** - * Prints a warning, only in verbose mode. - */ - @Override - @Deprecated - public void warning(ID id, ISourcePosition position, String message) { - warning(id, position.getFile(), position.getLine(), message); - } - /** * Prints a warning, only in verbose mode. */ @@ -238,11 +212,8 @@ private static JavaSites.WarningSites sites(ThreadContext context) { public void warn(ID id, String fileName, String message) { if (!runtime.warningsEnabled()) return; - StringBuilder buffer = new StringBuilder(100); - - buffer.append(fileName).append(' '); - buffer.append("warning: ").append(message).append('\n'); IRubyObject errorStream = runtime.getGlobalVariables().get("$stderr"); - errorStream.callMethod(runtime.getCurrentContext(), "write", runtime.newString(buffer.toString())); + String buffer = fileName + " warning: " + message + '\n'; + errorStream.callMethod(runtime.getCurrentContext(), "write", runtime.newString(buffer)); } } diff --git a/core/src/main/java/org/jruby/embed/osgi/internal/OSGiLoadService.java b/core/src/main/java/org/jruby/embed/osgi/internal/OSGiLoadService.java index 9b7400109a2..e2baa03a834 100644 --- a/core/src/main/java/org/jruby/embed/osgi/internal/OSGiLoadService.java +++ b/core/src/main/java/org/jruby/embed/osgi/internal/OSGiLoadService.java @@ -35,25 +35,22 @@ import org.jruby.embed.osgi.utils.OSGiFileLocator; import org.jruby.platform.Platform; import org.jruby.runtime.load.Library; +import org.jruby.runtime.load.LibrarySearcher; import org.jruby.runtime.load.LoadService; import org.jruby.runtime.load.LoadServiceResource; import org.osgi.framework.Bundle; /** * @author hmalphettes - * + * * Load scripts and java classes directly from the OSGi bundles. * bundle:/symbolic.name/ */ public class OSGiLoadService extends LoadService { - + public static final String OSGI_BUNDLE_CLASSPATH_SCHEME = "osgibundle:/"; - - public static final LoadServiceCreator OSGI_DEFAULT = new LoadServiceCreator() { - public LoadService create(Ruby runtime) { - return new OSGiLoadService19(runtime); - } - }; + + public static final LoadServiceCreator OSGI_DEFAULT = runtime -> new OSGiLoadService(runtime); /** * Default constructor @@ -63,18 +60,37 @@ public LoadService create(Ruby runtime) { public OSGiLoadService(Ruby runtime) { super(runtime); } - - protected Library findLibraryBySearchState(SearchState state) { - Library library = super.findLibraryBySearchState(state); - if (library == null){ - library = findLibraryWithClassloaders(state, state.searchFile, state.suffixType); - if (library != null) { - state.library = library; - } + +// @Override + protected LibrarySearcher.FoundLibrary searchForRequire(String searchFile) { + String[] fileHolder = {searchFile}; + SuffixType suffixType = LibrarySearcher.getSuffixTypeForRequire(fileHolder); + String baseName = fileHolder[0]; + + LibrarySearcher.FoundLibrary[] library = {null}; + char found = librarySearcher.findLibraryForRequire(baseName, library); + if (found != 0) { + return library[0]; } - return library; + + return findLibraryWithClassloaders(searchFile, suffixType); } - + + @Override + protected LibrarySearcher.FoundLibrary searchForLoad(String searchFile) { + String[] fileHolder = {searchFile}; + SuffixType suffixType = LibrarySearcher.getSuffixTypeForLoad(fileHolder); + String baseName = fileHolder[0]; + + LibrarySearcher.FoundLibrary[] library = {null}; + char found = librarySearcher.findLibraryForRequire(baseName, library); + if (found != 0) { + return library[0]; + } + + return findLibraryWithClassloaders(searchFile, suffixType); + } + /** * Support for 'bundle:/' to look for libraries in osgi bundles * or classes or ruby files. @@ -110,17 +126,16 @@ protected LoadServiceResource findFileInClasspath(String name) { } return super.findFileInClasspath(name); } - + /** * Support for 'bundle:/' to look for libraries in osgi bundles. */ @Override - @Deprecated - protected Library createLibrary(SearchState state, LoadServiceResource resource) { + protected LibrarySearcher.FoundLibrary createLibrary(String baseName, String loadName, LoadServiceResource resource) { if (resource == null) { return null; } - String file = state.loadName; + String file = loadName; if (file.startsWith(OSGI_BUNDLE_CLASSPATH_SCHEME)) { file = cleanupFindName(file); StringTokenizer tokenizer = new StringTokenizer(file, "/", false); @@ -128,10 +143,10 @@ protected Library createLibrary(SearchState state, LoadServiceResource resource) String symname = tokenizer.nextToken(); Bundle bundle = OSGiFileLocator.getBundle(symname); if (bundle != null) { - return new OSGiBundleLibrary(bundle); + return new LibrarySearcher.FoundLibrary(baseName, loadName, new OSGiBundleLibrary(bundle)); } } - return super.createLibrary(state, resource); + return new LibrarySearcher.FoundLibrary(baseName, loadName, super.createLibrary(baseName, loadName, resource)); } /** @@ -149,12 +164,6 @@ private String cleanupFindName(String name) { } } -} -class OSGiLoadService19 extends OSGiLoadService { - public OSGiLoadService19(Ruby runtime) { - super(runtime); - } - @Override protected String resolveLoadName(LoadServiceResource foundResource, String previousPath) { String path = foundResource.getAbsolutePath(); @@ -164,4 +173,37 @@ protected String resolveLoadName(LoadServiceResource foundResource, String previ return path; } + @Override + @Deprecated + protected Library findLibraryBySearchState(SearchState state) { + Library library = super.findLibraryBySearchState(state); + if (library == null){ + library = findLibraryWithClassloaders(state, state.searchFile, state.suffixType); + if (library != null) { + state.library = library; + } + } + return library; + } + + @Override + @Deprecated + protected Library createLibrary(SearchState state, LoadServiceResource resource) { + if (resource == null) { + return null; + } + String file = state.loadName; + if (file.startsWith(OSGI_BUNDLE_CLASSPATH_SCHEME)) { + file = cleanupFindName(file); + StringTokenizer tokenizer = new StringTokenizer(file, "/", false); + tokenizer.nextToken(); + String symname = tokenizer.nextToken(); + Bundle bundle = OSGiFileLocator.getBundle(symname); + if (bundle != null) { + return new OSGiBundleLibrary(bundle); + } + } + return super.createLibrary(state, resource); + } + } diff --git a/core/src/main/java/org/jruby/ext/date/RubyDate.java b/core/src/main/java/org/jruby/ext/date/RubyDate.java index f833af1cf95..67982d72d37 100644 --- a/core/src/main/java/org/jruby/ext/date/RubyDate.java +++ b/core/src/main/java/org/jruby/ext/date/RubyDate.java @@ -1399,7 +1399,7 @@ public IRubyObject marshal_dump(ThreadContext context) { final Ruby runtime = context.runtime; return context.runtime.newArrayNoCopy(new IRubyObject[] { ajd(context), - RubyFixnum.newFixnum(runtime, off), + RubyRational.newRationalCanonicalize(context, off, DAY_IN_SECONDS), RubyFixnum.newFixnum(runtime, start) }); } diff --git a/core/src/main/java/org/jruby/ext/ripper/RipperParser.java b/core/src/main/java/org/jruby/ext/ripper/RipperParser.java index a94bbb3a7c3..5c852a8f888 100644 --- a/core/src/main/java/org/jruby/ext/ripper/RipperParser.java +++ b/core/src/main/java/org/jruby/ext/ripper/RipperParser.java @@ -748,33 +748,33 @@ public RipperParser(ThreadContext context, IRubyObject ripper, LexerSource sourc null,null,null,null,null,null,null,null,null,null,null,null,null,null, null,null,null,null,null,null,null,null,null,null,null,null,null,null, null,null,null,null,null,null,null,null,null,null,null,null,null, - "keyword_class","keyword_module","keyword_def","keyword_undef", - "keyword_begin","keyword_rescue","keyword_ensure","keyword_end", - "keyword_if","keyword_unless","keyword_then","keyword_elsif", - "keyword_else","keyword_case","keyword_when","keyword_while", - "keyword_until","keyword_for","keyword_break","keyword_next", - "keyword_redo","keyword_retry","keyword_in","keyword_do", - "keyword_do_cond","keyword_do_block","keyword_return","keyword_yield", - "keyword_super","keyword_self","keyword_nil","keyword_true", - "keyword_false","keyword_and","keyword_or","keyword_not", - "modifier_if","modifier_unless","modifier_while","modifier_until", - "modifier_rescue","keyword_alias","keyword_defined","keyword_BEGIN", - "keyword_END","keyword__LINE__","keyword__FILE__", - "keyword__ENCODING__","keyword_do_lambda","tIDENTIFIER","tFID", +"class","module","def","undef", +"begin","rescue","ensure","end", +"if","unless","then","elsif", +"else","case","when","while", +"until","for","break","next", +"redo","retry","in","do", +"do (for condition)","do (for block)","return","yield", +"super","self","nil","true", +"false","and","or","not", +"if (modifier)","unless (modifier)","while (modifier)","until (modifier)", +"rescue (modifier)","alias","defined","BEGIN", +"END","__LINE__","__FILE__", +"__ENCODING__","do (for lambda)","tIDENTIFIER","tFID", "tGVAR","tIVAR","tCONSTANT","tCVAR","tLABEL","tCHAR","unary+", -"unary-","tUMINUS_NUM","'**'","'<=>'","'=='","'==='","'!='","'>='", -"'<='","'&&'","'||'","'=~'","'!~'","'.'","'..'","'...'", -"'[]'","'[]='","'<<'","'>>'","'&.'","'::'","':: at EXPR_BEG'", - "tOP_ASGN","'=>'","'('","'( arg'","')'","'['", -"'{'","'{ arg'","'['","'[ args'","'*'","'*'","'&'", -"'&'","'~'","'%'","'/'","'+'","'-'","'<'","'>'", -"'|'","'!'","'^'","'{'","'}'","'`'","':'", +"unary-","tUMINUS_NUM","**","<=>","==","===","!=",">=", +"<=","&&","||","=~","!~","'.'","..","...", +"[]","[]=","<<",">>","&.","::",":: at EXPR_BEG", + "tOP_ASGN","=>","'('","'('","')'","( arg", +"'['","']'","'{'","{ arg","'*'","'*'","'&'", +"'&'","'`'","'%'","'/'","'+'","'-'","'<'","'>'", +"'|'","'!'","'^'","'{'","'}'","'`'","tSYMBEG", "tSTRING_BEG","tXSTRING_BEG","tREGEXP_BEG","tWORDS_BEG","tQWORDS_BEG", - "tSTRING_DBEG","tSTRING_DVAR","tSTRING_END","'->'","tLAMBEG", + "tSTRING_DBEG","tSTRING_DVAR","tSTRING_END","->","tLAMBEG", "tNTH_REF","tBACK_REF","tSTRING_CONTENT","tINTEGER","tIMAGINARY", "tFLOAT","tRATIONAL","tREGEXP_END","tIGNORED_NL","tCOMMENT", "tEMBDOC_BEG","tEMBDOC","tEMBDOC_END","tSP","tHEREDOC_BEG", - "tHEREDOC_END","tSYMBOLS_BEG","tQSYMBOLS_BEG","'**'","tSTRING_DEND", + "tHEREDOC_END","tSYMBOLS_BEG","tQSYMBOLS_BEG","tDSTAR","tSTRING_DEND", "tLABEL_END","tLOWEST","k__END__", }; @@ -3236,7 +3236,8 @@ public Object yyparse (RipperLexer yyLex) throws java.io.IOException { }; states[352] = new RipperParserState() { @Override public Object execute(RipperParser p, Object yyVal, Object[] yyVals, int yyTop) { - yyVal = Integer.valueOf((p.isInClass() ? 2 : 0) & (p.isInDef() ? 1 : 0)); + yyVal = new Integer((p.isInClass() ? 0b10 : 0) | + (p.isInDef() ? 0b01 : 0)); p.setInDef(false); p.setIsInClass(false); p.pushLocalScope(); @@ -3248,8 +3249,8 @@ public Object yyparse (RipperLexer yyLex) throws java.io.IOException { yyVal = p.dispatch("on_sclass", ((IRubyObject)yyVals[-4+yyTop]), ((IRubyObject)yyVals[-1+yyTop])); p.popCurrentScope(); - p.setInDef(((((Integer)yyVals[-3+yyTop]).intValue()) & 1) != 0); - p.setIsInClass(((((Integer)yyVals[-3+yyTop]).intValue()) & 2) != 0); + p.setInDef(((((Integer)yyVals[-3+yyTop]).intValue()) & 0b01) != 0); + p.setIsInClass(((((Integer)yyVals[-3+yyTop]).intValue()) & 0b10) != 0); return yyVal; } }; @@ -4862,6 +4863,6 @@ public Object yyparse (RipperLexer yyLex) throws java.io.IOException { } }; } - // line 2198 "RipperParser.y" + // line 2250 "RipperParser.y" } - // line 9835 "-" + // line 9836 "-" diff --git a/core/src/main/java/org/jruby/ext/ripper/RipperParser.y b/core/src/main/java/org/jruby/ext/ripper/RipperParser.y index e7a8a11f842..d5eab010d13 100644 --- a/core/src/main/java/org/jruby/ext/ripper/RipperParser.y +++ b/core/src/main/java/org/jruby/ext/ripper/RipperParser.y @@ -48,75 +48,126 @@ public class RipperParser extends RipperParserBase { } %} -%token keyword_class keyword_module keyword_def keyword_undef - keyword_begin keyword_rescue keyword_ensure keyword_end keyword_if - keyword_unless keyword_then keyword_elsif keyword_else keyword_case - keyword_when keyword_while keyword_until keyword_for keyword_break - keyword_next keyword_redo keyword_retry keyword_in keyword_do keyword_do_cond - keyword_do_block keyword_return keyword_yield keyword_super keyword_self - keyword_nil keyword_true keyword_false keyword_and keyword_or keyword_not - modifier_if modifier_unless modifier_while modifier_until modifier_rescue - keyword_alias keyword_defined keyword_BEGIN keyword_END keyword__LINE__ - keyword__FILE__ keyword__ENCODING__ keyword_do_lambda - -%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL +%token keyword_class /* {{class}} */ +%token keyword_module /* {{module}} */ +%token keyword_def /* {{def}} */ +%token keyword_undef /* {{undef}} */ +%token keyword_begin /* {{begin}} */ +%token keyword_rescue /* {{rescue}} */ +%token keyword_ensure /* {{ensure}} */ +%token keyword_end /* {{end}} */ +%token keyword_if /* {{if}} */ +%token keyword_unless /* {{unless}} */ +%token keyword_then /* {{then}} */ +%token keyword_elsif /* {{elsif}} */ +%token keyword_else /* {{else}} */ +%token keyword_case /* {{case}} */ +%token keyword_when /* {{when}} */ +%token keyword_while /* {{while}} */ +%token keyword_until /* {{until}} */ +%token keyword_for /* {{for}} */ +%token keyword_break /* {{break}} */ +%token keyword_next /* {{next}} */ +%token keyword_redo /* {{redo}} */ +%token keyword_retry /* {{retry}} */ +%token keyword_in /* {{in}} */ +%token keyword_do /* {{do}} */ +%token keyword_do_cond /* {{do (for condition)}} */ +%token keyword_do_block /* {{do (for block)}} */ +%token keyword_return /* {{return}} */ +%token keyword_yield /* {{yield}} */ +%token keyword_super /* {{super}} */ +%token keyword_self /* {{self}} */ +%token keyword_nil /* {{nil}} */ +%token keyword_true /* {{true}} */ +%token keyword_false /* {{false}} */ +%token keyword_and /* {{and}} */ +%token keyword_or /* {{or}} */ +%token keyword_not /* {{not}} */ +%token modifier_if /* {{if (modifier)}} */ +%token modifier_unless /* {{unless (modifier)}} */ +%token modifier_while /* {{while (modifier)}} */ +%token modifier_until /* {{until (modifier)}} */ +%token modifier_rescue /* {{rescue (modifier)}} */ +%token keyword_alias /* {{alias}} */ +%token keyword_defined /* {{defined}} */ +%token keyword_BEGIN /* {{BEGIN}} */ +%token keyword_END /* {{END}} */ +%token keyword__LINE__ /* {{__LINE__}} */ +%token keyword__FILE__ /* {{__FILE__}} */ +%token keyword__ENCODING__ /* {{__ENCODING__}} */ +%token keyword_do_lambda /* {{do (for lambda)}} */ +%token tIDENTIFIER +%token tFID +%token tGVAR +%token tIVAR +%token tCONSTANT +%token tCVAR +%token tLABEL %token tCHAR -%type sym symbol operation operation2 operation3 op fname cname -%type f_norm_arg restarg_mark -%type dot_or_colon blkarg_mark -%token tUPLUS /* unary+ */ -%token tUMINUS /* unary- */ -%token tUMINUS_NUM /* unary- */ -%token tPOW /* ** */ -%token tCMP /* <=> */ -%token tEQ /* == */ -%token tEQQ /* === */ -%token tNEQ /* != */ -%token tGEQ /* >= */ -%token tLEQ /* <= */ -%token tANDOP tOROP /* && and || */ -%token tMATCH tNMATCH /* =~ and !~ */ -%token tDOT /* Is just '.' in ruby and not a token */ -%token tDOT2 tDOT3 /* .. and ... */ -%token tAREF tASET /* [] and []= */ -%token tLSHFT tRSHFT /* << and >> */ -%token tANDDOT /* &. */ -%token tCOLON2 /* :: */ -%token tCOLON3 /* :: at EXPR_BEG */ -%token tOP_ASGN /* +=, -= etc. */ -%token tASSOC /* => */ -%token tLPAREN /* ( */ -%token tLPAREN2 /* ( Is just '(' in ruby and not a token */ -%token tRPAREN /* ) */ -%token tLPAREN_ARG /* ( */ -%token tLBRACK /* [ */ -%token tRBRACK /* ] */ -%token tLBRACE /* { */ -%token tLBRACE_ARG /* { */ -%token tSTAR /* * */ -%token tSTAR2 /* * Is just '*' in ruby and not a token */ -%token tAMPER /* & */ -%token tAMPER2 /* & Is just '&' in ruby and not a token */ -%token tTILDE /* ` is just '`' in ruby and not a token */ -%token tPERCENT /* % is just '%' in ruby and not a token */ -%token tDIVIDE /* / is just '/' in ruby and not a token */ -%token tPLUS /* + is just '+' in ruby and not a token */ -%token tMINUS /* - is just '-' in ruby and not a token */ -%token tLT /* < is just '<' in ruby and not a token */ -%token tGT /* > is just '>' in ruby and not a token */ -%token tPIPE /* | is just '|' in ruby and not a token */ -%token tBANG /* ! is just '!' in ruby and not a token */ -%token tCARET /* ^ is just '^' in ruby and not a token */ -%token tLCURLY /* { is just '{' in ruby and not a token */ -%token tRCURLY /* } is just '}' in ruby and not a token */ -%token tBACK_REF2 /* { is just '`' in ruby and not a token */ +%token tUPLUS /* {{unary+}} */ +%token tUMINUS /* {{unary-}} */ +%token tUMINUS_NUM +%token tPOW /* {{**}} */ +%token tCMP /* {{<=>}} */ +%token tEQ /* {{==}} */ +%token tEQQ /* {{===}} */ +%token tNEQ /* {{!=}} */ +%token tGEQ /* {{>=}} */ +%token tLEQ /* {{<=}} */ +%token tANDOP /* {{&&}}*/ +%token tOROP /* {{||}} */ +%token tMATCH /* {{=~}} */ +%token tNMATCH /* {{!~}} */ +%token tDOT /* {{.}} - '.' in ruby and not a token */ +%token tDOT2 /* {{..}} */ +%token tDOT3 /* {{...}} */ +%token tAREF /* {{[]}} */ +%token tASET /* {{[]=}} */ +%token tLSHFT /* {{<<}} */ +%token tRSHFT /* {{>>}} */ +%token tANDDOT /* {{&.}} */ +%token tCOLON2 /* {{::}} */ +%token tCOLON3 /* {{:: at EXPR_BEG}} */ +%token tOP_ASGN /* +=, -= etc. */ +%token tASSOC /* {{=>}} */ +%token tLPAREN /* {{(}} */ +%token tLPAREN2 /* {{(}} - '(' in ruby and not a token */ +%token tRPAREN /* {{)}} */ +%token tLPAREN_ARG /* {{( arg}} */ +%token tLBRACK /* {{[}} */ +%token tRBRACK /* {{]}} */ +%token tLBRACE /* {{{}} */ +%token tLBRACE_ARG /* {{{ arg}} */ +%token tSTAR /* {{*}} */ +%token tSTAR2 /* {{*}} - '*' in ruby and not a token */ +%token tAMPER /* {{&}} */ +%token tAMPER2 /* {{&}} - '&' in ruby and not a token */ +%token tTILDE /* {{`}} - '`' in ruby and not a token */ +%token tPERCENT /* {{%}} - '%' in ruby and not a token */ +%token tDIVIDE /* {{/}} - '/' in ruby and not a token */ +%token tPLUS /* {{+}} - '+' in ruby and not a token */ +%token tMINUS /* {{-}} - '-' in ruby and not a token */ +%token tLT /* {{<}} - '<' in ruby and not a token */ +%token tGT /* {{>}} - '>' in ruby and not a token */ +%token tPIPE /* {{|}} - '|' in ruby and not a token */ +%token tBANG /* {{!}} - '!' in ruby and not a token */ +%token tCARET /* {{^}} - '^' in ruby and not a token */ +%token tLCURLY /* {{{}} - '{' in ruby and not a token */ +%token tRCURLY /* {{}}} - '}' in ruby and not a token */ +%token tBACK_REF2 /* {{`}} - '`' in ruby and not a token */ %token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG %token tSTRING_DBEG tSTRING_DVAR tSTRING_END -%token tLAMBDA tLAMBEG +%token tLAMBDA /* {{->}} */ +%token tLAMBEG %token tNTH_REF tBACK_REF tSTRING_CONTENT tINTEGER tIMAGINARY %token tFLOAT %token tRATIONAL %token tREGEXP_END + +%type sym symbol operation operation2 operation3 op fname cname +%type f_norm_arg restarg_mark +%type dot_or_colon blkarg_mark /* RIPPER-ONY TOKENS { */ %token tIGNORED_NL tCOMMENT tEMBDOC_BEG tEMBDOC tEMBDOC_END %token tSP tHEREDOC_BEG tHEREDOC_END @@ -1184,7 +1235,8 @@ primary : literal p.setIsInClass($4.booleanValue()); } | keyword_class tLSHFT expr { - $$ = Integer.valueOf((p.isInClass() ? 2 : 0) & (p.isInDef() ? 1 : 0)); + $$ = new Integer((p.isInClass() ? 0b10 : 0) | + (p.isInDef() ? 0b01 : 0)); p.setInDef(false); p.setIsInClass(false); p.pushLocalScope(); @@ -1192,8 +1244,8 @@ primary : literal $$ = p.dispatch("on_sclass", $3, $6); p.popCurrentScope(); - p.setInDef((($4.intValue()) & 1) != 0); - p.setIsInClass((($4.intValue()) & 2) != 0); + p.setInDef((($4.intValue()) & 0b01) != 0); + p.setIsInClass((($4.intValue()) & 0b10) != 0); } | keyword_module cpath { if (p.isInDef()) { diff --git a/core/src/main/java/org/jruby/ext/ripper/RipperParserBase.java b/core/src/main/java/org/jruby/ext/ripper/RipperParserBase.java index 1bbd0098da2..b3c9c30ce0f 100644 --- a/core/src/main/java/org/jruby/ext/ripper/RipperParserBase.java +++ b/core/src/main/java/org/jruby/ext/ripper/RipperParserBase.java @@ -119,7 +119,7 @@ public IRubyObject assignableConstant(IRubyObject value) { public IRubyObject assignableIdentifier(IRubyObject value) { String ident = lexer.getIdent().intern(); - getCurrentScope().assign(lexer.getPosition(), context.runtime.newSymbol(lexer.getIdent()), null); + getCurrentScope().assign(lexer.getRubySourceline(), context.runtime.newSymbol(lexer.getIdent()), null); return value; } diff --git a/core/src/main/java/org/jruby/ir/IRBuilder.java b/core/src/main/java/org/jruby/ir/IRBuilder.java index 269657338ac..9d3763fa676 100644 --- a/core/src/main/java/org/jruby/ir/IRBuilder.java +++ b/core/src/main/java/org/jruby/ir/IRBuilder.java @@ -1,10 +1,14 @@ package org.jruby.ir; import org.jruby.Ruby; +import org.jruby.RubyBignum; +import org.jruby.RubyComplex; import org.jruby.RubyInstanceConfig; +import org.jruby.RubyRational; import org.jruby.RubySymbol; import org.jruby.ast.*; import org.jruby.ast.types.INameNode; +import org.jruby.common.IRubyWarnings; import org.jruby.compiler.NotCompilableException; import org.jruby.ext.coverage.CoverageData; import org.jruby.parser.StaticScope; @@ -22,9 +26,9 @@ import org.jruby.runtime.Helpers; import org.jruby.runtime.RubyEvent; import org.jruby.runtime.Signature; +import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; import org.jruby.util.CommonByteLists; -import org.jruby.util.ConvertBytes; import org.jruby.util.DefinedMessage; import org.jruby.util.KeyValuePair; @@ -492,7 +496,7 @@ private Operand buildOperand(Variable result, Node node) throws NotCompilableExc case RESCUEBODYNODE: throw new NotCompilableException("rescue body is handled by rescue compilation at: " + scope.getFile() + ":" + node.getLine()); case RESCUENODE: return buildRescue((RescueNode) node); - case RETRYNODE: return buildRetry(); + case RETRYNODE: return buildRetry((RetryNode) node); case RETURNNODE: return buildReturn((ReturnNode) node); case ROOTNODE: throw new NotCompilableException("Use buildRoot(); Root node at: " + scope.getFile() + ":" + node.getLine()); @@ -1204,24 +1208,26 @@ private HashNode getPossibleKeywordArgument(Node argsNode) { } public Operand buildCase(CaseNode caseNode) { - // scan all cases to see if we have a homogeneous literal case/when - NodeType seenType = null; - for (Node aCase : caseNode.getCases().children()) { - WhenNode whenNode = (WhenNode)aCase; - NodeType exprNodeType = whenNode.getExpressionNodes().getNodeType(); - - if (seenType == null) { - seenType = exprNodeType; - } else if (seenType != exprNodeType) { - seenType = null; - break; + if (caseNode.getCaseNode() != null) { + // scan all cases to see if we have a homogeneous literal case/when + NodeType seenType = null; + for (Node aCase : caseNode.getCases().children()) { + WhenNode whenNode = (WhenNode) aCase; + NodeType exprNodeType = whenNode.getExpressionNodes().getNodeType(); + + if (seenType == null) { + seenType = exprNodeType; + } else if (seenType != exprNodeType) { + seenType = null; + break; + } } - } - if (seenType != null) { - switch (seenType) { - case FIXNUMNODE: - return buildFixnumCase(caseNode); + if (seenType != null) { + switch (seenType) { + case FIXNUMNODE: + return buildFixnumCase(caseNode); + } } } @@ -1242,6 +1248,7 @@ public Operand buildCase(CaseNode caseNode) { List + + rubygems + bundler + 1.17.3 + gem + provided + + + jar-dependencies + rubygems + + + rubygems cmath @@ -151,7 +164,7 @@ DO NOT MODIFIY - GENERATED CODE rubygems jruby-openssl - 0.10.4 + 0.10.5 gem provided @@ -255,7 +268,7 @@ DO NOT MODIFIY - GENERATED CODE rubygems racc - 1.5.0 + 1.5.1 gem provided @@ -385,7 +398,7 @@ DO NOT MODIFIY - GENERATED CODE rubygems webrick - 1.6.0 + 1.6.1 gem provided @@ -398,7 +411,7 @@ DO NOT MODIFIY - GENERATED CODE rubygems did_you_mean - 1.2.0 + 1.2.1 gem provided @@ -506,6 +519,9 @@ DO NOT MODIFIY - GENERATED CODE ${jruby.complete.gems} ${gem.home} + cache/bundler*1.17.3.gem + gems/bundler*1.17.3/** + specifications/bundler*1.17.3.gemspec cache/cmath*1.0.0.gem gems/cmath*1.0.0/** specifications/cmath*1.0.0.gemspec @@ -533,9 +549,9 @@ DO NOT MODIFIY - GENERATED CODE cache/jruby-readline*1.3.7.gem gems/jruby-readline*1.3.7/** specifications/jruby-readline*1.3.7.gemspec - cache/jruby-openssl*0.10.4.gem - gems/jruby-openssl*0.10.4/** - specifications/jruby-openssl*0.10.4.gemspec + cache/jruby-openssl*0.10.5.gem + gems/jruby-openssl*0.10.5/** + specifications/jruby-openssl*0.10.5.gemspec cache/json*${json.version}.gem gems/json*${json.version}/** specifications/json*${json.version}.gemspec @@ -557,9 +573,9 @@ DO NOT MODIFIY - GENERATED CODE cache/psych*3.2.0.gem gems/psych*3.2.0/** specifications/psych*3.2.0.gemspec - cache/racc*1.5.0.gem - gems/racc*1.5.0/** - specifications/racc*1.5.0.gemspec + cache/racc*1.5.1.gem + gems/racc*1.5.1/** + specifications/racc*1.5.1.gemspec cache/rake-ant*1.0.4.gem gems/rake-ant*1.0.4/** specifications/rake-ant*1.0.4.gemspec @@ -587,12 +603,12 @@ DO NOT MODIFIY - GENERATED CODE cache/tracer*0.1.0.gem gems/tracer*0.1.0/** specifications/tracer*0.1.0.gemspec - cache/webrick*1.6.0.gem - gems/webrick*1.6.0/** - specifications/webrick*1.6.0.gemspec - cache/did_you_mean*1.2.0.gem - gems/did_you_mean*1.2.0/** - specifications/did_you_mean*1.2.0.gemspec + cache/webrick*1.6.1.gem + gems/webrick*1.6.1/** + specifications/webrick*1.6.1.gemspec + cache/did_you_mean*1.2.1.gem + gems/did_you_mean*1.2.1/** + specifications/did_you_mean*1.2.1.gemspec cache/minitest*${minitest.version}.gem gems/minitest*${minitest.version}/** specifications/minitest*${minitest.version}.gemspec diff --git a/lib/ruby/stdlib/bundler.rb b/lib/ruby/stdlib/bundler.rb deleted file mode 100644 index 1cb3b4fb21e..00000000000 --- a/lib/ruby/stdlib/bundler.rb +++ /dev/null @@ -1,567 +0,0 @@ -# frozen_string_literal: true - -require "bundler/compatibility_guard" - -require "bundler/vendored_fileutils" -require "pathname" -require "rbconfig" -require "thread" - -require "bundler/errors" -require "bundler/environment_preserver" -require "bundler/plugin" -require "bundler/rubygems_ext" -require "bundler/rubygems_integration" -require "bundler/version" -require "bundler/constants" -require "bundler/current_ruby" -require "bundler/build_metadata" - -module Bundler - environment_preserver = EnvironmentPreserver.new(ENV, EnvironmentPreserver::BUNDLER_KEYS) - ORIGINAL_ENV = environment_preserver.restore - ENV.replace(environment_preserver.backup) - SUDO_MUTEX = Mutex.new - - autoload :Definition, "bundler/definition" - autoload :Dependency, "bundler/dependency" - autoload :DepProxy, "bundler/dep_proxy" - autoload :Deprecate, "bundler/deprecate" - autoload :Dsl, "bundler/dsl" - autoload :EndpointSpecification, "bundler/endpoint_specification" - autoload :Env, "bundler/env" - autoload :Fetcher, "bundler/fetcher" - autoload :FeatureFlag, "bundler/feature_flag" - autoload :GemHelper, "bundler/gem_helper" - autoload :GemHelpers, "bundler/gem_helpers" - autoload :GemRemoteFetcher, "bundler/gem_remote_fetcher" - autoload :GemVersionPromoter, "bundler/gem_version_promoter" - autoload :Graph, "bundler/graph" - autoload :Index, "bundler/index" - autoload :Injector, "bundler/injector" - autoload :Installer, "bundler/installer" - autoload :LazySpecification, "bundler/lazy_specification" - autoload :LockfileParser, "bundler/lockfile_parser" - autoload :MatchPlatform, "bundler/match_platform" - autoload :ProcessLock, "bundler/process_lock" - autoload :RemoteSpecification, "bundler/remote_specification" - autoload :Resolver, "bundler/resolver" - autoload :Retry, "bundler/retry" - autoload :RubyDsl, "bundler/ruby_dsl" - autoload :RubyGemsGemInstaller, "bundler/rubygems_gem_installer" - autoload :RubyVersion, "bundler/ruby_version" - autoload :Runtime, "bundler/runtime" - autoload :Settings, "bundler/settings" - autoload :SharedHelpers, "bundler/shared_helpers" - autoload :Source, "bundler/source" - autoload :SourceList, "bundler/source_list" - autoload :SpecSet, "bundler/spec_set" - autoload :StubSpecification, "bundler/stub_specification" - autoload :UI, "bundler/ui" - autoload :URICredentialsFilter, "bundler/uri_credentials_filter" - autoload :VersionRanges, "bundler/version_ranges" - - class << self - def configure - @configured ||= configure_gem_home_and_path - end - - def ui - (defined?(@ui) && @ui) || (self.ui = UI::Silent.new) - end - - def ui=(ui) - Bundler.rubygems.ui = ui ? UI::RGProxy.new(ui) : nil - @ui = ui - end - - # Returns absolute path of where gems are installed on the filesystem. - def bundle_path - @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) - end - - def configured_bundle_path - @configured_bundle_path ||= settings.path.tap(&:validate!) - end - - # Returns absolute location of where binstubs are installed to. - def bin_path - @bin_path ||= begin - path = settings[:bin] || "bin" - path = Pathname.new(path).expand_path(root).expand_path - SharedHelpers.filesystem_access(path) {|p| FileUtils.mkdir_p(p) } - path - end - end - - def setup(*groups) - # Return if all groups are already loaded - return @setup if defined?(@setup) && @setup - - definition.validate_runtime! - - SharedHelpers.print_major_deprecations! - - if groups.empty? - # Load all groups, but only once - @setup = load.setup - else - load.setup(*groups) - end - end - - def require(*groups) - setup(*groups).require(*groups) - end - - def load - @load ||= Runtime.new(root, definition) - end - - def environment - SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load" - load - end - - # Returns an instance of Bundler::Definition for given Gemfile and lockfile - # - # @param unlock [Hash, Boolean, nil] Gems that have been requested - # to be updated or true if all gems should be updated - # @return [Bundler::Definition] - def definition(unlock = nil) - @definition = nil if unlock - @definition ||= begin - configure - Definition.build(default_gemfile, default_lockfile, unlock) - end - end - - def frozen_bundle? - frozen = settings[:deployment] - frozen ||= settings[:frozen] unless feature_flag.deployment_means_frozen? - frozen - end - - def locked_gems - @locked_gems ||= - if defined?(@definition) && @definition - definition.locked_gems - elsif Bundler.default_lockfile.file? - lock = Bundler.read_file(Bundler.default_lockfile) - LockfileParser.new(lock) - end - end - - def ruby_scope - "#{Bundler.rubygems.ruby_engine}/#{Bundler.rubygems.config_map[:ruby_version]}" - end - - def user_home - @user_home ||= begin - home = Bundler.rubygems.user_home - bundle_home = home ? File.join(home, ".bundle") : nil - - warning = if home.nil? - "Your home directory is not set." - elsif !File.directory?(home) - "`#{home}` is not a directory." - elsif !File.writable?(home) && (!File.directory?(bundle_home) || !File.writable?(bundle_home)) - "`#{home}` is not writable." - end - - if warning - Kernel.send(:require, "etc") - user_home = tmp_home_path(Etc.getlogin, warning) - Bundler.ui.warn "#{warning}\nBundler will use `#{user_home}' as your home directory temporarily.\n" - user_home - else - Pathname.new(home) - end - end - end - - def tmp_home_path(login, warning) - login ||= "unknown" - Kernel.send(:require, "tmpdir") - path = Pathname.new(Dir.tmpdir).join("bundler", "home") - SharedHelpers.filesystem_access(path) do |tmp_home_path| - unless tmp_home_path.exist? - tmp_home_path.mkpath - tmp_home_path.chmod(0o777) - end - tmp_home_path.join(login).tap(&:mkpath) - end - rescue RuntimeError => e - raise e.exception("#{warning}\nBundler also failed to create a temporary home directory at `#{path}':\n#{e}") - end - - def user_bundle_path(dir = "home") - env_var, fallback = case dir - when "home" - ["BUNDLE_USER_HOME", Pathname.new(user_home).join(".bundle")] - when "cache" - ["BUNDLE_USER_CACHE", user_bundle_path.join("cache")] - when "config" - ["BUNDLE_USER_CONFIG", user_bundle_path.join("config")] - when "plugin" - ["BUNDLE_USER_PLUGIN", user_bundle_path.join("plugin")] - else - raise BundlerError, "Unknown user path requested: #{dir}" - end - # `fallback` will already be a Pathname, but Pathname.new() is - # idempotent so it's OK - Pathname.new(ENV.fetch(env_var, fallback)) - end - - def user_cache - user_bundle_path("cache") - end - - def home - bundle_path.join("bundler") - end - - def install_path - home.join("gems") - end - - def specs_path - bundle_path.join("specifications") - end - - def root - @root ||= begin - SharedHelpers.root - rescue GemfileNotFound - bundle_dir = default_bundle_dir - raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir - Pathname.new(File.expand_path("..", bundle_dir)) - end - end - - def app_config_path - if app_config = ENV["BUNDLE_APP_CONFIG"] - Pathname.new(app_config).expand_path(root) - else - root.join(".bundle") - end - end - - def app_cache(custom_path = nil) - path = custom_path || root - Pathname.new(path).join(settings.app_cache_path) - end - - def tmp(name = Process.pid.to_s) - Kernel.send(:require, "tmpdir") - Pathname.new(Dir.mktmpdir(["bundler", name])) - end - - def rm_rf(path) - FileUtils.remove_entry_secure(path) if path && File.exist?(path) - rescue ArgumentError - message = < e - raise MarshalError, "#{e.class}: #{e.message}" - end - - def load_gemspec(file, validate = false) - @gemspec_cache ||= {} - key = File.expand_path(file) - @gemspec_cache[key] ||= load_gemspec_uncached(file, validate) - # Protect against caching side-effected gemspecs by returning a - # new instance each time. - @gemspec_cache[key].dup if @gemspec_cache[key] - end - - def load_gemspec_uncached(file, validate = false) - path = Pathname.new(file) - contents = read_file(file) - spec = if contents.start_with?("---") # YAML header - eval_yaml_gemspec(path, contents) - else - # Eval the gemspec from its parent directory, because some gemspecs - # depend on "./" relative paths. - SharedHelpers.chdir(path.dirname.to_s) do - eval_gemspec(path, contents) - end - end - return unless spec - spec.loaded_from = path.expand_path.to_s - Bundler.rubygems.validate(spec) if validate - spec - end - - def clear_gemspec_cache - @gemspec_cache = {} - end - - def git_present? - return @git_present if defined?(@git_present) - @git_present = Bundler.which("git") || Bundler.which("git.exe") - end - - def feature_flag - @feature_flag ||= FeatureFlag.new(VERSION) - end - - def reset! - reset_paths! - Plugin.reset! - reset_rubygems! - end - - def reset_paths! - @bin_path = nil - @bundler_major_version = nil - @bundle_path = nil - @configured = nil - @configured_bundle_path = nil - @definition = nil - @load = nil - @locked_gems = nil - @root = nil - @settings = nil - @setup = nil - @user_home = nil - end - - def reset_rubygems! - return unless defined?(@rubygems) && @rubygems - rubygems.undo_replacements - rubygems.reset - @rubygems = nil - end - - private - - def eval_yaml_gemspec(path, contents) - Kernel.send(:require, "bundler/psyched_yaml") - - # If the YAML is invalid, Syck raises an ArgumentError, and Psych - # raises a Psych::SyntaxError. See psyched_yaml.rb for more info. - Gem::Specification.from_yaml(contents) - rescue YamlLibrarySyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception - eval_gemspec(path, contents) - end - - def eval_gemspec(path, contents) - eval(contents, TOPLEVEL_BINDING.dup, path.expand_path.to_s) - rescue ScriptError, StandardError => e - msg = "There was an error while loading `#{path.basename}`: #{e.message}" - - if e.is_a?(LoadError) && RUBY_VERSION >= "1.9" - msg += "\nDoes it try to require a relative path? That's been removed in Ruby 1.9" - end - - raise GemspecError, Dsl::DSLError.new(msg, path, e.backtrace, contents) - end - - def configure_gem_home_and_path - configure_gem_path - configure_gem_home - bundle_path - end - - def configure_gem_path(env = ENV) - blank_home = env["GEM_HOME"].nil? || env["GEM_HOME"].empty? - if !use_system_gems? - # this needs to be empty string to cause - # PathSupport.split_gem_path to only load up the - # Bundler --path setting as the GEM_PATH. - env["GEM_PATH"] = "" - elsif blank_home - possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path] - paths = possibles.flatten.compact.uniq.reject(&:empty?) - env["GEM_PATH"] = paths.join(File::PATH_SEPARATOR) - end - end - - def configure_gem_home - Bundler::SharedHelpers.set_env "GEM_HOME", File.expand_path(bundle_path, root) - Bundler.rubygems.clear_paths - end - - # @param env [Hash] - def with_env(env) - backup = ENV.to_hash - ENV.replace(env) - yield - ensure - ENV.replace(backup) - end - end -end diff --git a/lib/ruby/stdlib/bundler/build_metadata.rb b/lib/ruby/stdlib/bundler/build_metadata.rb deleted file mode 100644 index 33f91e91622..00000000000 --- a/lib/ruby/stdlib/bundler/build_metadata.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # Represents metadata from when the Bundler gem was built. - module BuildMetadata - # begin ivars - @release = false - # end ivars - - # A hash representation of the build metadata. - def self.to_h - { - "Built At" => built_at, - "Git SHA" => git_commit_sha, - "Released Version" => release?, - } - end - - # A string representing the date the bundler gem was built. - def self.built_at - @built_at ||= Time.now.utc.strftime("%Y-%m-%d").freeze - end - - # The SHA for the git commit the bundler gem was built from. - def self.git_commit_sha - return @git_commit_sha if @git_commit_sha - - # If Bundler has been installed without its .git directory and without a - # commit instance variable then we can't determine its commits SHA. - git_dir = File.join(File.expand_path("../../..", __FILE__), ".git") - if File.directory?(git_dir) - return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze } - end - - # If Bundler is a submodule in RubyGems, get the submodule commit - git_sub_dir = File.join(File.expand_path("../../../..", __FILE__), ".git") - if File.directory?(git_sub_dir) - return @git_commit_sha = Dir.chdir(git_sub_dir) do - `git ls-tree --abbrev=8 HEAD bundler`.split(/\s/).fetch(2, "").strip.freeze - end - end - - @git_commit_sha ||= "unknown" - end - - # Whether this is an official release build of Bundler. - def self.release? - @release - end - end -end diff --git a/lib/ruby/stdlib/bundler/capistrano.rb b/lib/ruby/stdlib/bundler/capistrano.rb deleted file mode 100644 index 1b7145b72be..00000000000 --- a/lib/ruby/stdlib/bundler/capistrano.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require "bundler/shared_helpers" -Bundler::SharedHelpers.major_deprecation 2, - "The Bundler task for Capistrano. Please use http://github.com/capistrano/bundler" - -# Capistrano task for Bundler. -# -# Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and -# Bundler will be activated after each new deployment. -require "bundler/deployment" -require "capistrano/version" - -if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0") - raise "For Capistrano 3.x integration, please use http://github.com/capistrano/bundler" -end - -Capistrano::Configuration.instance(:must_exist).load do - before "deploy:finalize_update", "bundle:install" - Bundler::Deployment.define_task(self, :task, :except => { :no_release => true }) - set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" } -end diff --git a/lib/ruby/stdlib/bundler/cli.rb b/lib/ruby/stdlib/bundler/cli.rb deleted file mode 100644 index e658ffce72f..00000000000 --- a/lib/ruby/stdlib/bundler/cli.rb +++ /dev/null @@ -1,790 +0,0 @@ -# frozen_string_literal: true - -require "bundler" -require "bundler/vendored_thor" - -module Bundler - class CLI < Thor - require "bundler/cli/common" - - package_name "Bundler" - - AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze - PARSEABLE_COMMANDS = %w[ - check config help exec platform show version - ].freeze - - def self.start(*) - super - rescue Exception => e - Bundler.ui = UI::Shell.new - raise e - ensure - Bundler::SharedHelpers.print_major_deprecations! - end - - def self.dispatch(*) - super do |i| - i.send(:print_command) - i.send(:warn_on_outdated_bundler) - end - end - - def initialize(*args) - super - - custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile] - if custom_gemfile && !custom_gemfile.empty? - Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile) - Bundler.reset_paths! - end - - Bundler.settings.set_command_option_if_given :retry, options[:retry] - - current_cmd = args.last[:current_command].name - auto_install if AUTO_INSTALL_CMDS.include?(current_cmd) - rescue UnknownArgumentError => e - raise InvalidOption, e.message - ensure - self.options ||= {} - unprinted_warnings = Bundler.ui.unprinted_warnings - Bundler.ui = UI::Shell.new(options) - Bundler.ui.level = "debug" if options["verbose"] - unprinted_warnings.each {|w| Bundler.ui.warn(w) } - - if ENV["RUBYGEMS_GEMDEPS"] && !ENV["RUBYGEMS_GEMDEPS"].empty? - Bundler.ui.warn( - "The RUBYGEMS_GEMDEPS environment variable is set. This enables RubyGems' " \ - "experimental Gemfile mode, which may conflict with Bundler and cause unexpected errors. " \ - "To remove this warning, unset RUBYGEMS_GEMDEPS.", :wrap => true - ) - end - end - - def self.deprecated_option(*args, &blk) - return if Bundler.feature_flag.forget_cli_options? - method_option(*args, &blk) - end - - check_unknown_options!(:except => [:config, :exec]) - stop_on_unknown_option! :exec - - desc "cli_help", "Prints a summary of bundler commands", :hide => true - def cli_help - version - Bundler.ui.info "\n" - - primary_commands = ["install", "update", - Bundler.feature_flag.cache_command_is_package? ? "cache" : "package", - "exec", "config", "help"] - - list = self.class.printable_commands(true) - by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] } - utilities = by_name.keys.sort - primary_commands - primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first } - utilities.map! {|name| by_name[name].first } - - shell.say "Bundler commands:\n\n" - - shell.say " Primary commands:\n" - shell.print_table(primary_commands, :indent => 4, :truncate => true) - shell.say - shell.say " Utilities:\n" - shell.print_table(utilities, :indent => 4, :truncate => true) - shell.say - self.class.send(:class_options_help, shell) - end - default_task(Bundler.feature_flag.default_cli_command) - - class_option "no-color", :type => :boolean, :desc => "Disable colorization in output" - class_option "retry", :type => :numeric, :aliases => "-r", :banner => "NUM", - :desc => "Specify the number of times you wish to attempt network commands" - class_option "verbose", :type => :boolean, :desc => "Enable verbose output mode", :aliases => "-V" - - def help(cli = nil) - case cli - when "gemfile" then command = "gemfile" - when nil then command = "bundle" - else command = "bundle-#{cli}" - end - - man_path = File.expand_path("../../../man", __FILE__) - man_pages = Hash[Dir.glob(File.join(man_path, "*")).grep(/.*\.\d*\Z/).collect do |f| - [File.basename(f, ".*"), f] - end] - - if man_pages.include?(command) - if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+} - Kernel.exec "man #{man_pages[command]}" - else - puts File.read("#{man_path}/#{File.basename(man_pages[command])}.txt") - end - elsif command_path = Bundler.which("bundler-#{cli}") - Kernel.exec(command_path, "--help") - else - super - end - end - - def self.handle_no_command_error(command, has_namespace = $thor_runner) - if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command) - return Bundler::Plugin.exec_command(command, ARGV[1..-1]) - end - - return super unless command_path = Bundler.which("bundler-#{command}") - - Kernel.exec(command_path, *ARGV[1..-1]) - end - - desc "init [OPTIONS]", "Generates a Gemfile into the current working directory" - long_desc <<-D - Init generates a default Gemfile in the current working directory. When adding a - Gemfile to a gem with a gemspec, the --gemspec option will automatically add each - dependency listed in the gemspec file to the newly created Gemfile. - D - deprecated_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile" - def init - require "bundler/cli/init" - Init.new(options.dup).run - end - - desc "check [OPTIONS]", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems" - long_desc <<-D - Check searches the local machine for each of the gems requested in the Gemfile. If - all gems are found, Bundler prints a success message and exits with a status of 0. - If not, the first missing gem is listed and Bundler exits status 1. - D - method_option "dry-run", :type => :boolean, :default => false, :banner => - "Lock the Gemfile" - method_option "gemfile", :type => :string, :banner => - "Use the specified gemfile instead of Gemfile" - method_option "path", :type => :string, :banner => - "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" - map "c" => "check" - def check - require "bundler/cli/check" - Check.new(options).run - end - - desc "remove [GEM [GEM ...]]", "Removes gems from the Gemfile" - long_desc <<-D - Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning. - D - method_option "install", :type => :boolean, :banner => - "Runs 'bundle install' after removing the gems from the Gemfile" - def remove(*gems) - require "bundler/cli/remove" - Remove.new(gems, options).run - end - - desc "install [OPTIONS]", "Install the current environment to the system" - long_desc <<-D - Install will install all of the gems in the current bundle, making them available - for use. In a freshly checked out repository, this command will give you the same - gem versions as the last person who updated the Gemfile and ran `bundle update`. - - Passing [DIR] to install (e.g. vendor) will cause the unpacked gems to be installed - into the [DIR] directory rather than into system gems. - - If the bundle has already been installed, bundler will tell you so and then exit. - D - deprecated_option "binstubs", :type => :string, :lazy_default => "bin", :banner => - "Generate bin stubs for bundled gems to ./bin" - deprecated_option "clean", :type => :boolean, :banner => - "Run bundle clean automatically after install" - deprecated_option "deployment", :type => :boolean, :banner => - "Install using defaults tuned for deployment environments" - deprecated_option "frozen", :type => :boolean, :banner => - "Do not allow the Gemfile.lock to be updated after this install" - method_option "full-index", :type => :boolean, :banner => - "Fall back to using the single-file index of all gems" - method_option "gemfile", :type => :string, :banner => - "Use the specified gemfile instead of Gemfile" - method_option "jobs", :aliases => "-j", :type => :numeric, :banner => - "Specify the number of jobs to run in parallel" - method_option "local", :type => :boolean, :banner => - "Do not attempt to fetch gems remotely and use the gem cache instead" - deprecated_option "no-cache", :type => :boolean, :banner => - "Don't update the existing gem cache." - method_option "redownload", :type => :boolean, :aliases => "--force", :banner => - "Force downloading every gem." - deprecated_option "no-prune", :type => :boolean, :banner => - "Don't remove stale gems from the cache." - deprecated_option "path", :type => :string, :banner => - "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME). Bundler will remember this value for future installs on this machine" - method_option "quiet", :type => :boolean, :banner => - "Only output warnings and errors." - deprecated_option "shebang", :type => :string, :banner => - "Specify a different shebang executable name than the default (usually 'ruby')" - method_option "standalone", :type => :array, :lazy_default => [], :banner => - "Make a bundle that can work without the Bundler runtime" - deprecated_option "system", :type => :boolean, :banner => - "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application" - method_option "trust-policy", :alias => "P", :type => :string, :banner => - "Gem trust policy (like gem install -P). Must be one of " + - Bundler.rubygems.security_policy_keys.join("|") - deprecated_option "without", :type => :array, :banner => - "Exclude gems that are part of the specified named group." - deprecated_option "with", :type => :array, :banner => - "Include gems that are part of the specified named group." - map "i" => "install" - def install - SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") - require "bundler/cli/install" - Bundler.settings.temporary(:no_install => false) do - Install.new(options.dup).run - end - end - - desc "update [OPTIONS]", "Update the current environment" - long_desc <<-D - Update will install the newest versions of the gems listed in the Gemfile. Use - update when you have changed the Gemfile, or if you want to get the newest - possible versions of the gems in the bundle. - D - method_option "full-index", :type => :boolean, :banner => - "Fall back to using the single-file index of all gems" - method_option "gemfile", :type => :string, :banner => - "Use the specified gemfile instead of Gemfile" - method_option "group", :aliases => "-g", :type => :array, :banner => - "Update a specific group" - method_option "jobs", :aliases => "-j", :type => :numeric, :banner => - "Specify the number of jobs to run in parallel" - method_option "local", :type => :boolean, :banner => - "Do not attempt to fetch gems remotely and use the gem cache instead" - method_option "quiet", :type => :boolean, :banner => - "Only output warnings and errors." - method_option "source", :type => :array, :banner => - "Update a specific source (and all gems associated with it)" - method_option "redownload", :type => :boolean, :aliases => "--force", :banner => - "Force downloading every gem." - method_option "ruby", :type => :boolean, :banner => - "Update ruby specified in Gemfile.lock" - method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner => - "Update the locked version of bundler" - method_option "patch", :type => :boolean, :banner => - "Prefer updating only to next patch version" - method_option "minor", :type => :boolean, :banner => - "Prefer updating only to next minor version" - method_option "major", :type => :boolean, :banner => - "Prefer updating to next major version (default)" - method_option "strict", :type => :boolean, :banner => - "Do not allow any gem to be updated past latest --patch | --minor | --major" - method_option "conservative", :type => :boolean, :banner => - "Use bundle install conservative update behavior and do not allow shared dependencies to be updated." - method_option "all", :type => :boolean, :banner => - "Update everything." - def update(*gems) - SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") - require "bundler/cli/update" - Update.new(options, gems).run - end - - desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" - long_desc <<-D - Show lists the names and versions of all gems that are required by your Gemfile. - Calling show with [GEM] will list the exact location of that gem on your machine. - D - method_option "paths", :type => :boolean, - :banner => "List the paths of all gems that are required by your Gemfile." - method_option "outdated", :type => :boolean, - :banner => "Show verbose output including whether gems are outdated." - def show(gem_name = nil) - if ARGV[0] == "show" - rest = ARGV[1..-1] - - new_command = rest.find {|arg| !arg.start_with?("--") } ? "info" : "list" - - new_arguments = rest.map do |arg| - next arg if arg != "--paths" - next "--path" if new_command == "info" - end - - old_argv = ARGV.join(" ") - new_argv = [new_command, *new_arguments.compact].join(" ") - - Bundler::SharedHelpers.major_deprecation(2, "use `bundle #{new_argv}` instead of `bundle #{old_argv}`") - end - require "bundler/cli/show" - Show.new(options, gem_name).run - end - # TODO: 2.0 remove `bundle show` - - if Bundler.feature_flag.list_command? - desc "list", "List all gems in the bundle" - method_option "name-only", :type => :boolean, :banner => "print only the gem names" - method_option "only-group", :type => :string, :banner => "print gems from a particular group" - method_option "without-group", :type => :string, :banner => "print all gems expect from a group" - method_option "paths", :type => :boolean, :banner => "print the path to each gem in the bundle" - def list - require "bundler/cli/list" - List.new(options).run - end - - map %w[ls] => "list" - else - map %w[list] => "show" - end - - desc "info GEM [OPTIONS]", "Show information for the given gem" - method_option "path", :type => :boolean, :banner => "Print full path to gem" - def info(gem_name) - require "bundler/cli/info" - Info.new(options, gem_name).run - end - - desc "binstubs GEM [OPTIONS]", "Install the binstubs of the listed gem" - long_desc <<-D - Generate binstubs for executables in [GEM]. Binstubs are put into bin, - or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]] - will create binstubs for all given gems. - D - method_option "force", :type => :boolean, :default => false, :banner => - "Overwrite existing binstubs if they exist" - method_option "path", :type => :string, :lazy_default => "bin", :banner => - "Binstub destination directory (default bin)" - method_option "shebang", :type => :string, :banner => - "Specify a different shebang executable name than the default (usually 'ruby')" - method_option "standalone", :type => :boolean, :banner => - "Make binstubs that can work without the Bundler runtime" - method_option "all", :type => :boolean, :banner => - "Install binstubs for all gems" - def binstubs(*gems) - require "bundler/cli/binstubs" - Binstubs.new(options, gems).run - end - - desc "add GEM VERSION", "Add gem to Gemfile and run bundle install" - long_desc <<-D - Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step. - D - method_option "version", :aliases => "-v", :type => :string - method_option "group", :aliases => "-g", :type => :string - method_option "source", :aliases => "-s", :type => :string - method_option "skip-install", :type => :boolean, :banner => - "Adds gem to the Gemfile but does not install it" - method_option "optimistic", :type => :boolean, :banner => "Adds optimistic declaration of version to gem" - method_option "strict", :type => :boolean, :banner => "Adds strict declaration of version to gem" - def add(*gems) - require "bundler/cli/add" - Add.new(options.dup, gems).run - end - - desc "outdated GEM [OPTIONS]", "List installed gems with newer versions available" - long_desc <<-D - Outdated lists the names and versions of gems that have a newer version available - in the given source. Calling outdated with [GEM [GEM]] will only check for newer - versions of the given gems. Prerelease gems are ignored by default. If your gems - are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. - - For more information on patch level options (--major, --minor, --patch, - --update-strict) see documentation on the same options on the update command. - D - method_option "group", :type => :string, :banner => "List gems from a specific group" - method_option "groups", :type => :boolean, :banner => "List gems organized by groups" - method_option "local", :type => :boolean, :banner => - "Do not attempt to fetch gems remotely and use the gem cache instead" - method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems" - method_option "source", :type => :array, :banner => "Check against a specific source" - method_option "strict", :type => :boolean, :banner => - "Only list newer versions allowed by your Gemfile requirements" - method_option "update-strict", :type => :boolean, :banner => - "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" - method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" - method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" - method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version" - method_option "filter-major", :type => :boolean, :banner => "Only list major newer versions" - method_option "filter-minor", :type => :boolean, :banner => "Only list minor newer versions" - method_option "filter-patch", :type => :boolean, :banner => "Only list patch newer versions" - method_option "parseable", :aliases => "--porcelain", :type => :boolean, :banner => - "Use minimal formatting for more parseable output" - method_option "only-explicit", :type => :boolean, :banner => - "Only list gems specified in your Gemfile, not their dependencies" - def outdated(*gems) - require "bundler/cli/outdated" - Outdated.new(options, gems).run - end - - if Bundler.feature_flag.cache_command_is_package? - map %w[cache] => :package - else - desc "cache [OPTIONS]", "Cache all the gems to vendor/cache", :hide => true - unless Bundler.feature_flag.cache_command_is_package? - method_option "all", :type => :boolean, - :banner => "Include all sources (including path and git)." - end - method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one" - method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." - def cache - require "bundler/cli/cache" - Cache.new(options).run - end - end - - desc "#{Bundler.feature_flag.cache_command_is_package? ? :cache : :package} [OPTIONS]", "Locks and then caches all of the gems into vendor/cache" - unless Bundler.feature_flag.cache_command_is_package? - method_option "all", :type => :boolean, - :banner => "Include all sources (including path and git)." - end - method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one" - method_option "cache-path", :type => :string, :banner => - "Specify a different cache path than the default (vendor/cache)." - method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile" - method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only the package." - method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache." - method_option "path", :type => :string, :banner => - "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME). Bundler will remember this value for future installs on this machine" - method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors." - method_option "frozen", :type => :boolean, :banner => - "Do not allow the Gemfile.lock to be updated after this package operation's install" - long_desc <<-D - The package command will copy the .gem files for every gem in the bundle into the - directory ./vendor/cache. If you then check that directory into your source - control repository, others who check out your source will be able to install the - bundle without having to download any additional gems. - D - def package - require "bundler/cli/package" - Package.new(options).run - end - map %w[pack] => :package - - desc "exec [OPTIONS]", "Run the command in context of the bundle" - method_option :keep_file_descriptors, :type => :boolean, :default => false - method_option :gemfile, :type => :string, :required => false - long_desc <<-D - Exec runs a command, providing it access to the gems in the bundle. While using - bundle exec you can require and call the bundled gems as if they were installed - into the system wide RubyGems repository. - D - map "e" => "exec" - def exec(*args) - require "bundler/cli/exec" - Exec.new(options, args).run - end - - desc "config NAME [VALUE]", "Retrieve or set a configuration value" - long_desc <<-D - Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the - existing value with the newly provided one. - - By default, setting a configuration value sets it for all projects - on the machine. - - If a global setting is superceded by local configuration, this command - will show the current value, as well as any superceded values and - where they were specified. - D - method_option "parseable", :type => :boolean, :banner => "Use minimal formatting for more parseable output" - def config(*args) - require "bundler/cli/config" - Config.new(options, args, self).run - end - - desc "open GEM", "Opens the source directory of the given bundled gem" - def open(name) - require "bundler/cli/open" - Open.new(options, name).run - end - - if Bundler.feature_flag.console_command? - desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded" - def console(group = nil) - require "bundler/cli/console" - Console.new(options, group).run - end - end - - desc "version", "Prints the bundler's version information" - def version - cli_help = current_command.name == "cli_help" - if cli_help || ARGV.include?("version") - build_info = " (#{BuildMetadata.built_at} commit #{BuildMetadata.git_commit_sha})" - end - - if !cli_help && Bundler.feature_flag.print_only_version_number? - Bundler.ui.info "#{Bundler::VERSION}#{build_info}" - else - Bundler.ui.info "Bundler version #{Bundler::VERSION}#{build_info}" - end - end - map %w[-v --version] => :version - - desc "licenses", "Prints the license of all gems in the bundle" - def licenses - Bundler.load.specs.sort_by {|s| s.license.to_s }.reverse_each do |s| - gem_name = s.name - license = s.license || s.licenses - - if license.empty? - Bundler.ui.warn "#{gem_name}: Unknown" - else - Bundler.ui.info "#{gem_name}: #{license}" - end - end - end - - if Bundler.feature_flag.viz_command? - desc "viz [OPTIONS]", "Generates a visual dependency graph", :hide => true - long_desc <<-D - Viz generates a PNG file of the current Gemfile as a dependency graph. - Viz requires the ruby-graphviz gem (and its dependencies). - The associated gems must also be installed via 'bundle install'. - D - method_option :file, :type => :string, :default => "gem_graph", :aliases => "-f", :desc => "The name to use for the generated file. see format option" - method_option :format, :type => :string, :default => "png", :aliases => "-F", :desc => "This is output format option. Supported format is png, jpg, svg, dot ..." - method_option :requirements, :type => :boolean, :default => false, :aliases => "-R", :desc => "Set to show the version of each required dependency." - method_option :version, :type => :boolean, :default => false, :aliases => "-v", :desc => "Set to show each gem version." - method_option :without, :type => :array, :default => [], :aliases => "-W", :banner => "GROUP[ GROUP...]", :desc => "Exclude gems that are part of the specified named group." - def viz - SharedHelpers.major_deprecation 2, "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/bundler/bundler-viz" - require "bundler/cli/viz" - Viz.new(options.dup).run - end - end - - old_gem = instance_method(:gem) - - desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem" - method_option :exe, :type => :boolean, :default => false, :aliases => ["--bin", "-b"], :desc => "Generate a binary executable for your library." - method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config gem.coc true`." - method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR", - :lazy_default => [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, - :desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" - method_option :ext, :type => :boolean, :default => false, :desc => "Generate the boilerplate for C extension code" - method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config gem.mit true`." - method_option :test, :type => :string, :lazy_default => "rspec", :aliases => "-t", :banner => "rspec", - :desc => "Generate a test directory for your library, either rspec or minitest. Set a default with `bundle config gem.test rspec`." - def gem(name) - end - - commands["gem"].tap do |gem_command| - def gem_command.run(instance, args = []) - arity = 1 # name - - require "bundler/cli/gem" - cmd_args = args + [instance] - cmd_args.unshift(instance.options) - - cmd = begin - Gem.new(*cmd_args) - rescue ArgumentError => e - instance.class.handle_argument_error(self, e, args, arity) - end - - cmd.run - end - end - - undef_method(:gem) - define_method(:gem, old_gem) - private :gem - - def self.source_root - File.expand_path(File.join(File.dirname(__FILE__), "templates")) - end - - desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true - method_option "dry-run", :type => :boolean, :default => false, :banner => - "Only print out changes, do not clean gems" - method_option "force", :type => :boolean, :default => false, :banner => - "Forces clean even if --path is not set" - def clean - require "bundler/cli/clean" - Clean.new(options.dup).run - end - - desc "platform [OPTIONS]", "Displays platform compatibility information" - method_option "ruby", :type => :boolean, :default => false, :banner => - "only display ruby related platform information" - def platform - require "bundler/cli/platform" - Platform.new(options).run - end - - desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", :hide => true - method_option "source", :type => :string, :banner => - "Install gem from the given source" - method_option "group", :type => :string, :banner => - "Install gem into a bundler group" - def inject(name, version) - SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command" - require "bundler/cli/inject" - Inject.new(options.dup, name, version).run - end - - desc "lock", "Creates a lockfile without installing" - method_option "update", :type => :array, :lazy_default => true, :banner => - "ignore the existing lockfile, update all gems by default, or update list of given gems" - method_option "local", :type => :boolean, :default => false, :banner => - "do not attempt to fetch remote gemspecs and use the local gem cache only" - method_option "print", :type => :boolean, :default => false, :banner => - "print the lockfile to STDOUT instead of writing to the file system" - method_option "lockfile", :type => :string, :default => nil, :banner => - "the path the lockfile should be written to" - method_option "full-index", :type => :boolean, :default => false, :banner => - "Fall back to using the single-file index of all gems" - method_option "add-platform", :type => :array, :default => [], :banner => - "Add a new platform to the lockfile" - method_option "remove-platform", :type => :array, :default => [], :banner => - "Remove a platform from the lockfile" - method_option "patch", :type => :boolean, :banner => - "If updating, prefer updating only to next patch version" - method_option "minor", :type => :boolean, :banner => - "If updating, prefer updating only to next minor version" - method_option "major", :type => :boolean, :banner => - "If updating, prefer updating to next major version (default)" - method_option "strict", :type => :boolean, :banner => - "If updating, do not allow any gem to be updated past latest --patch | --minor | --major" - method_option "conservative", :type => :boolean, :banner => - "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated" - def lock - require "bundler/cli/lock" - Lock.new(options).run - end - - desc "env", "Print information about the environment Bundler is running under" - def env - Env.write($stdout) - end - - desc "doctor [OPTIONS]", "Checks the bundle for common problems" - long_desc <<-D - Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If - missing dependencies are detected, Bundler prints them and exits status 1. - Otherwise, Bundler prints a success message and exits with a status of 0. - D - method_option "gemfile", :type => :string, :banner => - "Use the specified gemfile instead of Gemfile" - method_option "quiet", :type => :boolean, :banner => - "Only output warnings and errors." - def doctor - require "bundler/cli/doctor" - Doctor.new(options).run - end - - desc "issue", "Learn how to report an issue in Bundler" - def issue - require "bundler/cli/issue" - Issue.new.run - end - - desc "pristine [GEMS...]", "Restores installed gems to pristine condition" - long_desc <<-D - Restores installed gems to pristine condition from files located in the - gem cache. Gems installed from a git repository will be issued `git - checkout --force`. - D - def pristine(*gems) - require "bundler/cli/pristine" - Pristine.new(gems).run - end - - if Bundler.feature_flag.plugins? - require "bundler/cli/plugin" - desc "plugin", "Manage the bundler plugins" - subcommand "plugin", Plugin - end - - # Reformat the arguments passed to bundle that include a --help flag - # into the corresponding `bundle help #{command}` call - def self.reformatted_help_args(args) - bundler_commands = all_commands.keys - help_flags = %w[--help -h] - exec_commands = %w[e ex exe exec] - help_used = args.index {|a| help_flags.include? a } - exec_used = args.index {|a| exec_commands.include? a } - command = args.find {|a| bundler_commands.include? a } - if exec_used && help_used - if exec_used + help_used == 1 - %w[help exec] - else - args - end - elsif help_used - args = args.dup - args.delete_at(help_used) - ["help", command || args].flatten.compact - else - args - end - end - - private - - # Automatically invoke `bundle install` and resume if - # Bundler.settings[:auto_install] exists. This is set through config cmd - # `bundle config auto_install 1`. - # - # Note that this method `nil`s out the global Definition object, so it - # should be called first, before you instantiate anything like an - # `Installer` that'll keep a reference to the old one instead. - def auto_install - return unless Bundler.settings[:auto_install] - - begin - Bundler.definition.specs - rescue GemNotFound - Bundler.ui.info "Automatically installing missing gems." - Bundler.reset! - invoke :install, [] - Bundler.reset! - end - end - - def current_command - _, _, config = @_initializer - config[:current_command] - end - - def print_command - return unless Bundler.ui.debug? - cmd = current_command - command_name = cmd.name - return if PARSEABLE_COMMANDS.include?(command_name) - command = ["bundle", command_name] + args - options_to_print = options.dup - options_to_print.delete_if do |k, v| - next unless o = cmd.options[k] - o.default == v - end - command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip - command.reject!(&:empty?) - Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler::VERSION}" - end - - def warn_on_outdated_bundler - return if Bundler.settings[:disable_version_check] - - command_name = current_command.name - return if PARSEABLE_COMMANDS.include?(command_name) - - return unless SharedHelpers.md5_available? - - latest = Fetcher::CompactIndex. - new(nil, Source::Rubygems::Remote.new(URI("https://rubygems.org")), nil). - send(:compact_index_client). - instance_variable_get(:@cache). - dependencies("bundler"). - map {|d| Gem::Version.new(d.first) }. - max - return unless latest - - current = Gem::Version.new(VERSION) - return if current >= latest - latest_installed = Bundler.rubygems.find_name("bundler").map(&:version).max - - installation = "To install the latest version, run `gem install bundler#{" --pre" if latest.prerelease?}`" - if latest_installed && latest_installed > current - suggestion = "To update to the most recent installed version (#{latest_installed}), run `bundle update --bundler`" - suggestion = "#{installation}\n#{suggestion}" if latest_installed < latest - else - suggestion = installation - end - - Bundler.ui.warn "The latest bundler is #{latest}, but you are currently running #{current}.\n#{suggestion}" - rescue RuntimeError - nil - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/add.rb b/lib/ruby/stdlib/bundler/cli/add.rb deleted file mode 100644 index 9709e71be04..00000000000 --- a/lib/ruby/stdlib/bundler/cli/add.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Add - def initialize(options, gems) - @gems = gems - @options = options - @options[:group] = @options[:group].split(",").map(&:strip) if !@options[:group].nil? && !@options[:group].empty? - end - - def run - raise InvalidOption, "You can not specify `--strict` and `--optimistic` at the same time." if @options[:strict] && @options[:optimistic] - - # raise error when no gems are specified - raise InvalidOption, "Please specify gems to add." if @gems.empty? - - version = @options[:version].nil? ? nil : @options[:version].split(",").map(&:strip) - - unless version.nil? - version.each do |v| - raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN =~ v.to_s - end - end - - dependencies = @gems.map {|g| Bundler::Dependency.new(g, version, @options) } - - Injector.inject(dependencies, - :conservative_versioning => @options[:version].nil?, # Perform conservative versioning only when version is not specified - :optimistic => @options[:optimistic], - :strict => @options[:strict]) - - Installer.install(Bundler.root, Bundler.definition) unless @options["skip-install"] - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/binstubs.rb b/lib/ruby/stdlib/bundler/cli/binstubs.rb deleted file mode 100644 index 266396eedc6..00000000000 --- a/lib/ruby/stdlib/bundler/cli/binstubs.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Binstubs - attr_reader :options, :gems - def initialize(options, gems) - @options = options - @gems = gems - end - - def run - Bundler.definition.validate_runtime! - path_option = options["path"] - path_option = nil if path_option && path_option.empty? - Bundler.settings.set_command_option :bin, path_option if options["path"] - Bundler.settings.set_command_option_if_given :shebang, options["shebang"] - installer = Installer.new(Bundler.root, Bundler.definition) - - installer_opts = { :force => options[:force], :binstubs_cmd => true } - - if options[:all] - raise InvalidOption, "Cannot specify --all with specific gems" unless gems.empty? - @gems = Bundler.definition.specs.map(&:name) - installer_opts.delete(:binstubs_cmd) - elsif gems.empty? - Bundler.ui.error "`bundle binstubs` needs at least one gem to run." - exit 1 - end - - gems.each do |gem_name| - spec = Bundler.definition.specs.find {|s| s.name == gem_name } - unless spec - raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( - gem_name, Bundler.definition.specs - ) - end - - if options[:standalone] - next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler" - Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do - installer.generate_standalone_bundler_executable_stubs(spec) - end - else - installer.generate_bundler_executable_stubs(spec, installer_opts) - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/cache.rb b/lib/ruby/stdlib/bundler/cli/cache.rb deleted file mode 100644 index 9d2ba87d340..00000000000 --- a/lib/ruby/stdlib/bundler/cli/cache.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Cache - attr_reader :options - def initialize(options) - @options = options - end - - def run - Bundler.definition.validate_runtime! - Bundler.definition.resolve_with_cache! - setup_cache_all - Bundler.settings.set_command_option_if_given :cache_all_platforms, options["all-platforms"] - Bundler.load.cache - Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] - Bundler.load.lock - rescue GemNotFound => e - Bundler.ui.error(e.message) - Bundler.ui.warn "Run `bundle install` to install missing gems." - exit 1 - end - - private - - def setup_cache_all - Bundler.settings.set_command_option_if_given :cache_all, options[:all] - - if Bundler.definition.has_local_dependencies? && !Bundler.feature_flag.cache_all? - Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \ - "to package them as well, please pass the --all flag. This will be the default " \ - "on Bundler 2.0." - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/check.rb b/lib/ruby/stdlib/bundler/cli/check.rb deleted file mode 100644 index 19c0aaea06e..00000000000 --- a/lib/ruby/stdlib/bundler/cli/check.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Check - attr_reader :options - - def initialize(options) - @options = options - end - - def run - Bundler.settings.set_command_option_if_given :path, options[:path] - - begin - definition = Bundler.definition - definition.validate_runtime! - not_installed = definition.missing_specs - rescue GemNotFound, VersionConflict - Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." - Bundler.ui.warn "Install missing gems with `bundle install`." - exit 1 - end - - if not_installed.any? - Bundler.ui.error "The following gems are missing" - not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } - Bundler.ui.warn "Install missing gems with `bundle install`" - exit 1 - elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle? - Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present" - exit 1 - else - Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"] - Bundler.ui.info "The Gemfile's dependencies are satisfied" - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/clean.rb b/lib/ruby/stdlib/bundler/cli/clean.rb deleted file mode 100644 index 4a407fbae7e..00000000000 --- a/lib/ruby/stdlib/bundler/cli/clean.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Clean - attr_reader :options - - def initialize(options) - @options = options - end - - def run - require_path_or_force unless options[:"dry-run"] - Bundler.load.clean(options[:"dry-run"]) - end - - protected - - def require_path_or_force - return unless Bundler.use_system_gems? && !options[:force] - raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \ - "If you're sure you want to remove every system gem not in this " \ - "bundle, run `bundle clean --force`." - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/common.rb b/lib/ruby/stdlib/bundler/cli/common.rb deleted file mode 100644 index 9d40ee9dfd1..00000000000 --- a/lib/ruby/stdlib/bundler/cli/common.rb +++ /dev/null @@ -1,102 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module CLI::Common - def self.output_post_install_messages(messages) - return if Bundler.settings["ignore_messages"] - messages.to_a.each do |name, msg| - print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"] - end - end - - def self.print_post_install_message(name, msg) - Bundler.ui.confirm "Post-install message from #{name}:" - Bundler.ui.info msg - end - - def self.output_without_groups_message - return if Bundler.settings[:without].empty? - Bundler.ui.confirm without_groups_message - end - - def self.without_groups_message - groups = Bundler.settings[:without] - group_list = [groups[0...-1].join(", "), groups[-1..-1]]. - reject {|s| s.to_s.empty? }.join(" and ") - group_str = (groups.size == 1) ? "group" : "groups" - "Gems in the #{group_str} #{group_list} were not installed." - end - - def self.select_spec(name, regex_match = nil) - specs = [] - regexp = Regexp.new(name) if regex_match - - Bundler.definition.specs.each do |spec| - return spec if spec.name == name - specs << spec if regexp && spec.name =~ regexp - end - - case specs.count - when 0 - raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) - when 1 - specs.first - else - ask_for_spec_from(specs) - end - rescue RegexpError - raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) - end - - def self.ask_for_spec_from(specs) - if !$stdout.tty? && ENV["BUNDLE_SPEC_RUN"].nil? - raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) - end - - specs.each_with_index do |spec, index| - Bundler.ui.info "#{index.succ} : #{spec.name}", true - end - Bundler.ui.info "0 : - exit -", true - - num = Bundler.ui.ask("> ").to_i - num > 0 ? specs[num - 1] : nil - end - - def self.gem_not_found_message(missing_gem_name, alternatives) - require "bundler/similarity_detector" - message = "Could not find gem '#{missing_gem_name}'." - alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a } - suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name) - message += "\nDid you mean #{suggestions}?" if suggestions - message - end - - def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) - locked_names = locked_gems.specs.map(&:name) - names.-(locked_names).each do |g| - raise GemNotFound, gem_not_found_message(g, locked_names) - end - end - - def self.configure_gem_version_promoter(definition, options) - patch_level = patch_level_options(options) - raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1 - definition.gem_version_promoter.tap do |gvp| - gvp.level = patch_level.first || :major - gvp.strict = options[:strict] || options["update-strict"] - end - end - - def self.patch_level_options(options) - [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } - end - - def self.clean_after_install? - clean = Bundler.settings[:clean] - return clean unless clean.nil? - clean ||= Bundler.feature_flag.auto_clean_without_path? && Bundler.settings[:path].nil? - clean &&= !Bundler.use_system_gems? - clean - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/config.rb b/lib/ruby/stdlib/bundler/cli/config.rb deleted file mode 100644 index 12f71ea8fea..00000000000 --- a/lib/ruby/stdlib/bundler/cli/config.rb +++ /dev/null @@ -1,119 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Config - attr_reader :name, :options, :scope, :thor - attr_accessor :args - - def initialize(options, args, thor) - @options = options - @args = args - @thor = thor - @name = peek = args.shift - @scope = "global" - return unless peek && peek.start_with?("--") - @name = args.shift - @scope = peek[2..-1] - end - - def run - unless name - confirm_all - return - end - - unless valid_scope?(scope) - Bundler.ui.error "Invalid scope --#{scope} given. Please use --local or --global." - exit 1 - end - - if scope == "delete" - Bundler.settings.set_local(name, nil) - Bundler.settings.set_global(name, nil) - return - end - - if args.empty? - if options[:parseable] - if value = Bundler.settings[name] - Bundler.ui.info("#{name}=#{value}") - end - return - end - - confirm(name) - return - end - - Bundler.ui.info(message) if message - Bundler.settings.send("set_#{scope}", name, new_value) - end - - private - - def confirm_all - if @options[:parseable] - thor.with_padding do - Bundler.settings.all.each do |setting| - val = Bundler.settings[setting] - Bundler.ui.info "#{setting}=#{val}" - end - end - else - Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n" - Bundler.settings.all.each do |setting| - Bundler.ui.confirm "#{setting}" - show_pretty_values_for(setting) - Bundler.ui.confirm "" - end - end - end - - def confirm(name) - Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" - show_pretty_values_for(name) - end - - def new_value - pathname = Pathname.new(args.join(" ")) - if name.start_with?("local.") && pathname.directory? - pathname.expand_path.to_s - else - args.join(" ") - end - end - - def message - locations = Bundler.settings.locations(name) - if @options[:parseable] - "#{name}=#{new_value}" if new_value - elsif scope == "global" - if locations[:local] - "Your application has set #{name} to #{locations[:local].inspect}. " \ - "This will override the global value you are currently setting" - elsif locations[:env] - "You have a bundler environment variable for #{name} set to " \ - "#{locations[:env].inspect}. This will take precedence over the global value you are setting" - elsif locations[:global] && locations[:global] != args.join(" ") - "You are replacing the current global value of #{name}, which is currently " \ - "#{locations[:global].inspect}" - end - elsif scope == "local" && locations[:local] != args.join(" ") - "You are replacing the current local value of #{name}, which is currently " \ - "#{locations[:local].inspect}" - end - end - - def show_pretty_values_for(setting) - thor.with_padding do - Bundler.settings.pretty_values_for(setting).each do |line| - Bundler.ui.info line - end - end - end - - def valid_scope?(scope) - %w[delete local global].include?(scope) - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/console.rb b/lib/ruby/stdlib/bundler/cli/console.rb deleted file mode 100644 index 853eca8358a..00000000000 --- a/lib/ruby/stdlib/bundler/cli/console.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Console - attr_reader :options, :group - def initialize(options, group) - @options = options - @group = group - end - - def run - Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \ - "by `bin/console` generated by `bundle gem `" - - group ? Bundler.require(:default, *(group.split.map!(&:to_sym))) : Bundler.require - ARGV.clear - - console = get_console(Bundler.settings[:console] || "irb") - console.start - end - - def get_console(name) - require name - get_constant(name) - rescue LoadError - Bundler.ui.error "Couldn't load console #{name}, falling back to irb" - require "irb" - get_constant("irb") - end - - def get_constant(name) - const_name = { - "pry" => :Pry, - "ripl" => :Ripl, - "irb" => :IRB, - }[name] - Object.const_get(const_name) - rescue NameError - Bundler.ui.error "Could not find constant #{const_name}" - exit 1 - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/doctor.rb b/lib/ruby/stdlib/bundler/cli/doctor.rb deleted file mode 100644 index 3e0898ff8a8..00000000000 --- a/lib/ruby/stdlib/bundler/cli/doctor.rb +++ /dev/null @@ -1,140 +0,0 @@ -# frozen_string_literal: true - -require "rbconfig" - -module Bundler - class CLI::Doctor - DARWIN_REGEX = /\s+(.+) \(compatibility / - LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/ - - attr_reader :options - - def initialize(options) - @options = options - end - - def otool_available? - Bundler.which("otool") - end - - def ldd_available? - Bundler.which("ldd") - end - - def dylibs_darwin(path) - output = `/usr/bin/otool -L "#{path}"`.chomp - dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq - # ignore @rpath and friends - dylibs.reject {|dylib| dylib.start_with? "@" } - end - - def dylibs_ldd(path) - output = `/usr/bin/ldd "#{path}"`.chomp - output.split("\n").map do |l| - match = l.match(LDD_REGEX) - next if match.nil? - match.captures[0] - end.compact - end - - def dylibs(path) - case RbConfig::CONFIG["host_os"] - when /darwin/ - return [] unless otool_available? - dylibs_darwin(path) - when /(linux|solaris|bsd)/ - return [] unless ldd_available? - dylibs_ldd(path) - else # Windows, etc. - Bundler.ui.warn("Dynamic library check not supported on this platform.") - [] - end - end - - def bundles_for_gem(spec) - Dir.glob("#{spec.full_gem_path}/**/*.bundle") - end - - def check! - require "bundler/cli/check" - Bundler::CLI::Check.new({}).run - end - - def run - Bundler.ui.level = "error" if options[:quiet] - Bundler.settings.validate! - check! - - definition = Bundler.definition - broken_links = {} - - definition.specs.each do |spec| - bundles_for_gem(spec).each do |bundle| - bad_paths = dylibs(bundle).select {|f| !File.exist?(f) } - if bad_paths.any? - broken_links[spec] ||= [] - broken_links[spec].concat(bad_paths) - end - end - end - - permissions_valid = check_home_permissions - - if broken_links.any? - message = "The following gems are missing OS dependencies:" - broken_links.map do |spec, paths| - paths.uniq.map do |path| - "\n * #{spec.name}: #{path}" - end - end.flatten.sort.each {|m| message += m } - raise ProductionError, message - elsif !permissions_valid - Bundler.ui.info "No issues found with the installed bundle" - end - end - - private - - def check_home_permissions - require "find" - files_not_readable_or_writable = [] - files_not_rw_and_owned_by_different_user = [] - files_not_owned_by_current_user_but_still_rw = [] - Find.find(Bundler.home.to_s).each do |f| - if !File.writable?(f) || !File.readable?(f) - if File.stat(f).uid != Process.uid - files_not_rw_and_owned_by_different_user << f - else - files_not_readable_or_writable << f - end - elsif File.stat(f).uid != Process.uid - files_not_owned_by_current_user_but_still_rw << f - end - end - - ok = true - if files_not_owned_by_current_user_but_still_rw.any? - Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ - "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" - - ok = false - end - - if files_not_rw_and_owned_by_different_user.any? - Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ - "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}" - - ok = false - end - - if files_not_readable_or_writable.any? - Bundler.ui.warn "Files exist in the Bundler home that are not " \ - "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" - - ok = false - end - - ok - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/exec.rb b/lib/ruby/stdlib/bundler/cli/exec.rb deleted file mode 100644 index c29d6323070..00000000000 --- a/lib/ruby/stdlib/bundler/cli/exec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# frozen_string_literal: true - -require "bundler/current_ruby" - -module Bundler - class CLI::Exec - attr_reader :options, :args, :cmd - - TRAPPED_SIGNALS = %w[INT].freeze - - def initialize(options, args) - @options = options - @cmd = args.shift - @args = args - - if Bundler.current_ruby.ruby_2? && !Bundler.current_ruby.jruby? - @args << { :close_others => !options.keep_file_descriptors? } - elsif options.keep_file_descriptors? - Bundler.ui.warn "Ruby version #{RUBY_VERSION} defaults to keeping non-standard file descriptors on Kernel#exec." - end - end - - def run - validate_cmd! - SharedHelpers.set_bundle_environment - if bin_path = Bundler.which(cmd) - if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path) - return kernel_load(bin_path, *args) - end - # First, try to exec directly to something in PATH - if Bundler.current_ruby.jruby_18? - kernel_exec(bin_path, *args) - else - kernel_exec([bin_path, cmd], *args) - end - else - # exec using the given command - kernel_exec(cmd, *args) - end - end - - private - - def validate_cmd! - return unless cmd.nil? - Bundler.ui.error "bundler: exec needs a command to run" - exit 128 - end - - def kernel_exec(*args) - ui = Bundler.ui - Bundler.ui = nil - Kernel.exec(*args) - rescue Errno::EACCES, Errno::ENOEXEC - Bundler.ui = ui - Bundler.ui.error "bundler: not executable: #{cmd}" - exit 126 - rescue Errno::ENOENT - Bundler.ui = ui - Bundler.ui.error "bundler: command not found: #{cmd}" - Bundler.ui.warn "Install missing gem executables with `bundle install`" - exit 127 - end - - def kernel_load(file, *args) - args.pop if args.last.is_a?(Hash) - ARGV.replace(args) - $0 = file - Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle) - ui = Bundler.ui - Bundler.ui = nil - require "bundler/setup" - TRAPPED_SIGNALS.each {|s| trap(s, "DEFAULT") } - Kernel.load(file) - rescue SystemExit, SignalException - raise - rescue Exception => e # rubocop:disable Lint/RescueException - Bundler.ui = ui - Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" - backtrace = e.backtrace ? e.backtrace.take_while {|bt| !bt.start_with?(__FILE__) } : [] - abort "#{e.class}: #{e.message}\n #{backtrace.join("\n ")}" - end - - def process_title(file, args) - "#{file} #{args.join(" ")}".strip - end - - def ruby_shebang?(file) - possibilities = [ - "#!/usr/bin/env ruby\n", - "#!/usr/bin/env jruby\n", - "#!/usr/bin/env truffleruby\n", - "#!#{Gem.ruby}\n", - ] - - if File.zero?(file) - Bundler.ui.warn "#{file} is empty" - return false - end - - first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } - possibilities.any? {|shebang| first_line.start_with?(shebang) } - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/gem.rb b/lib/ruby/stdlib/bundler/cli/gem.rb deleted file mode 100644 index 58e2f8a3fdb..00000000000 --- a/lib/ruby/stdlib/bundler/cli/gem.rb +++ /dev/null @@ -1,252 +0,0 @@ -# frozen_string_literal: true - -require "pathname" - -module Bundler - class CLI - Bundler.require_thor_actions - include Thor::Actions - end - - class CLI::Gem - TEST_FRAMEWORK_VERSIONS = { - "rspec" => "3.0", - "minitest" => "5.0" - }.freeze - - attr_reader :options, :gem_name, :thor, :name, :target - - def initialize(options, gem_name, thor) - @options = options - @gem_name = resolve_name(gem_name) - - @thor = thor - thor.behavior = :invoke - thor.destination_root = nil - - @name = @gem_name - @target = SharedHelpers.pwd.join(gem_name) - - validate_ext_name if options[:ext] - end - - def run - Bundler.ui.confirm "Creating gem '#{name}'..." - - underscored_name = name.tr("-", "_") - namespaced_path = name.tr("-", "/") - constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } - constant_array = constant_name.split("::") - - git_installed = Bundler.git_present? - - git_author_name = git_installed ? `git config user.name`.chomp : "" - github_username = git_installed ? `git config github.user`.chomp : "" - git_user_email = git_installed ? `git config user.email`.chomp : "" - - config = { - :name => name, - :underscored_name => underscored_name, - :namespaced_path => namespaced_path, - :makefile_path => "#{underscored_name}/#{underscored_name}", - :constant_name => constant_name, - :constant_array => constant_array, - :author => git_author_name.empty? ? "TODO: Write your name" : git_author_name, - :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email, - :test => options[:test], - :ext => options[:ext], - :exe => options[:exe], - :bundler_version => bundler_dependency_version, - :github_username => github_username.empty? ? "[USERNAME]" : github_username - } - ensure_safe_gem_name(name, constant_array) - - templates = { - "Gemfile.tt" => "Gemfile", - "lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb", - "lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb", - "newgem.gemspec.tt" => "#{name}.gemspec", - "Rakefile.tt" => "Rakefile", - "README.md.tt" => "README.md", - "bin/console.tt" => "bin/console", - "bin/setup.tt" => "bin/setup" - } - - executables = %w[ - bin/console - bin/setup - ] - - templates.merge!("gitignore.tt" => ".gitignore") if Bundler.git_present? - - if test_framework = ask_and_set_test_framework - config[:test] = test_framework - config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework] - - templates.merge!("travis.yml.tt" => ".travis.yml") - - case test_framework - when "rspec" - templates.merge!( - "rspec.tt" => ".rspec", - "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", - "spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb" - ) - when "minitest" - templates.merge!( - "test/test_helper.rb.tt" => "test/test_helper.rb", - "test/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" - ) - end - end - - config[:test_task] = config[:test] == "minitest" ? "test" : "spec" - - if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", - "This means that any other developer or company will be legally allowed to use your code " \ - "for free as long as they admit you created it. You can read more about the MIT license " \ - "at https://choosealicense.com/licenses/mit.") - config[:mit] = true - Bundler.ui.info "MIT License enabled in config" - templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") - end - - if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", - "Codes of conduct can increase contributions to your project by contributors who " \ - "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ - "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ - "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \ - "address is specified as a contact in the generated code of conduct so that people know " \ - "who to contact in case of a violation. For suggestions about " \ - "how to enforce codes of conduct, see https://bit.ly/coc-enforcement.") - config[:coc] = true - Bundler.ui.info "Code of conduct enabled in config" - templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") - end - - templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] - - if options[:ext] - templates.merge!( - "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", - "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", - "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" - ) - end - - templates.each do |src, dst| - destination = target.join(dst) - SharedHelpers.filesystem_access(destination) do - thor.template("newgem/#{src}", destination, config) - end - end - - executables.each do |file| - SharedHelpers.filesystem_access(target.join(file)) do |path| - executable = (path.stat.mode | 0o111) - path.chmod(executable) - end - end - - if Bundler.git_present? - Bundler.ui.info "Initializing git repo in #{target}" - Dir.chdir(target) do - `git init` - `git add .` - end - end - - # Open gemspec in editor - open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] - - Bundler.ui.info "Gem '#{name}' was successfully created. " \ - "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" - rescue Errno::EEXIST => e - raise GenericSystemCallError.new(e, "There was a conflict while creating the new gem.") - end - - private - - def resolve_name(name) - SharedHelpers.pwd.join(name).basename.to_s - end - - def ask_and_set(key, header, message) - choice = options[key] - choice = Bundler.settings["gem.#{key}"] if choice.nil? - - if choice.nil? - Bundler.ui.confirm header - choice = Bundler.ui.yes? "#{message} y/(n):" - Bundler.settings.set_global("gem.#{key}", choice) - end - - choice - end - - def validate_ext_name - return unless gem_name.index("-") - - Bundler.ui.error "You have specified a gem name which does not conform to the \n" \ - "naming guidelines for C extensions. For more information, \n" \ - "see the 'Extension Naming' section at the following URL:\n" \ - "http://guides.rubygems.org/gems-with-extensions/\n" - exit 1 - end - - def ask_and_set_test_framework - test_framework = options[:test] || Bundler.settings["gem.test"] - - if test_framework.nil? - Bundler.ui.confirm "Do you want to generate tests with your gem?" - result = Bundler.ui.ask "Type 'rspec' or 'minitest' to generate those test files now and " \ - "in the future. rspec/minitest/(none):" - if result =~ /rspec|minitest/ - test_framework = result - else - test_framework = false - end - end - - if Bundler.settings["gem.test"].nil? - Bundler.settings.set_global("gem.test", test_framework) - end - - test_framework - end - - def bundler_dependency_version - v = Gem::Version.new(Bundler::VERSION) - req = v.segments[0..1] - req << "a" if v.prerelease? - req.join(".") - end - - def ensure_safe_gem_name(name, constant_array) - if name =~ /^\d/ - Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." - exit 1 - end - - constant_name = constant_array.join("::") - - existing_constant = constant_array.inject(Object) do |c, s| - defined = begin - c.const_defined?(s) - rescue NameError - Bundler.ui.error "Invalid gem name #{name} -- `#{constant_name}` is an invalid constant name" - exit 1 - end - (defined && c.const_get(s)) || break - end - - return unless existing_constant - Bundler.ui.error "Invalid gem name #{name} constant #{constant_name} is already in use. Please choose another gem name." - exit 1 - end - - def open_editor(editor, file) - thor.run(%(#{editor} "#{file}")) - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/info.rb b/lib/ruby/stdlib/bundler/cli/info.rb deleted file mode 100644 index 958b5250677..00000000000 --- a/lib/ruby/stdlib/bundler/cli/info.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Info - attr_reader :gem_name, :options - def initialize(options, gem_name) - @options = options - @gem_name = gem_name - end - - def run - spec = spec_for_gem(gem_name) - - spec_not_found(gem_name) unless spec - return print_gem_path(spec) if @options[:path] - print_gem_info(spec) - end - - private - - def spec_for_gem(gem_name) - spec = Bundler.definition.specs.find {|s| s.name == gem_name } - spec || default_gem_spec(gem_name) - end - - def default_gem_spec(gem_name) - return unless Gem::Specification.respond_to?(:find_all_by_name) - gem_spec = Gem::Specification.find_all_by_name(gem_name).last - return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem? - end - - def spec_not_found(gem_name) - raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies) - end - - def print_gem_path(spec) - Bundler.ui.info spec.full_gem_path - end - - def print_gem_info(spec) - gem_info = String.new - gem_info << " * #{spec.name} (#{spec.version}#{spec.git_version})\n" - gem_info << "\tSummary: #{spec.summary}\n" if spec.summary - gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage - gem_info << "\tPath: #{spec.full_gem_path}\n" - gem_info << "\tDefault Gem: yes" if spec.respond_to?(:default_gem?) && spec.default_gem? - Bundler.ui.info gem_info - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/init.rb b/lib/ruby/stdlib/bundler/cli/init.rb deleted file mode 100644 index 40df7972693..00000000000 --- a/lib/ruby/stdlib/bundler/cli/init.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Init - attr_reader :options - def initialize(options) - @options = options - end - - def run - if File.exist?(gemfile) - Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}" - exit 1 - end - - unless File.writable?(Dir.pwd) - Bundler.ui.error "Can not create #{gemfile} as the current directory is not writable." - exit 1 - end - - if options[:gemspec] - gemspec = File.expand_path(options[:gemspec]) - unless File.exist?(gemspec) - Bundler.ui.error "Gem specification #{gemspec} doesn't exist" - exit 1 - end - - spec = Bundler.load_gemspec_uncached(gemspec) - - File.open(gemfile, "wb") do |file| - file << "# Generated from #{gemspec}\n" - file << spec.to_gemfile - end - else - FileUtils.cp(File.expand_path("../../templates/#{gemfile}", __FILE__), gemfile) - end - - puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" - end - - private - - def gemfile - @gemfile ||= Bundler.feature_flag.init_gems_rb? ? "gems.rb" : "Gemfile" - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/inject.rb b/lib/ruby/stdlib/bundler/cli/inject.rb deleted file mode 100644 index b00675d3488..00000000000 --- a/lib/ruby/stdlib/bundler/cli/inject.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Inject - attr_reader :options, :name, :version, :group, :source, :gems - def initialize(options, name, version) - @options = options - @name = name - @version = version || last_version_number - @group = options[:group].split(",") unless options[:group].nil? - @source = options[:source] - @gems = [] - end - - def run - # The required arguments allow Thor to give useful feedback when the arguments - # are incorrect. This adds those first two arguments onto the list as a whole. - gems.unshift(source).unshift(group).unshift(version).unshift(name) - - # Build an array of Dependency objects out of the arguments - deps = [] - # when `inject` support addition of more than one gem, then this loop will - # help. Currently this loop is running once. - gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source| - ops = Gem::Requirement::OPS.map {|key, _val| key } - has_op = ops.any? {|op| gem_version.start_with? op } - gem_version = "~> #{gem_version}" unless has_op - deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source) - end - - added = Injector.inject(deps, options) - - if added.any? - Bundler.ui.confirm "Added to Gemfile:" - Bundler.ui.confirm(added.map do |d| - name = "'#{d.name}'" - requirement = ", '#{d.requirement}'" - group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default) - source = ", :source => '#{d.source}'" unless d.source.nil? - %(gem #{name}#{requirement}#{group}#{source}) - end.join("\n")) - else - Bundler.ui.confirm "All gems were already present in the Gemfile" - end - end - - private - - def last_version_number - definition = Bundler.definition(true) - definition.resolve_remotely! - specs = definition.index[name].sort_by(&:version) - unless options[:pre] - specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } - end - spec = specs.last - spec.version.to_s - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/install.rb b/lib/ruby/stdlib/bundler/cli/install.rb deleted file mode 100644 index b40e5f0e9e8..00000000000 --- a/lib/ruby/stdlib/bundler/cli/install.rb +++ /dev/null @@ -1,217 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Install - attr_reader :options - def initialize(options) - @options = options - end - - def run - Bundler.ui.level = "error" if options[:quiet] - - warn_if_root - - normalize_groups - - Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD - - # Disable color in deployment mode - Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment] - - check_for_options_conflicts - - check_trust_policy - - if options[:deployment] || options[:frozen] || Bundler.frozen_bundle? - unless Bundler.default_lockfile.exist? - flag = "--deployment flag" if options[:deployment] - flag ||= "--frozen flag" if options[:frozen] - flag ||= "deployment setting" - raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \ - "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \ - "before deploying." - end - - options[:local] = true if Bundler.app_cache.exist? - - if Bundler.feature_flag.deployment_means_frozen? - Bundler.settings.set_command_option :deployment, true - else - Bundler.settings.set_command_option :frozen, true - end - end - - # When install is called with --no-deployment, disable deployment mode - if options[:deployment] == false - Bundler.settings.set_command_option :frozen, nil - options[:system] = true - end - - normalize_settings - - Bundler::Fetcher.disable_endpoint = options["full-index"] - - if options["binstubs"] - Bundler::SharedHelpers.major_deprecation 2, - "The --binstubs option will be removed in favor of `bundle binstubs`" - end - - Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? - - definition = Bundler.definition - definition.validate_runtime! - - installer = Installer.install(Bundler.root, definition, options) - Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? - - Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." - Bundler::CLI::Common.output_without_groups_message - - if Bundler.use_system_gems? - Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed." - else - relative_path = Bundler.configured_bundle_path.base_path_relative_to_pwd - Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`" - end - - Bundler::CLI::Common.output_post_install_messages installer.post_install_messages - - warn_ambiguous_gems - - if CLI::Common.clean_after_install? - require "bundler/cli/clean" - Bundler::CLI::Clean.new(options).run - end - rescue GemNotFound, VersionConflict => e - if options[:local] && Bundler.app_cache.exist? - Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory." - end - - unless Bundler.definition.has_rubygems_remotes? - Bundler.ui.warn <<-WARN, :wrap => true - Your Gemfile has no gem server sources. If you need gems that are \ - not already on your machine, add a line like this to your Gemfile: - source 'https://rubygems.org' - WARN - end - raise e - rescue Gem::InvalidSpecificationException => e - Bundler.ui.warn "You have one or more invalid gemspecs that need to be fixed." - raise e - end - - private - - def warn_if_root - return if Bundler.settings[:silence_root_warning] || Bundler::WINDOWS || !Process.uid.zero? - Bundler.ui.warn "Don't run Bundler as root. Bundler can ask for sudo " \ - "if it is needed, and installing your bundle as root will break this " \ - "application for all non-root users on this machine.", :wrap => true - end - - def dependencies_count_for(definition) - count = definition.dependencies.count - "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}" - end - - def gems_installed_for(definition) - count = definition.specs.count - "#{count} #{count == 1 ? "gem" : "gems"} now installed" - end - - def check_for_group_conflicts_in_cli_options - conflicting_groups = Array(options[:without]) & Array(options[:with]) - return if conflicting_groups.empty? - raise InvalidOption, "You can't list a group in both with and without." \ - " The offending groups are: #{conflicting_groups.join(", ")}." - end - - def check_for_options_conflicts - if (options[:path] || options[:deployment]) && options[:system] - error_message = String.new - error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path] - error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment] - raise InvalidOption.new(error_message) - end - end - - def check_trust_policy - trust_policy = options["trust-policy"] - unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy) - raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \ - "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." - end - Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy - end - - def normalize_groups - options[:with] &&= options[:with].join(":").tr(" ", ":").split(":") - options[:without] &&= options[:without].join(":").tr(" ", ":").split(":") - - check_for_group_conflicts_in_cli_options - - Bundler.settings.set_command_option :with, nil if options[:with] == [] - Bundler.settings.set_command_option :without, nil if options[:without] == [] - - with = options.fetch(:with, []) - with |= Bundler.settings[:with].map(&:to_s) - with -= options[:without] if options[:without] - - without = options.fetch(:without, []) - without |= Bundler.settings[:without].map(&:to_s) - without -= options[:with] if options[:with] - - options[:with] = with - options[:without] = without - end - - def normalize_settings - Bundler.settings.set_command_option :path, nil if options[:system] - Bundler.settings.temporary(:path_relative_to_cwd => false) do - Bundler.settings.set_command_option :path, "vendor/bundle" if options[:deployment] - end - Bundler.settings.set_command_option_if_given :path, options[:path] - Bundler.settings.temporary(:path_relative_to_cwd => false) do - Bundler.settings.set_command_option :path, "bundle" if options["standalone"] && Bundler.settings[:path].nil? - end - - bin_option = options["binstubs"] - bin_option = nil if bin_option && bin_option.empty? - Bundler.settings.set_command_option :bin, bin_option if options["binstubs"] - - Bundler.settings.set_command_option_if_given :shebang, options["shebang"] - - Bundler.settings.set_command_option_if_given :jobs, options["jobs"] - - Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] - - Bundler.settings.set_command_option_if_given :no_install, options["no-install"] - - Bundler.settings.set_command_option_if_given :clean, options["clean"] - - unless Bundler.settings[:without] == options[:without] && Bundler.settings[:with] == options[:with] - # need to nil them out first to get around validation for backwards compatibility - Bundler.settings.set_command_option :without, nil - Bundler.settings.set_command_option :with, nil - Bundler.settings.set_command_option :without, options[:without] - options[:with] - Bundler.settings.set_command_option :with, options[:with] - end - - options[:force] = options[:redownload] - end - - def warn_ambiguous_gems - Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| - Bundler.ui.error "Warning: the gem '#{name}' was found in multiple sources." - Bundler.ui.error "Installed from: #{installed_from_uri}" - Bundler.ui.error "Also found in:" - also_found_in_uris.each {|uri| Bundler.ui.error " * #{uri}" } - Bundler.ui.error "You should add a source requirement to restrict this gem to your preferred source." - Bundler.ui.error "For example:" - Bundler.ui.error " gem '#{name}', :source => '#{installed_from_uri}'" - Bundler.ui.error "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/issue.rb b/lib/ruby/stdlib/bundler/cli/issue.rb deleted file mode 100644 index 91f827ea99c..00000000000 --- a/lib/ruby/stdlib/bundler/cli/issue.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require "rbconfig" - -module Bundler - class CLI::Issue - def run - Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") - Did you find an issue with Bundler? Before filing a new issue, - be sure to check out these resources: - - 1. Check out our troubleshooting guide for quick fixes to common issues: - https://github.com/bundler/bundler/blob/master/doc/TROUBLESHOOTING.md - - 2. Instructions for common Bundler uses can be found on the documentation - site: http://bundler.io/ - - 3. Information about each Bundler command can be found in the Bundler - man pages: http://bundler.io/man/bundle.1.html - - Hopefully the troubleshooting steps above resolved your problem! If things - still aren't working the way you expect them to, please let us know so - that we can diagnose and help fix the problem you're having. Please - view the Filing Issues guide for more information: - https://github.com/bundler/bundler/blob/master/doc/contributing/ISSUES.md - - EOS - - Bundler.ui.info Bundler::Env.report - - Bundler.ui.info "\n## Bundle Doctor" - doctor - end - - def doctor - require "bundler/cli/doctor" - Bundler::CLI::Doctor.new({}).run - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/list.rb b/lib/ruby/stdlib/bundler/cli/list.rb deleted file mode 100644 index d1799196e78..00000000000 --- a/lib/ruby/stdlib/bundler/cli/list.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::List - def initialize(options) - @options = options - end - - def run - raise InvalidOption, "The `--only-group` and `--without-group` options cannot be used together" if @options["only-group"] && @options["without-group"] - - raise InvalidOption, "The `--name-only` and `--paths` options cannot be used together" if @options["name-only"] && @options[:paths] - - specs = if @options["only-group"] || @options["without-group"] - filtered_specs_by_groups - else - Bundler.load.specs - end.reject {|s| s.name == "bundler" }.sort_by(&:name) - - return Bundler.ui.info "No gems in the Gemfile" if specs.empty? - - return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"] - return specs.each {|s| Bundler.ui.info s.full_gem_path } if @options["paths"] - - Bundler.ui.info "Gems included by the bundle:" - - specs.each {|s| Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})" } - - Bundler.ui.info "Use `bundle info` to print more detailed information about a gem" - end - - private - - def verify_group_exists(groups) - raise InvalidOption, "`#{@options["without-group"]}` group could not be found." if @options["without-group"] && !groups.include?(@options["without-group"].to_sym) - - raise InvalidOption, "`#{@options["only-group"]}` group could not be found." if @options["only-group"] && !groups.include?(@options["only-group"].to_sym) - end - - def filtered_specs_by_groups - definition = Bundler.definition - groups = definition.groups - - verify_group_exists(groups) - - show_groups = - if @options["without-group"] - groups.reject {|g| g == @options["without-group"].to_sym } - elsif @options["only-group"] - groups.select {|g| g == @options["only-group"].to_sym } - else - groups - end.map(&:to_sym) - - definition.specs_for(show_groups) - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/lock.rb b/lib/ruby/stdlib/bundler/cli/lock.rb deleted file mode 100644 index 7dd078b1ef9..00000000000 --- a/lib/ruby/stdlib/bundler/cli/lock.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Lock - attr_reader :options - - def initialize(options) - @options = options - end - - def run - unless Bundler.default_gemfile - Bundler.ui.error "Unable to find a Gemfile to lock" - exit 1 - end - - print = options[:print] - ui = Bundler.ui - Bundler.ui = UI::Silent.new if print - - Bundler::Fetcher.disable_endpoint = options["full-index"] - - update = options[:update] - if update.is_a?(Array) # unlocking specific gems - Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) - update = { :gems => update, :lock_shared_dependencies => options[:conservative] } - end - definition = Bundler.definition(update) - - Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update] - - options["remove-platform"].each do |platform| - definition.remove_platform(platform) - end - - options["add-platform"].each do |platform_string| - platform = Gem::Platform.new(platform_string) - if platform.to_s == "unknown" - Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \ - "and adding it will likely lead to resolution errors" - end - definition.add_platform(platform) - end - - if definition.platforms.empty? - raise InvalidOption, "Removing all platforms from the bundle is not allowed" - end - - definition.resolve_remotely! unless options[:local] - - if print - puts definition.to_lock - else - file = options[:lockfile] - file = file ? File.expand_path(file) : Bundler.default_lockfile - puts "Writing lockfile to #{file}" - definition.lock(file) - end - - Bundler.ui = ui - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/open.rb b/lib/ruby/stdlib/bundler/cli/open.rb deleted file mode 100644 index 552fe6f128b..00000000000 --- a/lib/ruby/stdlib/bundler/cli/open.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require "shellwords" - -module Bundler - class CLI::Open - attr_reader :options, :name - def initialize(options, name) - @options = options - @name = name - end - - def run - editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } - return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor - return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) - path = spec.full_gem_path - Dir.chdir(path) do - command = Shellwords.split(editor) + [path] - Bundler.with_original_env do - system(*command) - end || Bundler.ui.info("Could not run '#{command.join(" ")}'") - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/outdated.rb b/lib/ruby/stdlib/bundler/cli/outdated.rb deleted file mode 100644 index 2ca90293db0..00000000000 --- a/lib/ruby/stdlib/bundler/cli/outdated.rb +++ /dev/null @@ -1,266 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Outdated - attr_reader :options, :gems - - def initialize(options, gems) - @options = options - @gems = gems - end - - def run - check_for_deployment_mode - - sources = Array(options[:source]) - - gems.each do |gem_name| - Bundler::CLI::Common.select_spec(gem_name) - end - - Bundler.definition.validate_runtime! - current_specs = Bundler.ui.silence { Bundler.definition.resolve } - current_dependencies = {} - Bundler.ui.silence do - Bundler.load.dependencies.each do |dep| - current_dependencies[dep.name] = dep - end - end - - definition = if gems.empty? && sources.empty? - # We're doing a full update - Bundler.definition(true) - else - Bundler.definition(:gems => gems, :sources => sources) - end - - Bundler::CLI::Common.configure_gem_version_promoter( - Bundler.definition, - options - ) - - # the patch level options imply strict is also true. It wouldn't make - # sense otherwise. - strict = options[:strict] || - Bundler::CLI::Common.patch_level_options(options).any? - - filter_options_patch = options.keys & - %w[filter-major filter-minor filter-patch] - - definition_resolution = proc do - options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! - end - - if options[:parseable] - Bundler.ui.silence(&definition_resolution) - else - definition_resolution.call - end - - Bundler.ui.info "" - outdated_gems_by_groups = {} - outdated_gems_list = [] - - # Loop through the current specs - gemfile_specs, dependency_specs = current_specs.partition do |spec| - current_dependencies.key? spec.name - end - - specs = if options["only-explicit"] - gemfile_specs - else - gemfile_specs + dependency_specs - end - - specs.sort_by(&:name).each do |current_spec| - next if !gems.empty? && !gems.include?(current_spec.name) - - dependency = current_dependencies[current_spec.name] - active_spec = retrieve_active_spec(strict, definition, current_spec) - - next if active_spec.nil? - if filter_options_patch.any? - update_present = update_present_via_semver_portions(current_spec, active_spec, options) - next unless update_present - end - - gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) - next unless gem_outdated || (current_spec.git_version != active_spec.git_version) - groups = nil - if dependency && !options[:parseable] - groups = dependency.groups.join(", ") - end - - outdated_gems_list << { :active_spec => active_spec, - :current_spec => current_spec, - :dependency => dependency, - :groups => groups } - - outdated_gems_by_groups[groups] ||= [] - outdated_gems_by_groups[groups] << { :active_spec => active_spec, - :current_spec => current_spec, - :dependency => dependency, - :groups => groups } - end - - if outdated_gems_list.empty? - display_nothing_outdated_message(filter_options_patch) - else - unless options[:parseable] - if options[:pre] - Bundler.ui.info "Outdated gems included in the bundle (including " \ - "pre-releases):" - else - Bundler.ui.info "Outdated gems included in the bundle:" - end - end - - options_include_groups = [:group, :groups].select do |v| - options.keys.include?(v.to_s) - end - - if options_include_groups.any? - ordered_groups = outdated_gems_by_groups.keys.compact.sort - [nil, ordered_groups].flatten.each do |groups| - gems = outdated_gems_by_groups[groups] - contains_group = if groups - groups.split(",").include?(options[:group]) - else - options[:group] == "group" - end - - next if (!options[:groups] && !contains_group) || gems.nil? - - unless options[:parseable] - if groups - Bundler.ui.info "===== Group #{groups} =====" - else - Bundler.ui.info "===== Without group =====" - end - end - - gems.each do |gem| - print_gem( - gem[:current_spec], - gem[:active_spec], - gem[:dependency], - groups, - options_include_groups.any? - ) - end - end - else - outdated_gems_list.each do |gem| - print_gem( - gem[:current_spec], - gem[:active_spec], - gem[:dependency], - gem[:groups], - options_include_groups.any? - ) - end - end - - exit 1 - end - end - - private - - def retrieve_active_spec(strict, definition, current_spec) - if strict - active_spec = definition.find_resolved_spec(current_spec) - else - active_specs = definition.find_indexed_specs(current_spec) - if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 - active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } - end - active_spec = active_specs.last - end - - active_spec - end - - def display_nothing_outdated_message(filter_options_patch) - unless options[:parseable] - if filter_options_patch.any? - display = filter_options_patch.map do |o| - o.sub("filter-", "") - end.join(" or ") - - Bundler.ui.info "No #{display} updates to display.\n" - else - Bundler.ui.info "Bundle up to date!\n" - end - end - end - - def print_gem(current_spec, active_spec, dependency, groups, options_include_groups) - spec_version = "#{active_spec.version}#{active_spec.git_version}" - spec_version += " (from #{active_spec.loaded_from})" if Bundler.ui.debug? && active_spec.loaded_from - current_version = "#{current_spec.version}#{current_spec.git_version}" - - if dependency && dependency.specific? - dependency_version = %(, requested #{dependency.requirement}) - end - - spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \ - "installed #{current_version}#{dependency_version})" - - output_message = if options[:parseable] - spec_outdated_info.to_s - elsif options_include_groups || !groups - " * #{spec_outdated_info}" - else - " * #{spec_outdated_info} in groups \"#{groups}\"" - end - - Bundler.ui.info output_message.rstrip - end - - def check_for_deployment_mode - return unless Bundler.frozen_bundle? - suggested_command = if Bundler.settings.locations("frozen")[:global] - "bundle config --delete frozen" - elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? - "bundle config --delete deployment" - else - "bundle install --no-deployment" - end - raise ProductionError, "You are trying to check outdated gems in " \ - "deployment mode. Run `bundle outdated` elsewhere.\n" \ - "\nIf this is a development machine, remove the " \ - "#{Bundler.default_gemfile} freeze" \ - "\nby running `#{suggested_command}`." - end - - def update_present_via_semver_portions(current_spec, active_spec, options) - current_major = current_spec.version.segments.first - active_major = active_spec.version.segments.first - - update_present = false - update_present = active_major > current_major if options["filter-major"] - - if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major - current_minor = get_version_semver_portion_value(current_spec, 1) - active_minor = get_version_semver_portion_value(active_spec, 1) - - update_present = active_minor > current_minor if options["filter-minor"] - - if !update_present && options["filter-patch"] && current_minor == active_minor - current_patch = get_version_semver_portion_value(current_spec, 2) - active_patch = get_version_semver_portion_value(active_spec, 2) - - update_present = active_patch > current_patch - end - end - - update_present - end - - def get_version_semver_portion_value(spec, version_portion_index) - version_section = spec.version.segments[version_portion_index, 1] - version_section.nil? ? 0 : (version_section.first || 0) - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/package.rb b/lib/ruby/stdlib/bundler/cli/package.rb deleted file mode 100644 index 2dcd0e1e29c..00000000000 --- a/lib/ruby/stdlib/bundler/cli/package.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Package - attr_reader :options - - def initialize(options) - @options = options - end - - def run - Bundler.ui.level = "error" if options[:quiet] - Bundler.settings.set_command_option_if_given :path, options[:path] - Bundler.settings.set_command_option_if_given :cache_all_platforms, options["all-platforms"] - Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"] - - setup_cache_all - install - - # TODO: move cache contents here now that all bundles are locked - custom_path = Bundler.settings[:path] if options[:path] - Bundler.load.cache(custom_path) - end - - private - - def install - require "bundler/cli/install" - options = self.options.dup - if Bundler.settings[:cache_all_platforms] - options["local"] = false - options["update"] = true - end - Bundler::CLI::Install.new(options).run - end - - def setup_cache_all - all = options.fetch(:all, Bundler.feature_flag.cache_command_is_package? || nil) - - Bundler.settings.set_command_option_if_given :cache_all, all - - if Bundler.definition.has_local_dependencies? && !Bundler.feature_flag.cache_all? - Bundler.ui.warn "Your Gemfile contains path and git dependencies. If you want " \ - "to package them as well, please pass the --all flag. This will be the default " \ - "on Bundler 2.0." - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/platform.rb b/lib/ruby/stdlib/bundler/cli/platform.rb deleted file mode 100644 index e97cad49a4c..00000000000 --- a/lib/ruby/stdlib/bundler/cli/platform.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Platform - attr_reader :options - def initialize(options) - @options = options - end - - def run - platforms, ruby_version = Bundler.ui.silence do - locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version - gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string - [Bundler.definition.platforms.map {|p| "* #{p}" }, - locked_ruby_version || gemfile_ruby_version] - end - output = [] - - if options[:ruby] - if ruby_version - output << ruby_version - else - output << "No ruby version specified" - end - else - output << "Your platform is: #{RUBY_PLATFORM}" - output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" - - if ruby_version - output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" - - begin - Bundler.definition.validate_runtime! - output << "Your current platform satisfies the Ruby version requirement." - rescue RubyVersionMismatch => e - output << e.message - end - else - output << "Your Gemfile does not specify a Ruby version requirement." - end - end - - Bundler.ui.info output.join("\n\n") - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/plugin.rb b/lib/ruby/stdlib/bundler/cli/plugin.rb deleted file mode 100644 index 5488a9f28db..00000000000 --- a/lib/ruby/stdlib/bundler/cli/plugin.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_thor" -module Bundler - class CLI::Plugin < Thor - desc "install PLUGINS", "Install the plugin from the source" - long_desc <<-D - Install plugins either from the rubygems source provided (with --source option) or from a git source provided with (--git option). If no sources are provided, it uses Gem.sources - D - method_option "source", :type => :string, :default => nil, :banner => - "URL of the RubyGems source to fetch the plugin from" - method_option "version", :type => :string, :default => nil, :banner => - "The version of the plugin to fetch" - method_option "git", :type => :string, :default => nil, :banner => - "URL of the git repo to fetch from" - method_option "branch", :type => :string, :default => nil, :banner => - "The git branch to checkout" - method_option "ref", :type => :string, :default => nil, :banner => - "The git revision to check out" - def install(*plugins) - Bundler::Plugin.install(plugins, options) - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/pristine.rb b/lib/ruby/stdlib/bundler/cli/pristine.rb deleted file mode 100644 index 4a411a83fc7..00000000000 --- a/lib/ruby/stdlib/bundler/cli/pristine.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Pristine - def initialize(gems) - @gems = gems - end - - def run - CLI::Common.ensure_all_gems_in_lockfile!(@gems) - definition = Bundler.definition - definition.validate_runtime! - installer = Bundler::Installer.new(Bundler.root, definition) - - Bundler.load.specs.each do |spec| - next if spec.name == "bundler" # Source::Rubygems doesn't install bundler - next if !@gems.empty? && !@gems.include?(spec.name) - - gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" - gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY - - case source = spec.source - when Source::Rubygems - cached_gem = spec.cache_file - unless File.exist?(cached_gem) - Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") - next - end - - FileUtils.rm_rf spec.full_gem_path - when Source::Git - source.remote! - if extension_cache_path = source.extension_cache_path(spec) - FileUtils.rm_rf extension_cache_path - end - FileUtils.rm_rf spec.extension_dir if spec.respond_to?(:extension_dir) - FileUtils.rm_rf spec.full_gem_path - else - Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") - next - end - - Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/remove.rb b/lib/ruby/stdlib/bundler/cli/remove.rb deleted file mode 100644 index cd6a2cec281..00000000000 --- a/lib/ruby/stdlib/bundler/cli/remove.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Remove - def initialize(gems, options) - @gems = gems - @options = options - end - - def run - raise InvalidOption, "Please specify gems to remove." if @gems.empty? - - Injector.remove(@gems, {}) - - Installer.install(Bundler.root, Bundler.definition) if @options["install"] - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/show.rb b/lib/ruby/stdlib/bundler/cli/show.rb deleted file mode 100644 index 61756801b2f..00000000000 --- a/lib/ruby/stdlib/bundler/cli/show.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Show - attr_reader :options, :gem_name, :latest_specs - def initialize(options, gem_name) - @options = options - @gem_name = gem_name - @verbose = options[:verbose] || options[:outdated] - @latest_specs = fetch_latest_specs if @verbose - end - - def run - Bundler.ui.silence do - Bundler.definition.validate_runtime! - Bundler.load.lock - end - - if gem_name - if gem_name == "bundler" - path = File.expand_path("../../../..", __FILE__) - else - spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match) - return unless spec - path = spec.full_gem_path - unless File.directory?(path) - Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at:" - end - end - return Bundler.ui.info(path) - end - - if options[:paths] - Bundler.load.specs.sort_by(&:name).map do |s| - Bundler.ui.info s.full_gem_path - end - else - Bundler.ui.info "Gems included by the bundle:" - Bundler.load.specs.sort_by(&:name).each do |s| - desc = " * #{s.name} (#{s.version}#{s.git_version})" - if @verbose - latest = latest_specs.find {|l| l.name == s.name } - Bundler.ui.info <<-END.gsub(/^ +/, "") - #{desc} - \tSummary: #{s.summary || "No description available."} - \tHomepage: #{s.homepage || "No website available."} - \tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"} - END - else - Bundler.ui.info desc - end - end - end - end - - private - - def fetch_latest_specs - definition = Bundler.definition(true) - if options[:outdated] - Bundler.ui.info "Fetching remote specs for outdated check...\n\n" - Bundler.ui.silence { definition.resolve_remotely! } - else - definition.resolve_with_cache! - end - Bundler.reset! - definition.specs - end - - def outdated?(current, latest) - return false unless latest - Gem::Version.new(current.version) < Gem::Version.new(latest.version) - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/update.rb b/lib/ruby/stdlib/bundler/cli/update.rb deleted file mode 100644 index b088853768f..00000000000 --- a/lib/ruby/stdlib/bundler/cli/update.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Update - attr_reader :options, :gems - def initialize(options, gems) - @options = options - @gems = gems - end - - def run - Bundler.ui.level = "error" if options[:quiet] - - Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? - - sources = Array(options[:source]) - groups = Array(options[:group]).map(&:to_sym) - - full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !options[:bundler] - - if full_update && !options[:all] - if Bundler.feature_flag.update_requires_all_flag? - raise InvalidOption, "To update everything, pass the `--all` flag." - end - SharedHelpers.major_deprecation 2, "Pass --all to `bundle update` to update everything" - elsif !full_update && options[:all] - raise InvalidOption, "Cannot specify --all along with specific options." - end - - if full_update - # We're doing a full update - Bundler.definition(true) - else - unless Bundler.default_lockfile.exist? - raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ - "Run `bundle install` to update and install the bundled gems." - end - Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems) - - if groups.any? - deps = Bundler.definition.dependencies.select {|d| (d.groups & groups).any? } - gems.concat(deps.map(&:name)) - end - - Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], - :lock_shared_dependencies => options[:conservative], - :bundler => options[:bundler]) - end - - Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) - - Bundler::Fetcher.disable_endpoint = options["full-index"] - - opts = options.dup - opts["update"] = true - opts["local"] = options[:local] - - Bundler.settings.set_command_option_if_given :jobs, opts["jobs"] - - Bundler.definition.validate_runtime! - installer = Installer.install Bundler.root, Bundler.definition, opts - Bundler.load.cache if Bundler.app_cache.exist? - - if CLI::Common.clean_after_install? - require "bundler/cli/clean" - Bundler::CLI::Clean.new(options).run - end - - if locked_gems = Bundler.definition.locked_gems - gems.each do |name| - locked_version = locked_gems.specs.find {|s| s.name == name } - locked_version &&= locked_version.version - next unless locked_version - new_version = Bundler.definition.specs[name].first - new_version &&= new_version.version - if !new_version - Bundler.ui.warn "Bundler attempted to update #{name} but it was removed from the bundle" - elsif new_version < locked_version - Bundler.ui.warn "Note: #{name} version regressed from #{locked_version} to #{new_version}" - elsif new_version == locked_version - Bundler.ui.warn "Bundler attempted to update #{name} but its version stayed the same" - end - end - end - - Bundler.ui.confirm "Bundle updated!" - Bundler::CLI::Common.output_without_groups_message - Bundler::CLI::Common.output_post_install_messages installer.post_install_messages - end - end -end diff --git a/lib/ruby/stdlib/bundler/cli/viz.rb b/lib/ruby/stdlib/bundler/cli/viz.rb deleted file mode 100644 index 644f9b25cf7..00000000000 --- a/lib/ruby/stdlib/bundler/cli/viz.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CLI::Viz - attr_reader :options, :gem_name - def initialize(options) - @options = options - end - - def run - # make sure we get the right `graphviz`. There is also a `graphviz` - # gem we're not built to support - gem "ruby-graphviz" - require "graphviz" - - options[:without] = options[:without].join(":").tr(" ", ":").split(":") - output_file = File.expand_path(options[:file]) - - graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without]) - graph.viz - rescue LoadError => e - Bundler.ui.error e.inspect - Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" - Bundler.ui.warn "`gem install ruby-graphviz`" - rescue StandardError => e - raise unless e.message =~ /GraphViz not installed or dot not in PATH/ - Bundler.ui.error e.message - Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." - end - end -end diff --git a/lib/ruby/stdlib/bundler/compact_index_client.rb b/lib/ruby/stdlib/bundler/compact_index_client.rb deleted file mode 100644 index 6c241ca07a0..00000000000 --- a/lib/ruby/stdlib/bundler/compact_index_client.rb +++ /dev/null @@ -1,109 +0,0 @@ -# frozen_string_literal: true - -require "pathname" -require "set" - -module Bundler - class CompactIndexClient - DEBUG_MUTEX = Mutex.new - def self.debug - return unless ENV["DEBUG_COMPACT_INDEX"] - DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") } - end - - class Error < StandardError; end - - require "bundler/compact_index_client/cache" - require "bundler/compact_index_client/updater" - - attr_reader :directory - - # @return [Lambda] A lambda that takes an array of inputs and a block, and - # maps the inputs with the block in parallel. - # - attr_accessor :in_parallel - - def initialize(directory, fetcher) - @directory = Pathname.new(directory) - @updater = Updater.new(fetcher) - @cache = Cache.new(@directory) - @endpoints = Set.new - @info_checksums_by_name = {} - @parsed_checksums = false - @mutex = Mutex.new - @in_parallel = lambda do |inputs, &blk| - inputs.map(&blk) - end - end - - def names - Bundler::CompactIndexClient.debug { "/names" } - update(@cache.names_path, "names") - @cache.names - end - - def versions - Bundler::CompactIndexClient.debug { "/versions" } - update(@cache.versions_path, "versions") - versions, @info_checksums_by_name = @cache.versions - versions - end - - def dependencies(names) - Bundler::CompactIndexClient.debug { "dependencies(#{names})" } - in_parallel.call(names) do |name| - update_info(name) - @cache.dependencies(name).map {|d| d.unshift(name) } - end.flatten(1) - end - - def spec(name, version, platform = nil) - Bundler::CompactIndexClient.debug { "spec(name = #{name}, version = #{version}, platform = #{platform})" } - update_info(name) - @cache.specific_dependency(name, version, platform) - end - - def update_and_parse_checksums! - Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" } - return @info_checksums_by_name if @parsed_checksums - update(@cache.versions_path, "versions") - @info_checksums_by_name = @cache.checksums - @parsed_checksums = true - end - - private - - def update(local_path, remote_path) - Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" } - unless synchronize { @endpoints.add?(remote_path) } - Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" } - return - end - @updater.update(local_path, url(remote_path)) - end - - def update_info(name) - Bundler::CompactIndexClient.debug { "update_info(#{name})" } - path = @cache.info_path(name) - checksum = @updater.checksum_for_file(path) - unless existing = @info_checksums_by_name[name] - Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" } - return - end - if checksum == existing - Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" } - return - end - Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" } - update(path, "info/#{name}") - end - - def url(path) - path - end - - def synchronize - @mutex.synchronize { yield } - end - end -end diff --git a/lib/ruby/stdlib/bundler/compact_index_client/cache.rb b/lib/ruby/stdlib/bundler/compact_index_client/cache.rb deleted file mode 100644 index f6105d3bb3a..00000000000 --- a/lib/ruby/stdlib/bundler/compact_index_client/cache.rb +++ /dev/null @@ -1,118 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class CompactIndexClient - class Cache - attr_reader :directory - - def initialize(directory) - @directory = Pathname.new(directory).expand_path - info_roots.each do |dir| - SharedHelpers.filesystem_access(dir) do - FileUtils.mkdir_p(dir) - end - end - end - - def names - lines(names_path) - end - - def names_path - directory.join("names") - end - - def versions - versions_by_name = Hash.new {|hash, key| hash[key] = [] } - info_checksums_by_name = {} - - lines(versions_path).each do |line| - name, versions_string, info_checksum = line.split(" ", 3) - info_checksums_by_name[name] = info_checksum || "" - versions_string.split(",").each do |version| - if version.start_with?("-") - version = version[1..-1].split("-", 2).unshift(name) - versions_by_name[name].delete(version) - else - version = version.split("-", 2).unshift(name) - versions_by_name[name] << version - end - end - end - - [versions_by_name, info_checksums_by_name] - end - - def versions_path - directory.join("versions") - end - - def checksums - checksums = {} - - lines(versions_path).each do |line| - name, _, checksum = line.split(" ", 3) - checksums[name] = checksum - end - - checksums - end - - def dependencies(name) - lines(info_path(name)).map do |line| - parse_gem(line) - end - end - - def info_path(name) - name = name.to_s - if name =~ /[^a-z0-9_-]/ - name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}" - info_roots.last.join(name) - else - info_roots.first.join(name) - end - end - - def specific_dependency(name, version, platform) - pattern = [version, platform].compact.join("-") - return nil if pattern.empty? - - gem_lines = info_path(name).read - gem_line = gem_lines[/^#{Regexp.escape(pattern)}\b.*/, 0] - gem_line ? parse_gem(gem_line) : nil - end - - private - - def lines(path) - return [] unless path.file? - lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n") - header = lines.index("---") - header ? lines[header + 1..-1] : lines - end - - def parse_gem(string) - version_and_platform, rest = string.split(" ", 2) - version, platform = version_and_platform.split("-", 2) - dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest - dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : [] - requirements = requirements ? requirements.map {|r| parse_dependency(r) } : [] - [version, platform, dependencies, requirements] - end - - def parse_dependency(string) - dependency = string.split(":") - dependency[-1] = dependency[-1].split("&") if dependency.size > 1 - dependency - end - - def info_roots - [ - directory.join("info"), - directory.join("info-special-characters"), - ] - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/compact_index_client/updater.rb b/lib/ruby/stdlib/bundler/compact_index_client/updater.rb deleted file mode 100644 index 4d6eb800446..00000000000 --- a/lib/ruby/stdlib/bundler/compact_index_client/updater.rb +++ /dev/null @@ -1,116 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_fileutils" -require "stringio" -require "zlib" - -module Bundler - class CompactIndexClient - class Updater - class MisMatchedChecksumError < Error - def initialize(path, server_checksum, local_checksum) - @path = path - @server_checksum = server_checksum - @local_checksum = local_checksum - end - - def message - "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \ - "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})." - end - end - - def initialize(fetcher) - @fetcher = fetcher - require "tmpdir" - end - - def update(local_path, remote_path, retrying = nil) - headers = {} - - Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir| - local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename) - - # first try to fetch any new bytes on the existing file - if retrying.nil? && local_path.file? - SharedHelpers.filesystem_access(local_temp_path) do - FileUtils.cp local_path, local_temp_path - end - headers["If-None-Match"] = etag_for(local_temp_path) - headers["Range"] = - if local_temp_path.size.nonzero? - # Subtract a byte to ensure the range won't be empty. - # Avoids 416 (Range Not Satisfiable) responses. - "bytes=#{local_temp_path.size - 1}-" - else - "bytes=#{local_temp_path.size}-" - end - else - # Fastly ignores Range when Accept-Encoding: gzip is set - headers["Accept-Encoding"] = "gzip" - end - - response = @fetcher.call(remote_path, headers) - return nil if response.is_a?(Net::HTTPNotModified) - - content = response.body - if response["Content-Encoding"] == "gzip" - content = Zlib::GzipReader.new(StringIO.new(content)).read - end - - SharedHelpers.filesystem_access(local_temp_path) do - if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero? - local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) } - else - local_temp_path.open("w") {|f| f << content } - end - end - - response_etag = (response["ETag"] || "").gsub(%r{\AW/}, "") - if etag_for(local_temp_path) == response_etag - SharedHelpers.filesystem_access(local_path) do - FileUtils.mv(local_temp_path, local_path) - end - return nil - end - - if retrying - raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path)) - end - - update(local_path, remote_path, :retrying) - end - rescue Errno::EACCES - raise Bundler::PermissionError, - "Bundler does not have write access to create a temp directory " \ - "within #{Dir.tmpdir}. Bundler must have write access to your " \ - "systems temp directory to function properly. " - rescue Zlib::GzipFile::Error - raise Bundler::HTTPError - end - - def etag_for(path) - sum = checksum_for_file(path) - sum ? %("#{sum}") : nil - end - - def slice_body(body, range) - if body.respond_to?(:byteslice) - body.byteslice(range) - else # pre-1.9.3 - body.unpack("@#{range.first}a#{range.end + 1}").first - end - end - - def checksum_for_file(path) - return nil unless path.file? - # This must use IO.read instead of Digest.file().hexdigest - # because we need to preserve \n line endings on windows when calculating - # the checksum - SharedHelpers.filesystem_access(path, :read) do - SharedHelpers.digest(:MD5).hexdigest(IO.read(path)) - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/compatibility_guard.rb b/lib/ruby/stdlib/bundler/compatibility_guard.rb deleted file mode 100644 index 750a1db04fb..00000000000 --- a/lib/ruby/stdlib/bundler/compatibility_guard.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: false - -require "rubygems" -require "bundler/version" - -if Bundler::VERSION.split(".").first.to_i >= 2 - if Gem::Version.new(Object::RUBY_VERSION.dup) < Gem::Version.new("2.3") - abort "Bundler 2 requires Ruby 2.3 or later. Either install bundler 1 or update to a supported Ruby version." - end - - if Gem::Version.new(Gem::VERSION.dup) < Gem::Version.new("2.5") - abort "Bundler 2 requires RubyGems 2.5 or later. Either install bundler 1 or update to a supported RubyGems version." - end -end diff --git a/lib/ruby/stdlib/bundler/constants.rb b/lib/ruby/stdlib/bundler/constants.rb deleted file mode 100644 index 2e4ebb37ee6..00000000000 --- a/lib/ruby/stdlib/bundler/constants.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module Bundler - WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ - FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/ - NULL = WINDOWS ? "NUL" : "/dev/null" -end diff --git a/lib/ruby/stdlib/bundler/current_ruby.rb b/lib/ruby/stdlib/bundler/current_ruby.rb deleted file mode 100644 index d5efaad6c52..00000000000 --- a/lib/ruby/stdlib/bundler/current_ruby.rb +++ /dev/null @@ -1,93 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # Returns current version of Ruby - # - # @return [CurrentRuby] Current version of Ruby - def self.current_ruby - @current_ruby ||= CurrentRuby.new - end - - class CurrentRuby - KNOWN_MINOR_VERSIONS = %w[ - 1.8 - 1.9 - 2.0 - 2.1 - 2.2 - 2.3 - 2.4 - 2.5 - 2.6 - ].freeze - - KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze - - KNOWN_PLATFORMS = %w[ - jruby - maglev - mingw - mri - mswin - mswin64 - rbx - ruby - truffleruby - x64_mingw - ].freeze - - def ruby? - !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || - RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby") - end - - def mri? - !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby") - end - - def rbx? - ruby? && defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx" - end - - def jruby? - defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby" - end - - def maglev? - defined?(RUBY_ENGINE) && RUBY_ENGINE == "maglev" - end - - def truffleruby? - defined?(RUBY_ENGINE) && RUBY_ENGINE == "truffleruby" - end - - def mswin? - Bundler::WINDOWS - end - - def mswin64? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64" - end - - def mingw? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64" - end - - def x64_mingw? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64" - end - - (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version| - trimmed_version = version.tr(".", "") - define_method(:"on_#{trimmed_version}?") do - RUBY_VERSION.start_with?("#{version}.") - end - - KNOWN_PLATFORMS.each do |platform| - define_method(:"#{platform}_#{trimmed_version}?") do - send(:"#{platform}?") && send(:"on_#{trimmed_version}?") - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/definition.rb b/lib/ruby/stdlib/bundler/definition.rb deleted file mode 100644 index 8e56d4a9bcc..00000000000 --- a/lib/ruby/stdlib/bundler/definition.rb +++ /dev/null @@ -1,993 +0,0 @@ -# frozen_string_literal: true - -require "bundler/lockfile_parser" -require "set" - -module Bundler - class Definition - include GemHelpers - - attr_reader( - :dependencies, - :locked_deps, - :locked_gems, - :platforms, - :requires, - :ruby_version, - :lockfile, - :gemfiles - ) - - # Given a gemfile and lockfile creates a Bundler definition - # - # @param gemfile [Pathname] Path to Gemfile - # @param lockfile [Pathname,nil] Path to Gemfile.lock - # @param unlock [Hash, Boolean, nil] Gems that have been requested - # to be updated or true if all gems should be updated - # @return [Bundler::Definition] - def self.build(gemfile, lockfile, unlock) - unlock ||= {} - gemfile = Pathname.new(gemfile).expand_path - - raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file? - - Dsl.evaluate(gemfile, lockfile, unlock) - end - - # - # How does the new system work? - # - # * Load information from Gemfile and Lockfile - # * Invalidate stale locked specs - # * All specs from stale source are stale - # * All specs that are reachable only through a stale - # dependency are stale. - # * If all fresh dependencies are satisfied by the locked - # specs, then we can try to resolve locally. - # - # @param lockfile [Pathname] Path to Gemfile.lock - # @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile - # @param sources [Bundler::SourceList] - # @param unlock [Hash, Boolean, nil] Gems that have been requested - # to be updated or true if all gems should be updated - # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version - # @param optional_groups [Array(String)] A list of optional groups - def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) - if [true, false].include?(unlock) - @unlocking_bundler = false - @unlocking = unlock - else - unlock = unlock.dup - @unlocking_bundler = unlock.delete(:bundler) - unlock.delete_if {|_k, v| Array(v).empty? } - @unlocking = !unlock.empty? - end - - @dependencies = dependencies - @sources = sources - @unlock = unlock - @optional_groups = optional_groups - @remote = false - @specs = nil - @ruby_version = ruby_version - @gemfiles = gemfiles - - @lockfile = lockfile - @lockfile_contents = String.new - @locked_bundler_version = nil - @locked_ruby_version = nil - @locked_specs_incomplete_for_platform = false - - if lockfile && File.exist?(lockfile) - @lockfile_contents = Bundler.read_file(lockfile) - @locked_gems = LockfileParser.new(@lockfile_contents) - @locked_platforms = @locked_gems.platforms - @platforms = @locked_platforms.dup - @locked_bundler_version = @locked_gems.bundler_version - @locked_ruby_version = @locked_gems.ruby_version - - if unlock != true - @locked_deps = @locked_gems.dependencies - @locked_specs = SpecSet.new(@locked_gems.specs) - @locked_sources = @locked_gems.sources - else - @unlock = {} - @locked_deps = {} - @locked_specs = SpecSet.new([]) - @locked_sources = [] - end - else - @unlock = {} - @platforms = [] - @locked_gems = nil - @locked_deps = {} - @locked_specs = SpecSet.new([]) - @locked_sources = [] - @locked_platforms = [] - end - - @unlock[:gems] ||= [] - @unlock[:sources] ||= [] - @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object - @ruby_version.diff(locked_ruby_version_object) - end - @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) - - add_current_platform unless Bundler.frozen_bundle? - - converge_path_sources_to_gemspec_sources - @path_changes = converge_paths - @source_changes = converge_sources - - unless @unlock[:lock_shared_dependencies] - eager_unlock = expand_dependencies(@unlock[:gems], true) - @unlock[:gems] = @locked_specs.for(eager_unlock, [], false, false, false).map(&:name) - end - - @dependency_changes = converge_dependencies - @local_changes = converge_locals - - @requires = compute_requires - end - - def gem_version_promoter - @gem_version_promoter ||= begin - locked_specs = - if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty? - # Definition uses an empty set of locked_specs to indicate all gems - # are unlocked, but GemVersionPromoter needs the locked_specs - # for conservative comparison. - Bundler::SpecSet.new(@locked_gems.specs) - else - @locked_specs - end - GemVersionPromoter.new(locked_specs, @unlock[:gems]) - end - end - - def resolve_with_cache! - raise "Specs already loaded" if @specs - sources.cached! - specs - end - - def resolve_remotely! - raise "Specs already loaded" if @specs - @remote = true - sources.remote! - specs - end - - # For given dependency list returns a SpecSet with Gemspec of all the required - # dependencies. - # 1. The method first resolves the dependencies specified in Gemfile - # 2. After that it tries and fetches gemspec of resolved dependencies - # - # @return [Bundler::SpecSet] - def specs - @specs ||= begin - begin - specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies) - rescue GemNotFound => e # Handle yanked gem - gem_name, gem_version = extract_gem_info(e) - locked_gem = @locked_specs[gem_name].last - raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote - raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \ - "be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \ - "that means the author of #{locked_gem} has removed it. You'll need to update your bundle " \ - "to a version other than #{locked_gem} that hasn't been removed in order to install." - end - unless specs["bundler"].any? - bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last - specs["bundler"] = bundler - end - - specs - end - end - - def new_specs - specs - @locked_specs - end - - def removed_specs - @locked_specs - specs - end - - def new_platform? - @new_platform - end - - def missing_specs - missing = [] - resolve.materialize(requested_dependencies, missing) - missing - end - - def missing_specs? - missing = missing_specs - return false if missing.empty? - Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" - true - rescue BundlerError => e - @index = nil - @resolve = nil - @specs = nil - @gem_version_promoter = nil - - Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})" - true - end - - def requested_specs - @requested_specs ||= begin - groups = requested_groups - groups.map!(&:to_sym) - specs_for(groups) - end - end - - def current_dependencies - dependencies.select(&:should_include?) - end - - def specs_for(groups) - deps = dependencies.select {|d| (d.groups & groups).any? } - deps.delete_if {|d| !d.should_include? } - specs.for(expand_dependencies(deps)) - end - - # Resolve all the dependencies specified in Gemfile. It ensures that - # dependencies that have been already resolved via locked file and are fresh - # are reused when resolving dependencies - # - # @return [SpecSet] resolved dependencies - def resolve - @resolve ||= begin - last_resolve = converge_locked_specs - resolve = - if Bundler.frozen_bundle? - Bundler.ui.debug "Frozen, using resolution from the lockfile" - last_resolve - elsif !unlocking? && nothing_changed? - Bundler.ui.debug("Found no changes, using resolution from the lockfile") - last_resolve - else - # Run a resolve against the locally available gems - Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") - last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) - end - - # filter out gems that _can_ be installed on multiple platforms, but don't need - # to be - resolve.for(expand_dependencies(dependencies, true), [], false, false, false) - end - end - - def index - @index ||= Index.build do |idx| - dependency_names = @dependencies.map(&:name) - - sources.all_sources.each do |source| - source.dependency_names = dependency_names - pinned_spec_names(source) - idx.add_source source.specs - dependency_names.concat(source.unmet_deps).uniq! - end - - double_check_for_index(idx, dependency_names) - end - end - - # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both - # sources A and B. At this point, the API request will have found all the versions of Bar in source A, - # but will not have found any versions of Bar from source B, which is a problem if the requested version - # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for - # each spec we found, we add all possible versions from all sources to the index. - def double_check_for_index(idx, dependency_names) - pinned_names = pinned_spec_names - loop do - idxcount = idx.size - - names = :names # do this so we only have to traverse to get dependency_names from the index once - unmet_dependency_names = lambda do - return names unless names == :names - new_names = sources.all_sources.map(&:dependency_names_to_double_check) - return names = nil if new_names.compact! - names = new_names.flatten(1).concat(dependency_names) - names.uniq! - names -= pinned_names - names - end - - sources.all_sources.each do |source| - source.double_check_for(unmet_dependency_names) - end - - break if idxcount == idx.size - end - end - private :double_check_for_index - - def has_rubygems_remotes? - sources.rubygems_sources.any? {|s| s.remotes.any? } - end - - def has_local_dependencies? - !sources.path_sources.empty? || !sources.git_sources.empty? - end - - def spec_git_paths - sources.git_sources.map {|s| s.path.to_s } - end - - def groups - dependencies.map(&:groups).flatten.uniq - end - - def lock(file, preserve_unknown_sections = false) - contents = to_lock - - # Convert to \r\n if the existing lock has them - # i.e., Windows with `git config core.autocrlf=true` - contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n") - - if @locked_bundler_version - locked_major = @locked_bundler_version.segments.first - current_major = Gem::Version.create(Bundler::VERSION).segments.first - - if updating_major = locked_major < current_major - Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \ - "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}." - end - end - - preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler)) - - return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) - - if Bundler.frozen_bundle? - Bundler.ui.error "Cannot write a changed lockfile while frozen." - return - end - - SharedHelpers.filesystem_access(file) do |p| - File.open(p, "wb") {|f| f.puts(contents) } - end - end - - def locked_bundler_version - if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION) - new_version = Bundler::VERSION - end - - new_version || @locked_bundler_version || Bundler::VERSION - end - - def locked_ruby_version - return unless ruby_version - if @unlock[:ruby] || !@locked_ruby_version - Bundler::RubyVersion.system - else - @locked_ruby_version - end - end - - def locked_ruby_version_object - return unless @locked_ruby_version - @locked_ruby_version_object ||= begin - unless version = RubyVersion.from_string(@locked_ruby_version) - raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \ - "#{@lockfile} could not be parsed. " \ - "Try running bundle update --ruby to resolve this." - end - version - end - end - - def to_lock - require "bundler/lockfile_generator" - LockfileGenerator.generate(self) - end - - def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) - msg = String.new - msg << "You are trying to install in deployment mode after changing\n" \ - "your Gemfile. Run `bundle install` elsewhere and add the\n" \ - "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." - - unless explicit_flag - suggested_command = if Bundler.settings.locations("frozen")[:global] - "bundle config --delete frozen" - elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? - "bundle config --delete deployment" - else - "bundle install --no-deployment" - end - msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \ - "freeze \nby running `#{suggested_command}`." - end - - added = [] - deleted = [] - changed = [] - - new_platforms = @platforms - @locked_platforms - deleted_platforms = @locked_platforms - @platforms - added.concat new_platforms.map {|p| "* platform: #{p}" } - deleted.concat deleted_platforms.map {|p| "* platform: #{p}" } - - gemfile_sources = sources.lock_sources - - new_sources = gemfile_sources - @locked_sources - deleted_sources = @locked_sources - gemfile_sources - - new_deps = @dependencies - @locked_deps.values - deleted_deps = @locked_deps.values - @dependencies - - # Check if it is possible that the source is only changed thing - if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?) - new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } - deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) } - end - - if @locked_sources != gemfile_sources - if new_sources.any? - added.concat new_sources.map {|source| "* source: #{source}" } - end - - if deleted_sources.any? - deleted.concat deleted_sources.map {|source| "* source: #{source}" } - end - end - - added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? - if deleted_deps.any? - deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } - end - - both_sources = Hash.new {|h, k| h[k] = [] } - @dependencies.each {|d| both_sources[d.name][0] = d } - @locked_deps.each {|name, d| both_sources[name][1] = d.source } - - both_sources.each do |name, (dep, lock_source)| - next unless (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep)) - gemfile_source_name = (dep && dep.source) || "no specified source" - lockfile_source_name = lock_source || "no specified source" - changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`" - end - - reason = change_reason - msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty? - msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? - msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? - msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? - msg << "\n" - - raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed? - end - - def validate_runtime! - validate_ruby! - validate_platforms! - end - - def validate_ruby! - return unless ruby_version - - if diff = ruby_version.diff(Bundler::RubyVersion.system) - problem, expected, actual = diff - - msg = case problem - when :engine - "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" - when :version - "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" - when :engine_version - "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" - when :patchlevel - if !expected.is_a?(String) - "The Ruby patchlevel in your Gemfile must be a string" - else - "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" - end - end - - raise RubyVersionMismatch, msg - end - end - - def validate_platforms! - return if @platforms.any? do |bundle_platform| - Bundler.rubygems.platforms.any? do |local_platform| - MatchPlatform.platforms_match?(bundle_platform, local_platform) - end - end - - raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \ - "but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \ - "there's no compatible match between those two lists." - end - - def add_platform(platform) - @new_platform ||= !@platforms.include?(platform) - @platforms |= [platform] - end - - def remove_platform(platform) - return if @platforms.delete(Gem::Platform.new(platform)) - raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" - end - - def add_current_platform - current_platform = Bundler.local_platform - add_platform(current_platform) if Bundler.feature_flag.specific_platform? - add_platform(generic(current_platform)) - end - - def find_resolved_spec(current_spec) - specs.find_by_name_and_platform(current_spec.name, current_spec.platform) - end - - def find_indexed_specs(current_spec) - index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) - end - - attr_reader :sources - private :sources - - def nothing_changed? - !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform - end - - def unlocking? - @unlocking - end - - private - - def change_reason - if unlocking? - unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v| - if v == true - k.to_s - else - v = Array(v) - "#{k}: (#{v.join(", ")})" - end - end.join(", ") - return "bundler is unlocking #{unlock_reason}" - end - [ - [@source_changes, "the list of sources changed"], - [@dependency_changes, "the dependencies in your gemfile changed"], - [@new_platform, "you added a new platform to your gemfile"], - [@path_changes, "the gemspecs for path gems changed"], - [@local_changes, "the gemspecs for git local gems changed"], - [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"], - ].select(&:first).map(&:last).join(", ") - end - - def pretty_dep(dep, source = false) - SharedHelpers.pretty_dependency(dep, source) - end - - # Check if the specs of the given source changed - # according to the locked source. - def specs_changed?(source) - locked = @locked_sources.find {|s| s == source } - - !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source) - end - - def dependencies_for_source_changed?(source, locked_source = source) - deps_for_source = @dependencies.select {|s| s.source == source } - locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source } - - Set.new(deps_for_source) != Set.new(locked_deps_for_source) - end - - def specs_for_source_changed?(source) - locked_index = Index.new - locked_index.use(@locked_specs.select {|s| source.can_lock?(s) }) - - # order here matters, since Index#== is checking source.specs.include?(locked_index) - locked_index != source.specs - rescue PathError, GitError => e - Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})" - false - end - - # Get all locals and override their matching sources. - # Return true if any of the locals changed (for example, - # they point to a new revision) or depend on new specs. - def converge_locals - locals = [] - - Bundler.settings.local_overrides.map do |k, v| - spec = @dependencies.find {|s| s.name == k } - source = spec && spec.source - if source && source.respond_to?(:local_override!) - source.unlock! if @unlock[:gems].include?(spec.name) - locals << [source, source.local_override!(v)] - end - end - - sources_with_changes = locals.select do |source, changed| - changed || specs_changed?(source) - end.map(&:first) - !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty? - end - - def converge_paths - sources.path_sources.any? do |source| - specs_changed?(source) - end - end - - def converge_path_source_to_gemspec_source(source) - return source unless source.instance_of?(Source::Path) - gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source } - gemspec_source || source - end - - def converge_path_sources_to_gemspec_sources - @locked_sources.map! do |source| - converge_path_source_to_gemspec_source(source) - end - @locked_specs.each do |spec| - spec.source &&= converge_path_source_to_gemspec_source(spec.source) - end - @locked_deps.each do |_, dep| - dep.source &&= converge_path_source_to_gemspec_source(dep.source) - end - end - - def converge_rubygems_sources - return false if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - - changes = false - - # Get the RubyGems sources from the Gemfile.lock - locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } - # Get the RubyGems remotes from the Gemfile - actual_remotes = sources.rubygems_remotes - - # If there is a RubyGems source in both - if !locked_gem_sources.empty? && !actual_remotes.empty? - locked_gem_sources.each do |locked_gem| - # Merge the remotes from the Gemfile into the Gemfile.lock - changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) - end - end - - changes - end - - def converge_sources - changes = false - - changes |= converge_rubygems_sources - - # Replace the sources from the Gemfile with the sources from the Gemfile.lock, - # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent - # source in the Gemfile.lock, use the one from the Gemfile. - changes |= sources.replace_sources!(@locked_sources) - - sources.all_sources.each do |source| - # If the source is unlockable and the current command allows an unlock of - # the source (for example, you are doing a `bundle update ` of a git-pinned - # gem), unlock it. For git sources, this means to unlock the revision, which - # will cause the `ref` used to be the most recent for the branch (or master) if - # an explicit `ref` is not used. - if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name) - source.unlock! - changes = true - end - end - - changes - end - - def converge_dependencies - frozen = Bundler.frozen_bundle? - (@dependencies + @locked_deps.values).each do |dep| - locked_source = @locked_deps[dep.name] - # This is to make sure that if bundler is installing in deployment mode and - # after locked_source and sources don't match, we still use locked_source. - if frozen && !locked_source.nil? && - locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist? - dep.source = locked_source.source - elsif dep.source - dep.source = sources.get(dep.source) - end - if dep.source.is_a?(Source::Gemspec) - dep.platforms.concat(@platforms.map {|p| Dependency::REVERSE_PLATFORM_MAP[p] }.flatten(1)).uniq! - end - end - - changes = false - # We want to know if all match, but don't want to check all entries - # This means we need to return false if any dependency doesn't match - # the lock or doesn't exist in the lock. - @dependencies.each do |dependency| - unless locked_dep = @locked_deps[dependency.name] - changes = true - next - end - - # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile - # doesn't carry a notion of the dependency type, if you use - # add_development_dependency in a gemspec that's loaded with the gemspec - # directive, the lockfile dependencies and resolved dependencies end up - # with a mismatch on #type. Work around that by setting the type on the - # dep from the lockfile. - locked_dep.instance_variable_set(:@type, dependency.type) - - # We already know the name matches from the hash lookup - # so we only need to check the requirement now - changes ||= dependency.requirement != locked_dep.requirement - end - - changes - end - - # Remove elements from the locked specs that are expired. This will most - # commonly happen if the Gemfile has changed since the lockfile was last - # generated - def converge_locked_specs - deps = [] - - # Build a list of dependencies that are the same in the Gemfile - # and Gemfile.lock. If the Gemfile modified a dependency, but - # the gem in the Gemfile.lock still satisfies it, this is fine - # too. - @dependencies.each do |dep| - locked_dep = @locked_deps[dep.name] - - # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep - locked_dep = nil unless locked_dep == dep - - if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep) - deps << dep - elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source) - @locked_specs.each do |s| - @unlock[:gems] << s.name if s.source == dep.source - end - - dep.source.unlock! if dep.source.respond_to?(:unlock!) - dep.source.specs.each {|s| @unlock[:gems] << s.name } - end - end - - unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec? - - converged = [] - @locked_specs.each do |s| - # Replace the locked dependency's source with the equivalent source from the Gemfile - dep = @dependencies.find {|d| s.satisfies?(d) } - s.source = (dep && dep.source) || sources.get(s.source) - - # Don't add a spec to the list if its source is expired. For example, - # if you change a Git gem to RubyGems. - next if s.source.nil? - next if @unlock[:sources].include?(s.source.name) - - # XXX This is a backwards-compatibility fix to preserve the ability to - # unlock a single gem by passing its name via `--source`. See issue #3759 - # TODO: delete in Bundler 2 - next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.name) - - # If the spec is from a path source and it doesn't exist anymore - # then we unlock it. - - # Path sources have special logic - if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) - other_sources_specs = begin - s.source.specs - rescue PathError, GitError - # if we won't need the source (according to the lockfile), - # don't error if the path/git source isn't available - next if @locked_specs. - for(requested_dependencies, [], false, true, false). - none? {|locked_spec| locked_spec.source == s.source } - - raise - end - - other = other_sources_specs[s].first - - # If the spec is no longer in the path source, unlock it. This - # commonly happens if the version changed in the gemspec - next unless other - - deps2 = other.dependencies.select {|d| d.type != :development } - runtime_dependencies = s.dependencies.select {|d| d.type != :development } - # If the dependencies of the path source have changed, unlock it - next unless runtime_dependencies.sort == deps2.sort - end - - converged << s - end - - resolve = SpecSet.new(converged) - expanded_deps = expand_dependencies(deps, true) - @locked_specs_incomplete_for_platform = !resolve.for(expanded_deps, @unlock[:gems], true, true) - resolve = resolve.for(expanded_deps, @unlock[:gems], false, false, false) - diff = nil - - # Now, we unlock any sources that do not have anymore gems pinned to it - sources.all_sources.each do |source| - next unless source.respond_to?(:unlock!) - - unless resolve.any? {|s| s.source == source } - diff ||= @locked_specs.to_a - resolve.to_a - source.unlock! if diff.any? {|s| s.source == source } - end - end - - resolve - end - - def in_locked_deps?(dep, locked_dep) - # Because the lockfile can't link a dep to a specific remote, we need to - # treat sources as equivalent anytime the locked dep has all the remotes - # that the Gemfile dep does. - locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source) - end - - def satisfies_locked_spec?(dep) - @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } - end - - # This list of dependencies is only used in #resolve, so it's OK to add - # the metadata dependencies here - def expanded_dependencies - @expanded_dependencies ||= begin - expand_dependencies(dependencies + metadata_dependencies, @remote) - end - end - - def metadata_dependencies - @metadata_dependencies ||= begin - ruby_versions = concat_ruby_version_requirements(@ruby_version) - if ruby_versions.empty? || !@ruby_version.exact? - concat_ruby_version_requirements(RubyVersion.system) - concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby] - end - [ - Dependency.new("ruby\0", ruby_versions), - Dependency.new("rubygems\0", Gem::VERSION), - ] - end - end - - def concat_ruby_version_requirements(ruby_version, ruby_versions = []) - return ruby_versions unless ruby_version - if ruby_version.patchlevel - ruby_versions << ruby_version.to_gem_version_with_patchlevel - else - ruby_versions.concat(ruby_version.versions.map do |version| - requirement = Gem::Requirement.new(version) - if requirement.exact? - "~> #{version}.0" - else - requirement - end - end) - end - end - - def expand_dependencies(dependencies, remote = false) - sorted_platforms = Resolver.sort_platforms(@platforms) - deps = [] - dependencies.each do |dep| - dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) - next if !remote && !dep.current_platform? - platforms = dep.gem_platforms(sorted_platforms) - if platforms.empty? && !Bundler.settings[:disable_platform_warnings] - mapped_platforms = dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] } - Bundler.ui.warn \ - "The dependency #{dep} will be unused by any of the platforms Bundler is installing for. " \ - "Bundler is installing for #{@platforms.join ", "} but the dependency " \ - "is only for #{mapped_platforms.join ", "}. " \ - "To add those platforms to the bundle, " \ - "run `bundle lock --add-platform #{mapped_platforms.join " "}`." - end - platforms.each do |p| - deps << DepProxy.new(dep, p) if remote || p == generic_local_platform - end - end - deps - end - - def requested_dependencies - groups = requested_groups - groups.map!(&:to_sym) - dependencies.reject {|d| !d.should_include? || (d.groups & groups).empty? } - end - - def source_requirements - # Load all specs from remote sources - index - - # Record the specs available in each gem's source, so that those - # specs will be available later when the resolver knows where to - # look for that gemspec (or its dependencies) - default = sources.default_source - source_requirements = { :default => default } - default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - dependencies.each do |dep| - next unless source = dep.source || default - source_requirements[dep.name] = source - end - metadata_dependencies.each do |dep| - source_requirements[dep.name] = sources.metadata_source - end - source_requirements["bundler"] = sources.metadata_source # needs to come last to override - source_requirements - end - - def pinned_spec_names(skip = nil) - pinned_names = [] - default = Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? && sources.default_source - @dependencies.each do |dep| - next unless dep_source = dep.source || default - next if dep_source == skip - pinned_names << dep.name - end - pinned_names - end - - def requested_groups - groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] - end - - def lockfiles_equal?(current, proposed, preserve_unknown_sections) - if preserve_unknown_sections - sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version) - sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current) - sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS - pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/ - whitespace_cleanup = /\n{2,}/ - current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip - proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip - end - current == proposed - end - - def extract_gem_info(error) - # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources" - # to an array. The first element will be the gem name (e.g. foo), the second will be the version number. - error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten - end - - def compute_requires - dependencies.reduce({}) do |requires, dep| - next requires unless dep.should_include? - requires[dep.name] = Array(dep.autorequire || dep.name).map do |file| - # Allow `require: true` as an alias for `require: ` - file == true ? dep.name : file - end - requires - end - end - - def additional_base_requirements_for_resolve - return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions? - dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) } - @locked_gems.specs.reduce({}) do |requirements, locked_spec| - name = locked_spec.name - next requirements if @locked_gems.dependencies[name] != dependencies_by_name[name] - dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") - requirements[name] = DepProxy.new(dep, locked_spec.platform) - requirements - end.values - end - - def equivalent_rubygems_remotes?(source) - return false unless source.is_a?(Source::Rubygems) - - Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) - end - end -end diff --git a/lib/ruby/stdlib/bundler/dep_proxy.rb b/lib/ruby/stdlib/bundler/dep_proxy.rb deleted file mode 100644 index 6c32179ac18..00000000000 --- a/lib/ruby/stdlib/bundler/dep_proxy.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class DepProxy - attr_reader :__platform, :dep - - def initialize(dep, platform) - @dep = dep - @__platform = platform - end - - def hash - @hash ||= [dep, __platform].hash - end - - def ==(other) - return false if other.class != self.class - dep == other.dep && __platform == other.__platform - end - - alias_method :eql?, :== - - def type - @dep.type - end - - def name - @dep.name - end - - def requirement - @dep.requirement - end - - def to_s - s = name.dup - s << " (#{requirement})" unless requirement == Gem::Requirement.default - s << " #{__platform}" unless __platform == Gem::Platform::RUBY - s - end - - private - - def method_missing(*args, &blk) - @dep.send(*args, &blk) - end - end -end diff --git a/lib/ruby/stdlib/bundler/dependency.rb b/lib/ruby/stdlib/bundler/dependency.rb deleted file mode 100644 index 8840ad6a9ca..00000000000 --- a/lib/ruby/stdlib/bundler/dependency.rb +++ /dev/null @@ -1,139 +0,0 @@ -# frozen_string_literal: true - -require "rubygems/dependency" -require "bundler/shared_helpers" -require "bundler/rubygems_ext" - -module Bundler - class Dependency < Gem::Dependency - attr_reader :autorequire - attr_reader :groups, :platforms, :gemfile - - PLATFORM_MAP = { - :ruby => Gem::Platform::RUBY, - :ruby_18 => Gem::Platform::RUBY, - :ruby_19 => Gem::Platform::RUBY, - :ruby_20 => Gem::Platform::RUBY, - :ruby_21 => Gem::Platform::RUBY, - :ruby_22 => Gem::Platform::RUBY, - :ruby_23 => Gem::Platform::RUBY, - :ruby_24 => Gem::Platform::RUBY, - :ruby_25 => Gem::Platform::RUBY, - :mri => Gem::Platform::RUBY, - :mri_18 => Gem::Platform::RUBY, - :mri_19 => Gem::Platform::RUBY, - :mri_20 => Gem::Platform::RUBY, - :mri_21 => Gem::Platform::RUBY, - :mri_22 => Gem::Platform::RUBY, - :mri_23 => Gem::Platform::RUBY, - :mri_24 => Gem::Platform::RUBY, - :mri_25 => Gem::Platform::RUBY, - :rbx => Gem::Platform::RUBY, - :truffleruby => Gem::Platform::RUBY, - :jruby => Gem::Platform::JAVA, - :jruby_18 => Gem::Platform::JAVA, - :jruby_19 => Gem::Platform::JAVA, - :mswin => Gem::Platform::MSWIN, - :mswin_18 => Gem::Platform::MSWIN, - :mswin_19 => Gem::Platform::MSWIN, - :mswin_20 => Gem::Platform::MSWIN, - :mswin_21 => Gem::Platform::MSWIN, - :mswin_22 => Gem::Platform::MSWIN, - :mswin_23 => Gem::Platform::MSWIN, - :mswin_24 => Gem::Platform::MSWIN, - :mswin_25 => Gem::Platform::MSWIN, - :mswin64 => Gem::Platform::MSWIN64, - :mswin64_19 => Gem::Platform::MSWIN64, - :mswin64_20 => Gem::Platform::MSWIN64, - :mswin64_21 => Gem::Platform::MSWIN64, - :mswin64_22 => Gem::Platform::MSWIN64, - :mswin64_23 => Gem::Platform::MSWIN64, - :mswin64_24 => Gem::Platform::MSWIN64, - :mswin64_25 => Gem::Platform::MSWIN64, - :mingw => Gem::Platform::MINGW, - :mingw_18 => Gem::Platform::MINGW, - :mingw_19 => Gem::Platform::MINGW, - :mingw_20 => Gem::Platform::MINGW, - :mingw_21 => Gem::Platform::MINGW, - :mingw_22 => Gem::Platform::MINGW, - :mingw_23 => Gem::Platform::MINGW, - :mingw_24 => Gem::Platform::MINGW, - :mingw_25 => Gem::Platform::MINGW, - :x64_mingw => Gem::Platform::X64_MINGW, - :x64_mingw_20 => Gem::Platform::X64_MINGW, - :x64_mingw_21 => Gem::Platform::X64_MINGW, - :x64_mingw_22 => Gem::Platform::X64_MINGW, - :x64_mingw_23 => Gem::Platform::X64_MINGW, - :x64_mingw_24 => Gem::Platform::X64_MINGW, - :x64_mingw_25 => Gem::Platform::X64_MINGW, - }.freeze - - REVERSE_PLATFORM_MAP = {}.tap do |reverse_platform_map| - PLATFORM_MAP.each do |key, value| - reverse_platform_map[value] ||= [] - reverse_platform_map[value] << key - end - - reverse_platform_map.each {|_, platforms| platforms.freeze } - end.freeze - - def initialize(name, version, options = {}, &blk) - type = options["type"] || :runtime - super(name, version, type) - - @autorequire = nil - @groups = Array(options["group"] || :default).map(&:to_sym) - @source = options["source"] - @platforms = Array(options["platforms"]) - @env = options["env"] - @should_include = options.fetch("should_include", true) - @gemfile = options["gemfile"] - - @autorequire = Array(options["require"] || []) if options.key?("require") - end - - # Returns the platforms this dependency is valid for, in the same order as - # passed in the `valid_platforms` parameter - def gem_platforms(valid_platforms) - return valid_platforms if @platforms.empty? - - @gem_platforms ||= @platforms.map {|pl| PLATFORM_MAP[pl] }.compact.uniq - - valid_platforms & @gem_platforms - end - - def should_include? - @should_include && current_env? && current_platform? - end - - def current_env? - return true unless @env - if @env.is_a?(Hash) - @env.all? do |key, val| - ENV[key.to_s] && (val.is_a?(String) ? ENV[key.to_s] == val : ENV[key.to_s] =~ val) - end - else - ENV[@env.to_s] - end - end - - def current_platform? - return true if @platforms.empty? - @platforms.any? do |p| - Bundler.current_ruby.send("#{p}?") - end - end - - def to_lock - out = super - out << "!" if source - out << "\n" - end - - def specific? - super - rescue NoMethodError - requirement != ">= 0" - end - end -end diff --git a/lib/ruby/stdlib/bundler/deployment.rb b/lib/ruby/stdlib/bundler/deployment.rb deleted file mode 100644 index 291e158ca01..00000000000 --- a/lib/ruby/stdlib/bundler/deployment.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -require "bundler/shared_helpers" -Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \ - "Capistrano, but Capistrano provides its own integration with " \ - "Bundler via the capistrano-bundler gem. Use it instead." - -module Bundler - class Deployment - def self.define_task(context, task_method = :task, opts = {}) - if defined?(Capistrano) && context.is_a?(Capistrano::Configuration) - context_name = "capistrano" - role_default = "{:except => {:no_release => true}}" - error_type = ::Capistrano::CommandError - else - context_name = "vlad" - role_default = "[:app]" - error_type = ::Rake::CommandFailedError - end - - roles = context.fetch(:bundle_roles, false) - opts[:roles] = roles if roles - - context.send :namespace, :bundle do - send :desc, <<-DESC - Install the current Bundler environment. By default, gems will be \ - installed to the shared/bundle path. Gems in the development and \ - test group will not be installed. The install command is executed \ - with the --deployment and --quiet flags. If the bundle cmd cannot \ - be found then you can override the bundle_cmd variable to specify \ - which one it should use. The base path to the app is fetched from \ - the :latest_release variable. Set it for custom deploy layouts. - - You can override any of these defaults by setting the variables shown below. - - N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \ - in your deploy.rb file. - - set :bundle_gemfile, "Gemfile" - set :bundle_dir, File.join(fetch(:shared_path), 'bundle') - set :bundle_flags, "--deployment --quiet" - set :bundle_without, [:development, :test] - set :bundle_with, [:mysql] - set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle" - set :bundle_roles, #{role_default} # e.g. [:app, :batch] - DESC - send task_method, :install, opts do - bundle_cmd = context.fetch(:bundle_cmd, "bundle") - bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet") - bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), "bundle")) - bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile") - bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact - bundle_with = [*context.fetch(:bundle_with, [])].compact - app_path = context.fetch(:latest_release) - if app_path.to_s.empty? - raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.") - end - args = ["--gemfile #{File.join(app_path, bundle_gemfile)}"] - args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty? - args << bundle_flags.to_s - args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty? - args << "--with #{bundle_with.join(" ")}" unless bundle_with.empty? - - run "cd #{app_path} && #{bundle_cmd} install #{args.join(" ")}" - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/deprecate.rb b/lib/ruby/stdlib/bundler/deprecate.rb deleted file mode 100644 index f59533630e9..00000000000 --- a/lib/ruby/stdlib/bundler/deprecate.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -begin - require "rubygems/deprecate" -rescue LoadError - # it's fine if it doesn't exist on the current RubyGems... - nil -end - -module Bundler - # If Bundler::Deprecate is an autoload constant, we need to define it - if defined?(Bundler::Deprecate) && !autoload?(:Deprecate) - # nothing to do! - elsif defined? ::Deprecate - Deprecate = ::Deprecate - elsif defined? Gem::Deprecate - Deprecate = Gem::Deprecate - else - class Deprecate - end - end - - unless Deprecate.respond_to?(:skip_during) - def Deprecate.skip_during - original = skip - self.skip = true - yield - ensure - self.skip = original - end - end - - unless Deprecate.respond_to?(:skip) - def Deprecate.skip - @skip ||= false - end - end - - unless Deprecate.respond_to?(:skip=) - def Deprecate.skip=(skip) - @skip = skip - end - end -end diff --git a/lib/ruby/stdlib/bundler/dsl.rb b/lib/ruby/stdlib/bundler/dsl.rb deleted file mode 100644 index 1a2114ed938..00000000000 --- a/lib/ruby/stdlib/bundler/dsl.rb +++ /dev/null @@ -1,615 +0,0 @@ -# frozen_string_literal: true - -require "bundler/dependency" -require "bundler/ruby_dsl" - -module Bundler - class Dsl - include RubyDsl - - def self.evaluate(gemfile, lockfile, unlock) - builder = new - builder.eval_gemfile(gemfile) - builder.to_definition(lockfile, unlock) - end - - VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze - - VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules - platform platforms type source install_if gemfile].freeze - - attr_reader :gemspecs - attr_accessor :dependencies - - def initialize - @source = nil - @sources = SourceList.new - @git_sources = {} - @dependencies = [] - @groups = [] - @install_conditionals = [] - @optional_groups = [] - @platforms = [] - @env = nil - @ruby_version = nil - @gemspecs = [] - @gemfile = nil - @gemfiles = [] - add_git_sources - end - - def eval_gemfile(gemfile, contents = nil) - expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile && @gemfile.parent) - original_gemfile = @gemfile - @gemfile = expanded_gemfile_path - @gemfiles << expanded_gemfile_path - contents ||= Bundler.read_file(@gemfile.to_s) - instance_eval(contents.dup.untaint, gemfile.to_s, 1) - rescue Exception => e - message = "There was an error " \ - "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ - "`#{File.basename gemfile.to_s}`: #{e.message}" - - raise DSLError.new(message, gemfile, e.backtrace, contents) - ensure - @gemfile = original_gemfile - end - - def gemspec(opts = nil) - opts ||= {} - path = opts[:path] || "." - glob = opts[:glob] - name = opts[:name] - development_group = opts[:development_group] || :development - expanded_path = gemfile_root.join(path) - - gemspecs = Dir[File.join(expanded_path, "{,*}.gemspec")].map {|g| Bundler.load_gemspec(g) }.compact - gemspecs.reject! {|s| s.name != name } if name - Index.sort_specs(gemspecs) - specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] } - - case specs_by_name_and_version.size - when 1 - specs = specs_by_name_and_version.values.first - spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first - - @gemspecs << spec - - gem_platforms = Bundler::Dependency::REVERSE_PLATFORM_MAP[Bundler::GemHelpers.generic_local_platform] - gem spec.name, :name => spec.name, :path => path, :glob => glob, :platforms => gem_platforms - - group(development_group) do - spec.development_dependencies.each do |dep| - gem dep.name, *(dep.requirement.as_list + [:type => :development]) - end - end - when 0 - raise InvalidOption, "There are no gemspecs at #{expanded_path}" - else - raise InvalidOption, "There are multiple gemspecs at #{expanded_path}. " \ - "Please use the :name option to specify which one should be used" - end - end - - def gem(name, *args) - options = args.last.is_a?(Hash) ? args.pop.dup : {} - options["gemfile"] = @gemfile - version = args || [">= 0"] - - normalize_options(name, version, options) - - dep = Dependency.new(name, version, options) - - # if there's already a dependency with this name we try to prefer one - if current = @dependencies.find {|d| d.name == dep.name } - deleted_dep = @dependencies.delete(current) if current.type == :development - - if current.requirement != dep.requirement - unless deleted_dep - return if dep.type == :development - - update_prompt = "" - - if File.basename(@gemfile) == Injector::INJECTED_GEMS - if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0") - update_prompt = ". Gem already added" - else - update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`" - - update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0") - end - end - - raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \ - "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \ - "#{update_prompt}" - end - - else - Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \ - "You should probably keep only one of them.\n" \ - "Remove any duplicate entries and specify the gem only once (per group).\n" \ - "While it's not a problem now, it could cause errors if you change the version of one of them later." - end - - if current.source != dep.source - unless deleted_dep - return if dep.type == :development - raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ - "You specified that #{dep.name} (#{dep.requirement}) should come from " \ - "#{current.source || "an unspecified source"} and #{dep.source}\n" - end - end - end - - @dependencies << dep - end - - def source(source, *args, &blk) - options = args.last.is_a?(Hash) ? args.pop.dup : {} - options = normalize_hash(options) - source = normalize_source(source) - - if options.key?("type") - options["type"] = options["type"].to_s - unless Plugin.source?(options["type"]) - raise InvalidOption, "No plugin sources available for #{options["type"]}" - end - - unless block_given? - raise InvalidOption, "You need to pass a block to #source with :type option" - end - - source_opts = options.merge("uri" => source) - with_source(@sources.add_plugin_source(options["type"], source_opts), &blk) - elsif block_given? - with_source(@sources.add_rubygems_source("remotes" => source), &blk) - else - check_primary_source_safety(@sources) - @sources.global_rubygems_source = source - end - end - - def git_source(name, &block) - unless block_given? - raise InvalidOption, "You need to pass a block to #git_source" - end - - if valid_keys.include?(name.to_s) - raise InvalidOption, "You cannot use #{name} as a git source. It " \ - "is a reserved key. Reserved keys are: #{valid_keys.join(", ")}" - end - - @git_sources[name.to_s] = block - end - - def path(path, options = {}, &blk) - unless block_given? - msg = "You can no longer specify a path source by itself. Instead, \n" \ - "either use the :path option on a gem, or specify the gems that \n" \ - "bundler should find in the path source by passing a block to \n" \ - "the path method, like: \n\n" \ - " path 'dir/containing/rails' do\n" \ - " gem 'rails'\n" \ - " end\n\n" - - raise DeprecatedError, msg if Bundler.feature_flag.disable_multisource? - SharedHelpers.major_deprecation(2, msg.strip) - end - - source_options = normalize_hash(options).merge( - "path" => Pathname.new(path), - "root_path" => gemfile_root, - "gemspec" => gemspecs.find {|g| g.name == options["name"] } - ) - source = @sources.add_path_source(source_options) - with_source(source, &blk) - end - - def git(uri, options = {}, &blk) - unless block_given? - msg = "You can no longer specify a git source by itself. Instead, \n" \ - "either use the :git option on a gem, or specify the gems that \n" \ - "bundler should find in the git source by passing a block to \n" \ - "the git method, like: \n\n" \ - " git 'git://github.com/rails/rails.git' do\n" \ - " gem 'rails'\n" \ - " end" - raise DeprecatedError, msg - end - - with_source(@sources.add_git_source(normalize_hash(options).merge("uri" => uri)), &blk) - end - - def github(repo, options = {}) - raise ArgumentError, "GitHub sources require a block" unless block_given? - raise DeprecatedError, "The #github method has been removed" if Bundler.feature_flag.skip_default_git_sources? - github_uri = @git_sources["github"].call(repo) - git_options = normalize_hash(options).merge("uri" => github_uri) - git_source = @sources.add_git_source(git_options) - with_source(git_source) { yield } - end - - def to_definition(lockfile, unlock) - Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) - end - - def group(*args, &blk) - options = args.last.is_a?(Hash) ? args.pop.dup : {} - normalize_group_options(options, args) - - @groups.concat args - - if options["optional"] - optional_groups = args - @optional_groups - @optional_groups.concat optional_groups - end - - yield - ensure - args.each { @groups.pop } - end - - def install_if(*args) - @install_conditionals.concat args - yield - ensure - args.each { @install_conditionals.pop } - end - - def platforms(*platforms) - @platforms.concat platforms - yield - ensure - platforms.each { @platforms.pop } - end - alias_method :platform, :platforms - - def env(name) - old = @env - @env = name - yield - ensure - @env = old - end - - def plugin(*args) - # Pass on - end - - def method_missing(name, *args) - raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" - end - - private - - def add_git_sources - return if Bundler.feature_flag.skip_default_git_sources? - - git_source(:github) do |repo_name| - warn_deprecated_git_source(:github, <<-'RUBY'.strip, 'Change any "reponame" :github sources to "username/reponame".') -"https://github.com/#{repo_name}.git" - RUBY - # It would be better to use https instead of the git protocol, but this - # can break deployment of existing locked bundles when switching between - # different versions of Bundler. The change will be made in 2.0, which - # does not guarantee compatibility with the 1.x series. - # - # See https://github.com/bundler/bundler/pull/2569 for discussion - # - # This can be overridden by adding this code to your Gemfiles: - # - # git_source(:github) do |repo_name| - # repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") - # "https://github.com/#{repo_name}.git" - # end - repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") - # TODO: 2.0 upgrade this setting to the default - if Bundler.feature_flag.github_https? - Bundler::SharedHelpers.major_deprecation 2, "The `github.https` setting will be removed" - "https://github.com/#{repo_name}.git" - else - "git://github.com/#{repo_name}.git" - end - end - - # TODO: 2.0 remove this deprecated git source - git_source(:gist) do |repo_name| - warn_deprecated_git_source(:gist, '"https://gist.github.com/#{repo_name}.git"') - - "https://gist.github.com/#{repo_name}.git" - end - - # TODO: 2.0 remove this deprecated git source - git_source(:bitbucket) do |repo_name| - warn_deprecated_git_source(:bitbucket, <<-'RUBY'.strip) -user_name, repo_name = repo_name.split("/") -repo_name ||= user_name -"https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" - RUBY - - user_name, repo_name = repo_name.split("/") - repo_name ||= user_name - "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" - end - end - - def with_source(source) - old_source = @source - if block_given? - @source = source - yield - end - source - ensure - @source = old_source - end - - def normalize_hash(opts) - opts.keys.each do |k| - opts[k.to_s] = opts.delete(k) unless k.is_a?(String) - end - opts - end - - def valid_keys - @valid_keys ||= VALID_KEYS - end - - def normalize_options(name, version, opts) - if name.is_a?(Symbol) - raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead) - end - if name =~ /\s/ - raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) - end - if name.empty? - raise GemfileError, %(an empty gem name is not valid) - end - - normalize_hash(opts) - - git_names = @git_sources.keys.map(&:to_s) - validate_keys("gem '#{name}'", opts, valid_keys + git_names) - - groups = @groups.dup - opts["group"] = opts.delete("groups") || opts["group"] - groups.concat Array(opts.delete("group")) - groups = [:default] if groups.empty? - - install_if = @install_conditionals.dup - install_if.concat Array(opts.delete("install_if")) - install_if = install_if.reduce(true) do |memo, val| - memo && (val.respond_to?(:call) ? val.call : val) - end - - platforms = @platforms.dup - opts["platforms"] = opts["platform"] || opts["platforms"] - platforms.concat Array(opts.delete("platforms")) - platforms.map!(&:to_sym) - platforms.each do |p| - next if VALID_PLATFORMS.include?(p) - raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}" - end - - # Save sources passed in a key - if opts.key?("source") - source = normalize_source(opts["source"]) - opts["source"] = @sources.add_rubygems_source("remotes" => source) - end - - git_name = (git_names & opts.keys).last - if @git_sources[git_name] - opts["git"] = @git_sources[git_name].call(opts[git_name]) - end - - %w[git path].each do |type| - next unless param = opts[type] - if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ - options = opts.merge("name" => name, "version" => $1) - else - options = opts.dup - end - source = send(type, param, options) {} - opts["source"] = source - end - - opts["source"] ||= @source - opts["env"] ||= @env - opts["platforms"] = platforms.dup - opts["group"] = groups - opts["should_include"] = install_if - end - - def normalize_group_options(opts, groups) - normalize_hash(opts) - - groups = groups.map {|group| ":#{group}" }.join(", ") - validate_keys("group #{groups}", opts, %w[optional]) - - opts["optional"] ||= false - end - - def validate_keys(command, opts, valid_keys) - invalid_keys = opts.keys - valid_keys - - git_source = opts.keys & @git_sources.keys.map(&:to_s) - if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?) - raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) - end - - return true unless invalid_keys.any? - - message = String.new - message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " - message << if invalid_keys.size > 1 - "as options for #{command}, but they are invalid." - else - "as an option for #{command}, but it is invalid." - end - - message << " Valid options are: #{valid_keys.join(", ")}." - message << " You may be able to resolve this by upgrading Bundler to the newest version." - raise InvalidOption, message - end - - def normalize_source(source) - case source - when :gemcutter, :rubygems, :rubyforge - Bundler::SharedHelpers.major_deprecation 2, "The source :#{source} is deprecated because HTTP " \ - "requests are insecure.\nPlease change your source to 'https://" \ - "rubygems.org' if possible, or 'http://rubygems.org' if not." - "http://rubygems.org" - when String - source - else - raise GemfileError, "Unknown source '#{source}'" - end - end - - def check_primary_source_safety(source_list) - return if source_list.rubygems_primary_remotes.empty? && source_list.global_rubygems_source.nil? - - if Bundler.feature_flag.disable_multisource? - msg = "This Gemfile contains multiple primary sources. " \ - "Each source after the first must include a block to indicate which gems " \ - "should come from that source" - unless Bundler.feature_flag.bundler_2_mode? - msg += ". To downgrade this error to a warning, run " \ - "`bundle config --delete disable_multisource`" - end - raise GemfileEvalError, msg - else - Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \ - "Using `source` more than once without a block is a security risk, and " \ - "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source. " \ - "To upgrade this warning to an error, run `bundle config " \ - "disable_multisource true`." - end - end - - def warn_deprecated_git_source(name, replacement, additional_message = nil) - # TODO: 2.0 remove deprecation - additional_message &&= " #{additional_message}" - replacement = if replacement.count("\n").zero? - "{|repo_name| #{replacement} }" - else - "do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end" - end - - Bundler::SharedHelpers.major_deprecation 2, <<-EOS -The :#{name} git source is deprecated, and will be removed in Bundler 2.0.#{additional_message} Add this code to the top of your Gemfile to ensure it continues to work: - - git_source(:#{name}) #{replacement} - - EOS - end - - class DSLError < GemfileError - # @return [String] the description that should be presented to the user. - # - attr_reader :description - - # @return [String] the path of the dsl file that raised the exception. - # - attr_reader :dsl_path - - # @return [Exception] the backtrace of the exception raised by the - # evaluation of the dsl file. - # - attr_reader :backtrace - - # @param [Exception] backtrace @see backtrace - # @param [String] dsl_path @see dsl_path - # - def initialize(description, dsl_path, backtrace, contents = nil) - @status_code = $!.respond_to?(:status_code) && $!.status_code - - @description = description - @dsl_path = dsl_path - @backtrace = backtrace - @contents = contents - end - - def status_code - @status_code || super - end - - # @return [String] the contents of the DSL that cause the exception to - # be raised. - # - def contents - @contents ||= begin - dsl_path && File.exist?(dsl_path) && File.read(dsl_path) - end - end - - # The message of the exception reports the content of podspec for the - # line that generated the original exception. - # - # @example Output - # - # Invalid podspec at `RestKit.podspec` - undefined method - # `exclude_header_search_paths=' for # - # - # from spec-repos/master/RestKit/0.9.3/RestKit.podspec:36 - # ------------------------------------------- - # # because it would break: #import - # > ns.exclude_header_search_paths = 'Code/RestKit.h' - # end - # ------------------------------------------- - # - # @return [String] the message of the exception. - # - def to_s - @to_s ||= begin - trace_line, description = parse_line_number_from_description - - m = String.new("\n[!] ") - m << description - m << ". Bundler cannot continue.\n" - - return m unless backtrace && dsl_path && contents - - trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line - return m unless trace_line - line_numer = trace_line.split(":")[1].to_i - 1 - return m unless line_numer - - lines = contents.lines.to_a - indent = " # " - indicator = indent.tr("#", ">") - first_line = line_numer.zero? - last_line = (line_numer == (lines.count - 1)) - - m << "\n" - m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n" - m << "#{indent}-------------------------------------------\n" - m << "#{indent}#{lines[line_numer - 1]}" unless first_line - m << "#{indicator}#{lines[line_numer]}" - m << "#{indent}#{lines[line_numer + 1]}" unless last_line - m << "\n" unless m.end_with?("\n") - m << "#{indent}-------------------------------------------\n" - end - end - - private - - def parse_line_number_from_description - description = self.description - if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/ - trace_line = Regexp.last_match[1] - description = description.sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ") - end - [trace_line, description] - end - end - - def gemfile_root - @gemfile ||= Bundler.default_gemfile - @gemfile.dirname - end - end -end diff --git a/lib/ruby/stdlib/bundler/endpoint_specification.rb b/lib/ruby/stdlib/bundler/endpoint_specification.rb deleted file mode 100644 index 9a00b64e0ed..00000000000 --- a/lib/ruby/stdlib/bundler/endpoint_specification.rb +++ /dev/null @@ -1,141 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # used for Creating Specifications from the Gemcutter Endpoint - class EndpointSpecification < Gem::Specification - ILLFORMED_MESSAGE = 'Ill-formed requirement ["# e - raise GemspecError, "There was an error parsing the metadata for the gem #{name} (#{version}): #{e.class}\n#{e}\nThe metadata was #{data.inspect}" - end - - def build_dependency(name, requirements) - Gem::Dependency.new(name, requirements) - rescue ArgumentError => e - raise unless e.message.include?(ILLFORMED_MESSAGE) - puts # we shouldn't print the error message on the "fetching info" status line - raise GemspecError, - "Unfortunately, the gem #{name} (#{version}) has an invalid " \ - "gemspec.\nPlease ask the gem author to yank the bad version to fix " \ - "this issue. For more information, see http://bit.ly/syck-defaultkey." - end - end -end diff --git a/lib/ruby/stdlib/bundler/env.rb b/lib/ruby/stdlib/bundler/env.rb deleted file mode 100644 index 51738139fac..00000000000 --- a/lib/ruby/stdlib/bundler/env.rb +++ /dev/null @@ -1,155 +0,0 @@ -# frozen_string_literal: true - -require "bundler/rubygems_integration" -require "bundler/source/git/git_proxy" - -module Bundler - class Env - def self.write(io) - io.write report - end - - def self.report(options = {}) - print_gemfile = options.delete(:print_gemfile) { true } - print_gemspecs = options.delete(:print_gemspecs) { true } - - out = String.new - append_formatted_table("Environment", environment, out) - append_formatted_table("Bundler Build Metadata", BuildMetadata.to_h, out) - - unless Bundler.settings.all.empty? - out << "\n## Bundler settings\n\n```\n" - Bundler.settings.all.each do |setting| - out << setting << "\n" - Bundler.settings.pretty_values_for(setting).each do |line| - out << " " << line << "\n" - end - end - out << "```\n" - end - - return out unless SharedHelpers.in_bundle? - - if print_gemfile - gemfiles = [Bundler.default_gemfile] - begin - gemfiles = Bundler.definition.gemfiles - rescue GemfileNotFound - nil - end - - out << "\n## Gemfile\n" - gemfiles.each do |gemfile| - out << "\n### #{Pathname.new(gemfile).relative_path_from(SharedHelpers.pwd)}\n\n" - out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n" - end - - out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n" - out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n" - end - - if print_gemspecs - dsl = Dsl.new.tap {|d| d.eval_gemfile(Bundler.default_gemfile) } - out << "\n## Gemspecs\n" unless dsl.gemspecs.empty? - dsl.gemspecs.each do |gs| - out << "\n### #{File.basename(gs.loaded_from)}" - out << "\n\n```ruby\n" << read_file(gs.loaded_from).chomp << "\n```\n" - end - end - - out - end - - def self.read_file(filename) - Bundler.read_file(filename.to_s).strip - rescue Errno::ENOENT - "" - rescue RuntimeError => e - "#{e.class}: #{e.message}" - end - - def self.ruby_version - str = String.new("#{RUBY_VERSION}") - if RUBY_VERSION < "1.9" - str << " (#{RUBY_RELEASE_DATE}" - str << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL - str << ") [#{RUBY_PLATFORM}]" - else - str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL - str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]" - end - end - - def self.git_version - Bundler::Source::Git::GitProxy.new(nil, nil, nil).full_version - rescue Bundler::Source::Git::GitNotInstalledError - "not installed" - end - - def self.version_of(script) - return "not installed" unless Bundler.which(script) - `#{script} --version`.chomp - end - - def self.chruby_version - return "not installed" unless Bundler.which("chruby-exec") - `chruby-exec -- chruby --version`. - sub(/.*^chruby: (#{Gem::Version::VERSION_PATTERN}).*/m, '\1') - end - - def self.environment - out = [] - - out << ["Bundler", Bundler::VERSION] - out << [" Platforms", Gem.platforms.join(", ")] - out << ["Ruby", ruby_version] - out << [" Full Path", Gem.ruby] - out << [" Config Dir", Pathname.new(Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE).dirname] - out << ["RubyGems", Gem::VERSION] - out << [" Gem Home", ENV.fetch("GEM_HOME") { Gem.dir }] - out << [" Gem Path", ENV.fetch("GEM_PATH") { Gem.path.join(File::PATH_SEPARATOR) }] - out << [" User Path", Gem.user_dir] - out << [" Bin Dir", Gem.bindir] - if defined?(OpenSSL) - out << ["OpenSSL"] - out << [" Compiled", OpenSSL::OPENSSL_VERSION] if defined?(OpenSSL::OPENSSL_VERSION) - out << [" Loaded", OpenSSL::OPENSSL_LIBRARY_VERSION] if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) - out << [" Cert File", OpenSSL::X509::DEFAULT_CERT_FILE] if defined?(OpenSSL::X509::DEFAULT_CERT_FILE) - out << [" Cert Dir", OpenSSL::X509::DEFAULT_CERT_DIR] if defined?(OpenSSL::X509::DEFAULT_CERT_DIR) - end - out << ["Tools"] - out << [" Git", git_version] - out << [" RVM", ENV.fetch("rvm_version") { version_of("rvm") }] - out << [" rbenv", version_of("rbenv")] - out << [" chruby", chruby_version] - - %w[rubygems-bundler open_gem].each do |name| - specs = Bundler.rubygems.find_name(name) - out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty? - end - if (exe = caller.last.split(":").first) && exe =~ %r{(exe|bin)/bundler?\z} - shebang = File.read(exe).lines.first - shebang.sub!(/^#!\s*/, "") - unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby") - out << ["Gem.ruby", Gem.ruby] - out << ["bundle #!", shebang] - end - end - - out - end - - def self.append_formatted_table(title, pairs, out) - return if pairs.empty? - out << "\n" unless out.empty? - out << "## #{title}\n\n```\n" - ljust = pairs.map {|k, _v| k.to_s.length }.max - pairs.each do |k, v| - out << "#{k.to_s.ljust(ljust)} #{v}\n" - end - out << "```\n" - end - - private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table, :version_of, :chruby_version - end -end diff --git a/lib/ruby/stdlib/bundler/environment_preserver.rb b/lib/ruby/stdlib/bundler/environment_preserver.rb deleted file mode 100644 index af7c1ef0a49..00000000000 --- a/lib/ruby/stdlib/bundler/environment_preserver.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class EnvironmentPreserver - INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze - BUNDLER_KEYS = %w[ - BUNDLE_BIN_PATH - BUNDLE_GEMFILE - BUNDLER_ORIG_MANPATH - BUNDLER_VERSION - GEM_HOME - GEM_PATH - MANPATH - PATH - RB_USER_INSTALL - RUBYLIB - RUBYOPT - ].map(&:freeze).freeze - BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze - - # @param env [ENV] - # @param keys [Array] - def initialize(env, keys) - @original = env.to_hash - @keys = keys - @prefix = BUNDLER_PREFIX - end - - # @return [Hash] - def backup - env = @original.clone - @keys.each do |key| - value = env[key] - if !value.nil? && !value.empty? - env[@prefix + key] ||= value - elsif value.nil? - env[@prefix + key] ||= INTENTIONALLY_NIL - end - end - env - end - - # @return [Hash] - def restore - env = @original.clone - @keys.each do |key| - value_original = env[@prefix + key] - next if value_original.nil? || value_original.empty? - if value_original == INTENTIONALLY_NIL - env.delete(key) - else - env[key] = value_original - end - env.delete(@prefix + key) - end - env - end - end -end diff --git a/lib/ruby/stdlib/bundler/errors.rb b/lib/ruby/stdlib/bundler/errors.rb deleted file mode 100644 index e471bce0b6f..00000000000 --- a/lib/ruby/stdlib/bundler/errors.rb +++ /dev/null @@ -1,158 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class BundlerError < StandardError - def self.status_code(code) - define_method(:status_code) { code } - if match = BundlerError.all_errors.find {|_k, v| v == code } - error, _ = match - raise ArgumentError, - "Trying to register #{self} for status code #{code} but #{error} is already registered" - end - BundlerError.all_errors[self] = code - end - - def self.all_errors - @all_errors ||= {} - end - end - - class GemfileError < BundlerError; status_code(4); end - class InstallError < BundlerError; status_code(5); end - - # Internal error, should be rescued - class VersionConflict < BundlerError - attr_reader :conflicts - - def initialize(conflicts, msg = nil) - super(msg) - @conflicts = conflicts - end - - status_code(6) - end - - class GemNotFound < BundlerError; status_code(7); end - class InstallHookError < BundlerError; status_code(8); end - class GemfileNotFound < BundlerError; status_code(10); end - class GitError < BundlerError; status_code(11); end - class DeprecatedError < BundlerError; status_code(12); end - class PathError < BundlerError; status_code(13); end - class GemspecError < BundlerError; status_code(14); end - class InvalidOption < BundlerError; status_code(15); end - class ProductionError < BundlerError; status_code(16); end - class HTTPError < BundlerError - status_code(17) - def filter_uri(uri) - URICredentialsFilter.credential_filtered_uri(uri) - end - end - class RubyVersionMismatch < BundlerError; status_code(18); end - class SecurityError < BundlerError; status_code(19); end - class LockfileError < BundlerError; status_code(20); end - class CyclicDependencyError < BundlerError; status_code(21); end - class GemfileLockNotFound < BundlerError; status_code(22); end - class PluginError < BundlerError; status_code(29); end - class SudoNotPermittedError < BundlerError; status_code(30); end - class ThreadCreationError < BundlerError; status_code(33); end - class APIResponseMismatchError < BundlerError; status_code(34); end - class GemfileEvalError < GemfileError; end - class MarshalError < StandardError; end - - class PermissionError < BundlerError - def initialize(path, permission_type = :write) - @path = path - @permission_type = permission_type - end - - def action - case @permission_type - when :read then "read from" - when :write then "write to" - when :executable, :exec then "execute" - else @permission_type.to_s - end - end - - def message - "There was an error while trying to #{action} `#{@path}`. " \ - "It is likely that you need to grant #{@permission_type} permissions " \ - "for that path." - end - - status_code(23) - end - - class GemRequireError < BundlerError - attr_reader :orig_exception - - def initialize(orig_exception, msg) - full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\ - "Backtrace for gem load error is:\n"\ - "#{orig_exception.backtrace.join("\n")}\n"\ - "Bundler Error Backtrace:\n" - super(full_message) - @orig_exception = orig_exception - end - - status_code(24) - end - - class YamlSyntaxError < BundlerError - attr_reader :orig_exception - - def initialize(orig_exception, msg) - super(msg) - @orig_exception = orig_exception - end - - status_code(25) - end - - class TemporaryResourceError < PermissionError - def message - "There was an error while trying to #{action} `#{@path}`. " \ - "Some resource was temporarily unavailable. It's suggested that you try" \ - "the operation again." - end - - status_code(26) - end - - class VirtualProtocolError < BundlerError - def message - "There was an error relating to virtualization and file access." \ - "It is likely that you need to grant access to or mount some file system correctly." - end - - status_code(27) - end - - class OperationNotSupportedError < PermissionError - def message - "Attempting to #{action} `#{@path}` is unsupported by your OS." - end - - status_code(28) - end - - class NoSpaceOnDeviceError < PermissionError - def message - "There was an error while trying to #{action} `#{@path}`. " \ - "There was insufficient space remaining on the device." - end - - status_code(31) - end - - class GenericSystemCallError < BundlerError - attr_reader :underlying_error - - def initialize(underlying_error, message) - @underlying_error = underlying_error - super("#{message}\nThe underlying system error is #{@underlying_error.class}: #{@underlying_error}") - end - - status_code(32) - end -end diff --git a/lib/ruby/stdlib/bundler/feature_flag.rb b/lib/ruby/stdlib/bundler/feature_flag.rb deleted file mode 100644 index 249170c4b29..00000000000 --- a/lib/ruby/stdlib/bundler/feature_flag.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class FeatureFlag - def self.settings_flag(flag, &default) - unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s) - raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key" - end - - settings_method("#{flag}?", flag, &default) - end - private_class_method :settings_flag - - def self.settings_option(key, &default) - settings_method(key, key, &default) - end - private_class_method :settings_option - - def self.settings_method(name, key, &default) - define_method(name) do - value = Bundler.settings[key] - value = instance_eval(&default) if value.nil? && !default.nil? - value - end - end - private_class_method :settings_method - - (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } } - - settings_flag(:allow_bundler_dependency_conflicts) { bundler_2_mode? } - settings_flag(:allow_offline_install) { bundler_2_mode? } - settings_flag(:auto_clean_without_path) { bundler_2_mode? } - settings_flag(:auto_config_jobs) { bundler_2_mode? } - settings_flag(:cache_all) { bundler_2_mode? } - settings_flag(:cache_command_is_package) { bundler_2_mode? } - settings_flag(:console_command) { !bundler_2_mode? } - settings_flag(:default_install_uses_path) { bundler_2_mode? } - settings_flag(:deployment_means_frozen) { bundler_2_mode? } - settings_flag(:disable_multisource) { bundler_2_mode? } - settings_flag(:error_on_stderr) { bundler_2_mode? } - settings_flag(:forget_cli_options) { bundler_2_mode? } - settings_flag(:global_path_appends_ruby_scope) { bundler_2_mode? } - settings_flag(:global_gem_cache) { bundler_2_mode? } - settings_flag(:init_gems_rb) { bundler_2_mode? } - settings_flag(:list_command) { bundler_2_mode? } - settings_flag(:lockfile_uses_separate_rubygems_sources) { bundler_2_mode? } - settings_flag(:only_update_to_newer_versions) { bundler_2_mode? } - settings_flag(:path_relative_to_cwd) { bundler_2_mode? } - settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } - settings_flag(:prefer_gems_rb) { bundler_2_mode? } - settings_flag(:print_only_version_number) { bundler_2_mode? } - settings_flag(:setup_makes_kernel_gem_public) { !bundler_2_mode? } - settings_flag(:skip_default_git_sources) { bundler_2_mode? } - settings_flag(:specific_platform) { bundler_2_mode? } - settings_flag(:suppress_install_using_messages) { bundler_2_mode? } - settings_flag(:unlock_source_unlocks_spec) { !bundler_2_mode? } - settings_flag(:update_requires_all_flag) { bundler_2_mode? } - settings_flag(:use_gem_version_promoter_for_major_updates) { bundler_2_mode? } - settings_flag(:viz_command) { !bundler_2_mode? } - - settings_option(:default_cli_command) { bundler_2_mode? ? :cli_help : :install } - - settings_method(:github_https?, "github.https") { bundler_2_mode? } - - def initialize(bundler_version) - @bundler_version = Gem::Version.create(bundler_version) - end - - def major_version - @bundler_version.segments.first - end - private :major_version - end -end diff --git a/lib/ruby/stdlib/bundler/fetcher.rb b/lib/ruby/stdlib/bundler/fetcher.rb deleted file mode 100644 index 4dd42e42ffa..00000000000 --- a/lib/ruby/stdlib/bundler/fetcher.rb +++ /dev/null @@ -1,312 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_persistent" -require "cgi" -require "securerandom" -require "zlib" - -module Bundler - # Handles all the fetching with the rubygems server - class Fetcher - autoload :CompactIndex, "bundler/fetcher/compact_index" - autoload :Downloader, "bundler/fetcher/downloader" - autoload :Dependency, "bundler/fetcher/dependency" - autoload :Index, "bundler/fetcher/index" - - # This error is raised when it looks like the network is down - class NetworkDownError < HTTPError; end - # This error is raised if the API returns a 413 (only printed in verbose) - class FallbackError < HTTPError; end - # This is the error raised if OpenSSL fails the cert verification - class CertificateFailureError < HTTPError - def initialize(remote_uri) - remote_uri = filter_uri(remote_uri) - super "Could not verify the SSL certificate for #{remote_uri}.\nThere" \ - " is a chance you are experiencing a man-in-the-middle attack, but" \ - " most likely your system doesn't have the CA certificates needed" \ - " for verification. For information about OpenSSL certificates, see" \ - " http://bit.ly/ruby-ssl. To connect without using SSL, edit your Gemfile" \ - " sources and change 'https' to 'http'." - end - end - # This is the error raised when a source is HTTPS and OpenSSL didn't load - class SSLError < HTTPError - def initialize(msg = nil) - super msg || "Could not load OpenSSL.\n" \ - "You must recompile Ruby with OpenSSL support or change the sources in your " \ - "Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL " \ - "using RVM are available at rvm.io/packages/openssl." - end - end - # This error is raised if HTTP authentication is required, but not provided. - class AuthenticationRequiredError < HTTPError - def initialize(remote_uri) - remote_uri = filter_uri(remote_uri) - super "Authentication is required for #{remote_uri}.\n" \ - "Please supply credentials for this source. You can do this by running:\n" \ - " bundle config #{remote_uri} username:password" - end - end - # This error is raised if HTTP authentication is provided, but incorrect. - class BadAuthenticationError < HTTPError - def initialize(remote_uri) - remote_uri = filter_uri(remote_uri) - super "Bad username or password for #{remote_uri}.\n" \ - "Please double-check your credentials and correct them." - end - end - - # Exceptions classes that should bypass retry attempts. If your password didn't work the - # first time, it's not going to the third time. - NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency, - :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed, - :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound, - :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge, - :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity, - :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze - FAIL_ERRORS = begin - fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError] - fail_errors << Gem::Requirement::BadRequirementError if defined?(Gem::Requirement::BadRequirementError) - fail_errors.concat(NET_ERRORS.map {|e| SharedHelpers.const_get_safely(e, Net) }.compact) - end.freeze - - class << self - attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries - end - - self.redirect_limit = Bundler.settings[:redirect] # How many redirects to allow in one request - self.api_timeout = Bundler.settings[:timeout] # How long to wait for each API call - self.max_retries = Bundler.settings[:retry] # How many retries for the API call - - def initialize(remote) - @remote = remote - - Socket.do_not_reverse_lookup = true - connection # create persistent connection - end - - def uri - @remote.anonymized_uri - end - - # fetch a gem specification - def fetch_spec(spec) - spec -= [nil, "ruby", ""] - spec_file_name = "#{spec.join "-"}.gemspec" - - uri = URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") - if uri.scheme == "file" - Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(uri.path)) - elsif cached_spec_path = gemspec_cached_path(spec_file_name) - Bundler.load_gemspec(cached_spec_path) - else - Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) - end - rescue MarshalError - raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ - "Your network or your gem server is probably having issues right now." - end - - # return the specs in the bundler format as an index with retries - def specs_with_retry(gem_names, source) - Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do - specs(gem_names, source) - end - end - - # return the specs in the bundler format as an index - def specs(gem_names, source) - old = Bundler.rubygems.sources - index = Bundler::Index.new - - if Bundler::Fetcher.disable_endpoint - @use_api = false - specs = fetchers.last.specs(gem_names) - else - specs = [] - fetchers.shift until fetchers.first.available? || fetchers.empty? - fetchers.dup.each do |f| - break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names) - fetchers.delete(f) - end - @use_api = false if fetchers.none?(&:api_fetcher?) - end - - specs.each do |name, version, platform, dependencies, metadata| - next if name == "bundler" - spec = if dependencies - EndpointSpecification.new(name, version, platform, dependencies, metadata) - else - RemoteSpecification.new(name, version, platform, self) - end - spec.source = source - spec.remote = @remote - index << spec - end - - index - rescue CertificateFailureError - Bundler.ui.info "" if gem_names && use_api # newline after dots - raise - ensure - Bundler.rubygems.sources = old - end - - def use_api - return @use_api if defined?(@use_api) - - fetchers.shift until fetchers.first.available? - - @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint - false - else - fetchers.first.api_fetcher? - end - end - - def user_agent - @user_agent ||= begin - ruby = Bundler::RubyVersion.system - - agent = String.new("bundler/#{Bundler::VERSION}") - agent << " rubygems/#{Gem::VERSION}" - agent << " ruby/#{ruby.versions_string(ruby.versions)}" - agent << " (#{ruby.host})" - agent << " command/#{ARGV.first}" - - if ruby.engine != "ruby" - # engine_version raises on unknown engines - engine_version = begin - ruby.engine_versions - rescue RuntimeError - "???" - end - agent << " #{ruby.engine}/#{ruby.versions_string(engine_version)}" - end - - agent << " options/#{Bundler.settings.all.join(",")}" - - agent << " ci/#{cis.join(",")}" if cis.any? - - # add a random ID so we can consolidate runs server-side - agent << " " << SecureRandom.hex(8) - - # add any user agent strings set in the config - extra_ua = Bundler.settings[:user_agent] - agent << " " << extra_ua if extra_ua - - agent - end - end - - def fetchers - @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) } - end - - def http_proxy - return unless uri = connection.proxy_uri - uri.to_s - end - - def inspect - "#<#{self.class}:0x#{object_id} uri=#{uri}>" - end - - private - - FETCHERS = [CompactIndex, Dependency, Index].freeze - - def cis - env_cis = { - "TRAVIS" => "travis", - "CIRCLECI" => "circle", - "SEMAPHORE" => "semaphore", - "JENKINS_URL" => "jenkins", - "BUILDBOX" => "buildbox", - "GO_SERVER_URL" => "go", - "SNAP_CI" => "snap", - "CI_NAME" => ENV["CI_NAME"], - "CI" => "ci" - } - env_cis.find_all {|env, _| ENV[env] }.map {|_, ci| ci } - end - - def connection - @connection ||= begin - needs_ssl = remote_uri.scheme == "https" || - Bundler.settings[:ssl_verify_mode] || - Bundler.settings[:ssl_client_cert] - raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) - - con = PersistentHTTP.new "bundler", :ENV - if gem_proxy = Bundler.rubygems.configuration[:http_proxy] - con.proxy = URI.parse(gem_proxy) if gem_proxy != :no_proxy - end - - if remote_uri.scheme == "https" - con.verify_mode = (Bundler.settings[:ssl_verify_mode] || - OpenSSL::SSL::VERIFY_PEER) - con.cert_store = bundler_cert_store - end - - ssl_client_cert = Bundler.settings[:ssl_client_cert] || - (Bundler.rubygems.configuration.ssl_client_cert if - Bundler.rubygems.configuration.respond_to?(:ssl_client_cert)) - if ssl_client_cert - pem = File.read(ssl_client_cert) - con.cert = OpenSSL::X509::Certificate.new(pem) - con.key = OpenSSL::PKey::RSA.new(pem) - end - - con.read_timeout = Fetcher.api_timeout - con.open_timeout = Fetcher.api_timeout - con.override_headers["User-Agent"] = user_agent - con.override_headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri - con - end - end - - # cached gem specification path, if one exists - def gemspec_cached_path(spec_file_name) - paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } - paths = paths.select {|path| File.file? path } - paths.first - end - - HTTP_ERRORS = [ - Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH, - Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN, - Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, - PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH - ].freeze - - def bundler_cert_store - store = OpenSSL::X509::Store.new - ssl_ca_cert = Bundler.settings[:ssl_ca_cert] || - (Bundler.rubygems.configuration.ssl_ca_cert if - Bundler.rubygems.configuration.respond_to?(:ssl_ca_cert)) - if ssl_ca_cert - if File.directory? ssl_ca_cert - store.add_path ssl_ca_cert - else - store.add_file ssl_ca_cert - end - else - store.set_default_paths - certs = File.expand_path("../ssl_certs/*/*.pem", __FILE__) - Dir.glob(certs).each {|c| store.add_file c } - end - store - end - - private - - def remote_uri - @remote.uri - end - - def downloader - @downloader ||= Downloader.new(connection, self.class.redirect_limit) - end - end -end diff --git a/lib/ruby/stdlib/bundler/fetcher/base.rb b/lib/ruby/stdlib/bundler/fetcher/base.rb deleted file mode 100644 index 27987f670ae..00000000000 --- a/lib/ruby/stdlib/bundler/fetcher/base.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Fetcher - class Base - attr_reader :downloader - attr_reader :display_uri - attr_reader :remote - - def initialize(downloader, remote, display_uri) - raise "Abstract class" if self.class == Base - @downloader = downloader - @remote = remote - @display_uri = display_uri - end - - def remote_uri - @remote.uri - end - - def fetch_uri - @fetch_uri ||= begin - if remote_uri.host == "rubygems.org" - uri = remote_uri.dup - uri.host = "index.rubygems.org" - uri - else - remote_uri - end - end - end - - def available? - true - end - - def api_fetcher? - false - end - - private - - def log_specs(debug_msg) - if Bundler.ui.debug? - Bundler.ui.debug debug_msg - else - Bundler.ui.info ".", false - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/fetcher/compact_index.rb b/lib/ruby/stdlib/bundler/fetcher/compact_index.rb deleted file mode 100644 index cfc74d642cf..00000000000 --- a/lib/ruby/stdlib/bundler/fetcher/compact_index.rb +++ /dev/null @@ -1,126 +0,0 @@ -# frozen_string_literal: true - -require "bundler/fetcher/base" -require "bundler/worker" - -module Bundler - autoload :CompactIndexClient, "bundler/compact_index_client" - - class Fetcher - class CompactIndex < Base - def self.compact_index_request(method_name) - method = instance_method(method_name) - undef_method(method_name) - define_method(method_name) do |*args, &blk| - begin - method.bind(self).call(*args, &blk) - rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e - raise HTTPError, e.message - rescue AuthenticationRequiredError - # Fail since we got a 401 from the server. - raise - rescue HTTPError => e - Bundler.ui.trace(e) - nil - end - end - end - - def specs(gem_names) - specs_for_names(gem_names) - end - compact_index_request :specs - - def specs_for_names(gem_names) - gem_info = [] - complete_gems = [] - remaining_gems = gem_names.dup - - until remaining_gems.empty? - log_specs "Looking up gems #{remaining_gems.inspect}" - - deps = compact_index_client.dependencies(remaining_gems) - next_gems = deps.map {|d| d[3].map(&:first).flatten(1) }.flatten(1).uniq - deps.each {|dep| gem_info << dep } - complete_gems.concat(deps.map(&:first)).uniq! - remaining_gems = next_gems - complete_gems - end - @bundle_worker.stop if @bundle_worker - @bundle_worker = nil # reset it. Not sure if necessary - - gem_info - end - - def fetch_spec(spec) - spec -= [nil, "ruby", ""] - contents = compact_index_client.spec(*spec) - return nil if contents.nil? - contents.unshift(spec.first) - contents[3].map! {|d| Gem::Dependency.new(*d) } - EndpointSpecification.new(*contents) - end - compact_index_request :fetch_spec - - def available? - return nil unless SharedHelpers.md5_available? - user_home = Bundler.user_home - return nil unless user_home.directory? && user_home.writable? - # Read info file checksums out of /versions, so we can know if gems are up to date - fetch_uri.scheme != "file" && compact_index_client.update_and_parse_checksums! - rescue CompactIndexClient::Updater::MisMatchedChecksumError => e - Bundler.ui.debug(e.message) - nil - end - compact_index_request :available? - - def api_fetcher? - true - end - - private - - def compact_index_client - @compact_index_client ||= begin - SharedHelpers.filesystem_access(cache_path) do - CompactIndexClient.new(cache_path, client_fetcher) - end.tap do |client| - client.in_parallel = lambda do |inputs, &blk| - func = lambda {|object, _index| blk.call(object) } - worker = bundle_worker(func) - inputs.each {|input| worker.enq(input) } - inputs.map { worker.deq } - end - end - end - end - - def bundle_worker(func = nil) - @bundle_worker ||= begin - worker_name = "Compact Index (#{display_uri.host})" - Bundler::Worker.new(Bundler.current_ruby.rbx? ? 1 : 25, worker_name, func) - end - @bundle_worker.tap do |worker| - worker.instance_variable_set(:@func, func) if func - end - end - - def cache_path - Bundler.user_cache.join("compact_index", remote.cache_slug) - end - - def client_fetcher - ClientFetcher.new(self, Bundler.ui) - end - - ClientFetcher = Struct.new(:fetcher, :ui) do - def call(path, headers) - fetcher.downloader.fetch(fetcher.fetch_uri + path, headers) - rescue NetworkDownError => e - raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"] - ui.warn "Using the cached data for the new index because of a network error: #{e}" - Net::HTTPNotModified.new(nil, nil, nil) - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/fetcher/dependency.rb b/lib/ruby/stdlib/bundler/fetcher/dependency.rb deleted file mode 100644 index 1430d1ebeb9..00000000000 --- a/lib/ruby/stdlib/bundler/fetcher/dependency.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -require "bundler/fetcher/base" -require "cgi" - -module Bundler - class Fetcher - class Dependency < Base - def available? - @available ||= fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri) - rescue NetworkDownError => e - raise HTTPError, e.message - rescue AuthenticationRequiredError - # Fail since we got a 401 from the server. - raise - rescue HTTPError - false - end - - def api_fetcher? - true - end - - def specs(gem_names, full_dependency_list = [], last_spec_list = []) - query_list = gem_names.uniq - full_dependency_list - - log_specs "Query List: #{query_list.inspect}" - - return last_spec_list if query_list.empty? - - spec_list, deps_list = Bundler::Retry.new("dependency api", FAIL_ERRORS).attempts do - dependency_specs(query_list) - end - - returned_gems = spec_list.map(&:first).uniq - specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) - rescue MarshalError - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - Bundler.ui.debug "could not fetch from the dependency API, trying the full index" - nil - rescue HTTPError, GemspecError - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - Bundler.ui.debug "could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`" - nil - end - - def dependency_specs(gem_names) - Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(",")}" - - gem_list = unmarshalled_dep_gems(gem_names) - get_formatted_specs_and_deps(gem_list) - end - - def unmarshalled_dep_gems(gem_names) - gem_list = [] - gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names| - marshalled_deps = downloader.fetch(dependency_api_uri(names)).body - gem_list.concat(Bundler.load_marshal(marshalled_deps)) - end - gem_list - end - - def get_formatted_specs_and_deps(gem_list) - deps_list = [] - spec_list = [] - - gem_list.each do |s| - deps_list.concat(s[:dependencies].map(&:first)) - deps = s[:dependencies].map {|n, d| [n, d.split(", ")] } - spec_list.push([s[:name], s[:number], s[:platform], deps]) - end - [spec_list, deps_list] - end - - def dependency_api_uri(gem_names = []) - uri = fetch_uri + "api/v1/dependencies" - uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any? - uri - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/fetcher/downloader.rb b/lib/ruby/stdlib/bundler/fetcher/downloader.rb deleted file mode 100644 index e0e0cbf1c9a..00000000000 --- a/lib/ruby/stdlib/bundler/fetcher/downloader.rb +++ /dev/null @@ -1,84 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Fetcher - class Downloader - attr_reader :connection - attr_reader :redirect_limit - - def initialize(connection, redirect_limit) - @connection = connection - @redirect_limit = redirect_limit - end - - def fetch(uri, headers = {}, counter = 0) - raise HTTPError, "Too many redirects" if counter >= redirect_limit - - response = request(uri, headers) - Bundler.ui.debug("HTTP #{response.code} #{response.message} #{uri}") - - case response - when Net::HTTPSuccess, Net::HTTPNotModified - response - when Net::HTTPRedirection - new_uri = URI.parse(response["location"]) - if new_uri.host == uri.host - new_uri.user = uri.user - new_uri.password = uri.password - end - fetch(new_uri, headers, counter + 1) - when Net::HTTPRequestedRangeNotSatisfiable - new_headers = headers.dup - new_headers.delete("Range") - new_headers["Accept-Encoding"] = "gzip" - fetch(uri, new_headers) - when Net::HTTPRequestEntityTooLarge - raise FallbackError, response.body - when Net::HTTPUnauthorized - raise AuthenticationRequiredError, uri.host - when Net::HTTPNotFound - raise FallbackError, "Net::HTTPNotFound" - else - raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}" - end - end - - def request(uri, headers) - validate_uri_scheme!(uri) - - Bundler.ui.debug "HTTP GET #{uri}" - req = Net::HTTP::Get.new uri.request_uri, headers - if uri.user - user = CGI.unescape(uri.user) - password = uri.password ? CGI.unescape(uri.password) : nil - req.basic_auth(user, password) - end - connection.request(uri, req) - rescue NoMethodError => e - raise unless ["undefined method", "use_ssl="].all? {|snippet| e.message.include? snippet } - raise LoadError.new("cannot load such file -- openssl") - rescue OpenSSL::SSL::SSLError - raise CertificateFailureError.new(uri) - rescue *HTTP_ERRORS => e - Bundler.ui.trace e - case e.message - when /host down:/, /getaddrinfo: nodename nor servname provided/ - raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ - "connection and try again." - else - raise HTTPError, "Network error while fetching #{URICredentialsFilter.credential_filtered_uri(uri)}" \ - " (#{e})" - end - end - - private - - def validate_uri_scheme!(uri) - return if uri.scheme =~ /\Ahttps?\z/ - raise InvalidOption, - "The request uri `#{uri}` has an invalid scheme (`#{uri.scheme}`). " \ - "Did you mean `http` or `https`?" - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/fetcher/index.rb b/lib/ruby/stdlib/bundler/fetcher/index.rb deleted file mode 100644 index 1a8064624d8..00000000000 --- a/lib/ruby/stdlib/bundler/fetcher/index.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require "bundler/fetcher/base" -require "rubygems/remote_fetcher" - -module Bundler - class Fetcher - class Index < Base - def specs(_gem_names) - Bundler.rubygems.fetch_all_remote_specs(remote) - rescue Gem::RemoteFetcher::FetchError, OpenSSL::SSL::SSLError, Net::HTTPFatalError => e - case e.message - when /certificate verify failed/ - raise CertificateFailureError.new(display_uri) - when /401/ - raise AuthenticationRequiredError, remote_uri - when /403/ - raise BadAuthenticationError, remote_uri if remote_uri.userinfo - raise AuthenticationRequiredError, remote_uri - else - Bundler.ui.trace e - raise HTTPError, "Could not fetch specs from #{display_uri}" - end - end - - def fetch_spec(spec) - spec -= [nil, "ruby", ""] - spec_file_name = "#{spec.join "-"}.gemspec" - - uri = URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") - if uri.scheme == "file" - Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(uri.path)) - elsif cached_spec_path = gemspec_cached_path(spec_file_name) - Bundler.load_gemspec(cached_spec_path) - else - Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) - end - rescue MarshalError - raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ - "Your network or your gem server is probably having issues right now." - end - - private - - # cached gem specification path, if one exists - def gemspec_cached_path(spec_file_name) - paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } - paths.find {|path| File.file? path } - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/friendly_errors.rb b/lib/ruby/stdlib/bundler/friendly_errors.rb deleted file mode 100644 index ae3299a7c8c..00000000000 --- a/lib/ruby/stdlib/bundler/friendly_errors.rb +++ /dev/null @@ -1,131 +0,0 @@ -# encoding: utf-8 -# frozen_string_literal: true - -require "cgi" -require "bundler/vendored_thor" - -module Bundler - module FriendlyErrors - module_function - - def log_error(error) - case error - when YamlSyntaxError - Bundler.ui.error error.message - Bundler.ui.trace error.orig_exception - when Dsl::DSLError, GemspecError - Bundler.ui.error error.message - when GemRequireError - Bundler.ui.error error.message - Bundler.ui.trace error.orig_exception, nil, true - when BundlerError - Bundler.ui.error error.message, :wrap => true - Bundler.ui.trace error - when Thor::Error - Bundler.ui.error error.message - when LoadError - raise error unless error.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/ - Bundler.ui.error "\nCould not load OpenSSL." - Bundler.ui.warn <<-WARN, :wrap => true - You must recompile Ruby with OpenSSL support or change the sources in your \ - Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL \ - using RVM are available at http://rvm.io/packages/openssl. - WARN - Bundler.ui.trace error - when Interrupt - Bundler.ui.error "\nQuitting..." - Bundler.ui.trace error - when Gem::InvalidSpecificationException - Bundler.ui.error error.message, :wrap => true - when SystemExit - when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact - Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \ - "You can decrease the amount of memory Bundler needs by removing gems from your Gemfile, " \ - "especially large gems. (Gems can be as large as hundreds of megabytes, and Bundler has to read those files!). " \ - "Alternatively, you can increase the amount of memory the JVM is able to use by running Bundler with jruby -J-Xmx1024m -S bundle (JRuby defaults to 500MB)." - else request_issue_report_for(error) - end - rescue - raise error - end - - def exit_status(error) - case error - when BundlerError then error.status_code - when Thor::Error then 15 - when SystemExit then error.status - else 1 - end - end - - def request_issue_report_for(e) - Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") - --- ERROR REPORT TEMPLATE ------------------------------------------------------- - # Error Report - - ## Questions - - Please fill out answers to these questions, it'll help us figure out - why things are going wrong. - - - **What did you do?** - - I ran the command `#{$PROGRAM_NAME} #{ARGV.join(" ")}` - - - **What did you expect to happen?** - - I expected Bundler to... - - - **What happened instead?** - - Instead, what happened was... - - - **Have you tried any solutions posted on similar issues in our issue tracker, stack overflow, or google?** - - I tried... - - - **Have you read our issues document, https://github.com/bundler/bundler/blob/master/doc/contributing/ISSUES.md?** - - ... - - ## Backtrace - - ``` - #{e.class}: #{e.message} - #{e.backtrace && e.backtrace.join("\n ").chomp} - ``` - - #{Bundler::Env.report} - --- TEMPLATE END ---------------------------------------------------------------- - - EOS - - Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue." - - Bundler.ui.warn <<-EOS.gsub(/^ {8}/, "") - - First, try this link to see if there are any existing issue reports for this error: - #{issues_url(e)} - - If there aren't any reports for this error yet, please create copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: - https://github.com/bundler/bundler/issues/new - EOS - end - - def issues_url(exception) - message = exception.message.lines.first.tr(":", " ").chomp - message = message.split("-").first if exception.is_a?(Errno) - "https://github.com/bundler/bundler/search?q=" \ - "#{CGI.escape(message)}&type=Issues" - end - end - - def self.with_friendly_errors - yield - rescue SignalException - raise - rescue Exception => e - FriendlyErrors.log_error(e) - exit FriendlyErrors.exit_status(e) - end -end diff --git a/lib/ruby/stdlib/bundler/gem_helper.rb b/lib/ruby/stdlib/bundler/gem_helper.rb deleted file mode 100644 index e7673cba883..00000000000 --- a/lib/ruby/stdlib/bundler/gem_helper.rb +++ /dev/null @@ -1,202 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_thor" unless defined?(Thor) -require "bundler" - -module Bundler - class GemHelper - include Rake::DSL if defined? Rake::DSL - - class << self - # set when install'd. - attr_accessor :instance - - def install_tasks(opts = {}) - new(opts[:dir], opts[:name]).install - end - - def gemspec(&block) - gemspec = instance.gemspec - block.call(gemspec) if block - gemspec - end - end - - attr_reader :spec_path, :base, :gemspec - - def initialize(base = nil, name = nil) - Bundler.ui = UI::Shell.new - @base = (base ||= SharedHelpers.pwd) - gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "{,*}.gemspec")] - raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 - @spec_path = gemspecs.first - @gemspec = Bundler.load_gemspec(@spec_path) - end - - def install - built_gem_path = nil - - desc "Build #{name}-#{version}.gem into the pkg directory." - task "build" do - built_gem_path = build_gem - end - - desc "Build and install #{name}-#{version}.gem into system gems." - task "install" => "build" do - install_gem(built_gem_path) - end - - desc "Build and install #{name}-#{version}.gem into system gems without network access." - task "install:local" => "build" do - install_gem(built_gem_path, :local) - end - - desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to #{gem_push_host}\n" \ - "To prevent publishing in RubyGems use `gem_push=no rake release`" - task "release", [:remote] => ["build", "release:guard_clean", - "release:source_control_push", "release:rubygem_push"] do - end - - task "release:guard_clean" do - guard_clean - end - - task "release:source_control_push", [:remote] do |_, args| - tag_version { git_push(args[:remote]) } unless already_tagged? - end - - task "release:rubygem_push" do - rubygem_push(built_gem_path) if gem_push? - end - - GemHelper.instance = self - end - - def build_gem - file_name = nil - sh("gem build -V '#{spec_path}'") do - file_name = File.basename(built_gem_path) - SharedHelpers.filesystem_access(File.join(base, "pkg")) {|p| FileUtils.mkdir_p(p) } - FileUtils.mv(built_gem_path, "pkg") - Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}." - end - File.join(base, "pkg", file_name) - end - - def install_gem(built_gem_path = nil, local = false) - built_gem_path ||= build_gem - out, _ = sh_with_code("gem install '#{built_gem_path}'#{" --local" if local}") - raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/] - Bundler.ui.confirm "#{name} (#{version}) installed." - end - - protected - - def rubygem_push(path) - gem_command = "gem push '#{path}'" - gem_command += " --key #{gem_key}" if gem_key - gem_command += " --host #{allowed_push_host}" if allowed_push_host - unless allowed_push_host || Bundler.user_home.join(".gem/credentials").file? - raise "Your rubygems.org credentials aren't set. Run `gem push` to set them." - end - sh(gem_command) - Bundler.ui.confirm "Pushed #{name} #{version} to #{gem_push_host}" - end - - def built_gem_path - Dir[File.join(base, "#{name}-*.gem")].sort_by {|f| File.mtime(f) }.last - end - - def git_push(remote = "") - perform_git_push remote - perform_git_push "#{remote} --tags" - Bundler.ui.confirm "Pushed git commits and tags." - end - - def allowed_push_host - @gemspec.metadata["allowed_push_host"] if @gemspec.respond_to?(:metadata) - end - - def gem_push_host - env_rubygems_host = ENV["RUBYGEMS_HOST"] - env_rubygems_host = nil if - env_rubygems_host && env_rubygems_host.empty? - - allowed_push_host || env_rubygems_host || "rubygems.org" - end - - def perform_git_push(options = "") - cmd = "git push #{options}" - out, code = sh_with_code(cmd) - raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" unless code == 0 - end - - def already_tagged? - return false unless sh("git tag").split(/\n/).include?(version_tag) - Bundler.ui.confirm "Tag #{version_tag} has already been created." - true - end - - def guard_clean - clean? && committed? || raise("There are files that need to be committed first.") - end - - def clean? - sh_with_code("git diff --exit-code")[1] == 0 - end - - def committed? - sh_with_code("git diff-index --quiet --cached HEAD")[1] == 0 - end - - def tag_version - sh "git tag -m \"Version #{version}\" #{version_tag}" - Bundler.ui.confirm "Tagged #{version_tag}." - yield if block_given? - rescue RuntimeError - Bundler.ui.error "Untagging #{version_tag} due to error." - sh_with_code "git tag -d #{version_tag}" - raise - end - - def version - gemspec.version - end - - def version_tag - "v#{version}" - end - - def name - gemspec.name - end - - def sh(cmd, &block) - out, code = sh_with_code(cmd, &block) - unless code.zero? - raise(out.empty? ? "Running `#{cmd}` failed. Run this command directly for more detailed output." : out) - end - out - end - - def sh_with_code(cmd, &block) - cmd += " 2>&1" - outbuf = String.new - Bundler.ui.debug(cmd) - SharedHelpers.chdir(base) do - outbuf = `#{cmd}` - status = $?.exitstatus - block.call(outbuf) if status.zero? && block - [outbuf, status] - end - end - - def gem_key - Bundler.settings["gem.push_key"].to_s.downcase if Bundler.settings["gem.push_key"] - end - - def gem_push? - !%w[n no nil false off 0].include?(ENV["gem_push"].to_s.downcase) - end - end -end diff --git a/lib/ruby/stdlib/bundler/gem_helpers.rb b/lib/ruby/stdlib/bundler/gem_helpers.rb deleted file mode 100644 index 019ae10c66c..00000000000 --- a/lib/ruby/stdlib/bundler/gem_helpers.rb +++ /dev/null @@ -1,101 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module GemHelpers - GENERIC_CACHE = {} # rubocop:disable MutableConstant - GENERICS = [ - [Gem::Platform.new("java"), Gem::Platform.new("java")], - [Gem::Platform.new("mswin32"), Gem::Platform.new("mswin32")], - [Gem::Platform.new("mswin64"), Gem::Platform.new("mswin64")], - [Gem::Platform.new("universal-mingw32"), Gem::Platform.new("universal-mingw32")], - [Gem::Platform.new("x64-mingw32"), Gem::Platform.new("x64-mingw32")], - [Gem::Platform.new("x86_64-mingw32"), Gem::Platform.new("x64-mingw32")], - [Gem::Platform.new("mingw32"), Gem::Platform.new("x86-mingw32")] - ].freeze - - def generic(p) - return p if p == Gem::Platform::RUBY - - GENERIC_CACHE[p] ||= begin - _, found = GENERICS.find do |match, _generic| - p.os == match.os && (!match.cpu || p.cpu == match.cpu) - end - found || Gem::Platform::RUBY - end - end - module_function :generic - - def generic_local_platform - generic(Bundler.local_platform) - end - module_function :generic_local_platform - - def platform_specificity_match(spec_platform, user_platform) - spec_platform = Gem::Platform.new(spec_platform) - return PlatformMatch::EXACT_MATCH if spec_platform == user_platform - return PlatformMatch::WORST_MATCH if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY - - PlatformMatch.new( - PlatformMatch.os_match(spec_platform, user_platform), - PlatformMatch.cpu_match(spec_platform, user_platform), - PlatformMatch.platform_version_match(spec_platform, user_platform) - ) - end - module_function :platform_specificity_match - - def select_best_platform_match(specs, platform) - specs.select {|spec| spec.match_platform(platform) }. - min_by {|spec| platform_specificity_match(spec.platform, platform) } - end - module_function :select_best_platform_match - - PlatformMatch = Struct.new(:os_match, :cpu_match, :platform_version_match) - class PlatformMatch - def <=>(other) - return nil unless other.is_a?(PlatformMatch) - - m = os_match <=> other.os_match - return m unless m.zero? - - m = cpu_match <=> other.cpu_match - return m unless m.zero? - - m = platform_version_match <=> other.platform_version_match - m - end - - EXACT_MATCH = new(-1, -1, -1).freeze - WORST_MATCH = new(1_000_000, 1_000_000, 1_000_000).freeze - - def self.os_match(spec_platform, user_platform) - if spec_platform.os == user_platform.os - 0 - else - 1 - end - end - - def self.cpu_match(spec_platform, user_platform) - if spec_platform.cpu == user_platform.cpu - 0 - elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm") - 0 - elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal" - 1 - else - 2 - end - end - - def self.platform_version_match(spec_platform, user_platform) - if spec_platform.version == user_platform.version - 0 - elsif spec_platform.version.nil? - 1 - else - 2 - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/gem_remote_fetcher.rb b/lib/ruby/stdlib/bundler/gem_remote_fetcher.rb deleted file mode 100644 index 9577535d63c..00000000000 --- a/lib/ruby/stdlib/bundler/gem_remote_fetcher.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require "rubygems/remote_fetcher" - -module Bundler - # Adds support for setting custom HTTP headers when fetching gems from the - # server. - # - # TODO: Get rid of this when and if gemstash only supports RubyGems versions - # that contain https://github.com/rubygems/rubygems/commit/3db265cc20b2f813. - class GemRemoteFetcher < Gem::RemoteFetcher - attr_accessor :headers - - # Extracted from RubyGems 2.4. - def fetch_http(uri, last_modified = nil, head = false, depth = 0) - fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get - # beginning of change - response = request uri, fetch_type, last_modified do |req| - headers.each {|k, v| req.add_field(k, v) } if headers - end - # end of change - - case response - when Net::HTTPOK, Net::HTTPNotModified then - response.uri = uri if response.respond_to? :uri - head ? response : response.body - when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, - Net::HTTPTemporaryRedirect then - raise FetchError.new("too many redirects", uri) if depth > 10 - - location = URI.parse response["Location"] - - if https?(uri) && !https?(location) - raise FetchError.new("redirecting to non-https resource: #{location}", uri) - end - - fetch_http(location, last_modified, head, depth + 1) - else - raise FetchError.new("bad response #{response.message} #{response.code}", uri) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/gem_tasks.rb b/lib/ruby/stdlib/bundler/gem_tasks.rb deleted file mode 100644 index f736517bd76..00000000000 --- a/lib/ruby/stdlib/bundler/gem_tasks.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require "rake/clean" -CLOBBER.include "pkg" - -require "bundler/gem_helper" -Bundler::GemHelper.install_tasks diff --git a/lib/ruby/stdlib/bundler/gem_version_promoter.rb b/lib/ruby/stdlib/bundler/gem_version_promoter.rb deleted file mode 100644 index adb951a7a0c..00000000000 --- a/lib/ruby/stdlib/bundler/gem_version_promoter.rb +++ /dev/null @@ -1,190 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # This class contains all of the logic for determining the next version of a - # Gem to update to based on the requested level (patch, minor, major). - # Primarily designed to work with Resolver which will provide it the list of - # available dependency versions as found in its index, before returning it to - # to the resolution engine to select the best version. - class GemVersionPromoter - DEBUG = ENV["DEBUG_RESOLVER"] - - attr_reader :level, :locked_specs, :unlock_gems - - # By default, strict is false, meaning every available version of a gem - # is returned from sort_versions. The order gives preference to the - # requested level (:patch, :minor, :major) but in complicated requirement - # cases some gems will by necessity by promoted past the requested level, - # or even reverted to older versions. - # - # If strict is set to true, the results from sort_versions will be - # truncated, eliminating any version outside the current level scope. - # This can lead to unexpected outcomes or even VersionConflict exceptions - # that report a version of a gem not existing for versions that indeed do - # existing in the referenced source. - attr_accessor :strict - - attr_accessor :prerelease_specified - - # Given a list of locked_specs and a list of gems to unlock creates a - # GemVersionPromoter instance. - # - # @param locked_specs [SpecSet] All current locked specs. Unlike Definition - # where this list is empty if all gems are being updated, this should - # always be populated for all gems so this class can properly function. - # @param unlock_gems [String] List of gem names being unlocked. If empty, - # all gems will be considered unlocked. - # @return [GemVersionPromoter] - def initialize(locked_specs = SpecSet.new([]), unlock_gems = []) - @level = :major - @strict = false - @locked_specs = locked_specs - @unlock_gems = unlock_gems - @sort_versions = {} - @prerelease_specified = {} - end - - # @param value [Symbol] One of three Symbols: :major, :minor or :patch. - def level=(value) - v = case value - when String, Symbol - value.to_sym - end - - raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v) - @level = v - end - - # Given a Dependency and an Array of SpecGroups of available versions for a - # gem, this method will return the Array of SpecGroups sorted (and possibly - # truncated if strict is true) in an order to give preference to the current - # level (:major, :minor or :patch) when resolution is deciding what versions - # best resolve all dependencies in the bundle. - # @param dep [Dependency] The Dependency of the gem. - # @param spec_groups [SpecGroup] An array of SpecGroups for the same gem - # named in the @dep param. - # @return [SpecGroup] A new instance of the SpecGroup Array sorted and - # possibly filtered. - def sort_versions(dep, spec_groups) - before_result = "before sort_versions: #{debug_format_result(dep, spec_groups).inspect}" if DEBUG - - @sort_versions[dep] ||= begin - gem_name = dep.name - - # An Array per version returned, different entries for different platforms. - # We only need the version here so it's ok to hard code this to the first instance. - locked_spec = locked_specs[gem_name].first - - if strict - filter_dep_specs(spec_groups, locked_spec) - else - sort_dep_specs(spec_groups, locked_spec) - end.tap do |specs| - if DEBUG - STDERR.puts before_result - STDERR.puts " after sort_versions: #{debug_format_result(dep, specs).inspect}" - end - end - end - end - - # @return [bool] Convenience method for testing value of level variable. - def major? - level == :major - end - - # @return [bool] Convenience method for testing value of level variable. - def minor? - level == :minor - end - - private - - def filter_dep_specs(spec_groups, locked_spec) - res = spec_groups.select do |spec_group| - if locked_spec && !major? - gsv = spec_group.version - lsv = locked_spec.version - - must_match = minor? ? [0] : [0, 1] - - matches = must_match.map {|idx| gsv.segments[idx] == lsv.segments[idx] } - (matches.uniq == [true]) ? (gsv >= lsv) : false - else - true - end - end - - sort_dep_specs(res, locked_spec) - end - - def sort_dep_specs(spec_groups, locked_spec) - return spec_groups unless locked_spec - @gem_name = locked_spec.name - @locked_version = locked_spec.version - - result = spec_groups.sort do |a, b| - @a_ver = a.version - @b_ver = b.version - - unless @prerelease_specified[@gem_name] - a_pre = @a_ver.prerelease? - b_pre = @b_ver.prerelease? - - next -1 if a_pre && !b_pre - next 1 if b_pre && !a_pre - end - - if major? - @a_ver <=> @b_ver - elsif either_version_older_than_locked - @a_ver <=> @b_ver - elsif segments_do_not_match(:major) - @b_ver <=> @a_ver - elsif !minor? && segments_do_not_match(:minor) - @b_ver <=> @a_ver - else - @a_ver <=> @b_ver - end - end - post_sort(result) - end - - def either_version_older_than_locked - @a_ver < @locked_version || @b_ver < @locked_version - end - - def segments_do_not_match(level) - index = [:major, :minor].index(level) - @a_ver.segments[index] != @b_ver.segments[index] - end - - def unlocking_gem? - unlock_gems.empty? || unlock_gems.include?(@gem_name) - end - - # Specific version moves can't always reliably be done during sorting - # as not all elements are compared against each other. - def post_sort(result) - # default :major behavior in Bundler does not do this - return result if major? - if unlocking_gem? - result - else - move_version_to_end(result, @locked_version) - end - end - - def move_version_to_end(result, version) - move, keep = result.partition {|s| s.version.to_s == version.to_s } - keep.concat(move) - end - - def debug_format_result(dep, spec_groups) - a = [dep.to_s, - spec_groups.map {|sg| [sg.version, sg.dependencies_for_activated_platforms.map {|dp| [dp.name, dp.requirement.to_s] }] }] - last_map = a.last.map {|sg_data| [sg_data.first.version, sg_data.last.map {|aa| aa.join(" ") }] } - [a.first, last_map, level, strict ? :strict : :not_strict] - end - end -end diff --git a/lib/ruby/stdlib/bundler/gemdeps.rb b/lib/ruby/stdlib/bundler/gemdeps.rb deleted file mode 100644 index cd4b25d0e69..00000000000 --- a/lib/ruby/stdlib/bundler/gemdeps.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Gemdeps - def initialize(runtime) - @runtime = runtime - end - - def requested_specs - @runtime.requested_specs - end - - def specs - @runtime.specs - end - - def dependencies - @runtime.dependencies - end - - def current_dependencies - @runtime.current_dependencies - end - - def requires - @runtime.requires - end - end -end diff --git a/lib/ruby/stdlib/bundler/graph.rb b/lib/ruby/stdlib/bundler/graph.rb deleted file mode 100644 index de6bba02148..00000000000 --- a/lib/ruby/stdlib/bundler/graph.rb +++ /dev/null @@ -1,152 +0,0 @@ -# frozen_string_literal: true - -require "set" -module Bundler - class Graph - GRAPH_NAME = :Gemfile - - def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = []) - @env = env - @output_file = output_file - @show_version = show_version - @show_requirements = show_requirements - @output_format = output_format - @without_groups = without.map(&:to_sym) - - @groups = [] - @relations = Hash.new {|h, k| h[k] = Set.new } - @node_options = {} - @edge_options = {} - - _populate_relations - end - - attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format - - def viz - GraphVizClient.new(self).run - end - - private - - def _populate_relations - parent_dependencies = _groups.values.to_set.flatten - loop do - break if parent_dependencies.empty? - - tmp = Set.new - parent_dependencies.each do |dependency| - child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set - @relations[dependency.name] += child_dependencies.map(&:name).to_set - tmp += child_dependencies - - @node_options[dependency.name] = _make_label(dependency, :node) - child_dependencies.each do |c_dependency| - @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge) - end - end - parent_dependencies = tmp - end - end - - def _groups - relations = Hash.new {|h, k| h[k] = Set.new } - @env.current_dependencies.each do |dependency| - dependency.groups.each do |group| - next if @without_groups.include?(group) - - relations[group.to_s].add(dependency) - @relations[group.to_s].add(dependency.name) - - @node_options[group.to_s] ||= _make_label(group, :node) - @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge) - end - end - @groups = relations.keys - relations - end - - def _make_label(symbol_or_string_or_dependency, element_type) - case element_type.to_sym - when :node - if symbol_or_string_or_dependency.is_a?(Gem::Dependency) - label = symbol_or_string_or_dependency.name.dup - label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version - else - label = symbol_or_string_or_dependency.to_s - end - when :edge - label = nil - if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements - tmp = symbol_or_string_or_dependency.requirements_list.join(", ") - label = tmp if tmp != ">= 0" - end - else - raise ArgumentError, "2nd argument is invalid" - end - label.nil? ? {} : { :label => label } - end - - def spec_for_dependency(dependency) - @env.requested_specs.find {|s| s.name == dependency.name } - end - - class GraphVizClient - def initialize(graph_instance) - @graph_name = graph_instance.class::GRAPH_NAME - @groups = graph_instance.groups - @relations = graph_instance.relations - @node_options = graph_instance.node_options - @edge_options = graph_instance.edge_options - @output_file = graph_instance.output_file - @output_format = graph_instance.output_format - end - - def g - @g ||= ::GraphViz.digraph(@graph_name, :concentrate => true, :normalize => true, :nodesep => 0.55) do |g| - g.edge[:weight] = 2 - g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif" - g.edge[:fontsize] = 12 - end - end - - def run - @groups.each do |group| - g.add_nodes( - group, { - :style => "filled", - :fillcolor => "#B9B9D5", - :shape => "box3d", - :fontsize => 16 - }.merge(@node_options[group]) - ) - end - - @relations.each do |parent, children| - children.each do |child| - if @groups.include?(parent) - g.add_nodes(child, { :style => "filled", :fillcolor => "#B9B9D5" }.merge(@node_options[child])) - g.add_edges(parent, child, { :constraint => false }.merge(@edge_options["#{parent}_#{child}"])) - else - g.add_nodes(child, @node_options[child]) - g.add_edges(parent, child, @edge_options["#{parent}_#{child}"]) - end - end - end - - if @output_format.to_s == "debug" - $stdout.puts g.output :none => String - Bundler.ui.info "debugging bundle viz..." - else - begin - g.output @output_format.to_sym => "#{@output_file}.#{@output_format}" - Bundler.ui.info "#{@output_file}.#{@output_format}" - rescue ArgumentError => e - $stderr.puts "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb" - raise e - end - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/index.rb b/lib/ruby/stdlib/bundler/index.rb deleted file mode 100644 index 9166a927388..00000000000 --- a/lib/ruby/stdlib/bundler/index.rb +++ /dev/null @@ -1,213 +0,0 @@ -# frozen_string_literal: true - -require "set" - -module Bundler - class Index - include Enumerable - - def self.build - i = new - yield i - i - end - - attr_reader :specs, :all_specs, :sources - protected :specs, :all_specs - - RUBY = "ruby".freeze - NULL = "\0".freeze - - def initialize - @sources = [] - @cache = {} - @specs = Hash.new {|h, k| h[k] = {} } - @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } - end - - def initialize_copy(o) - @sources = o.sources.dup - @cache = {} - @specs = Hash.new {|h, k| h[k] = {} } - @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH } - - o.specs.each do |name, hash| - @specs[name] = hash.dup - end - o.all_specs.each do |name, array| - @all_specs[name] = array.dup - end - end - - def inspect - "#<#{self.class}:0x#{object_id} sources=#{sources.map(&:inspect)} specs.size=#{specs.size}>" - end - - def empty? - each { return false } - true - end - - def search_all(name) - all_matches = local_search(name) + @all_specs[name] - @sources.each do |source| - all_matches.concat(source.search_all(name)) - end - all_matches - end - - # Search this index's specs, and any source indexes that this index knows - # about, returning all of the results. - def search(query, base = nil) - sort_specs(unsorted_search(query, base)) - end - - def unsorted_search(query, base) - results = local_search(query, base) - - seen = results.map(&:full_name).to_set unless @sources.empty? - - @sources.each do |source| - source.unsorted_search(query, base).each do |spec| - results << spec if seen.add?(spec.full_name) - end - end - - results - end - protected :unsorted_search - - def self.sort_specs(specs) - specs.sort_by do |s| - platform_string = s.platform.to_s - [s.version, platform_string == RUBY ? NULL : platform_string] - end - end - - def sort_specs(specs) - self.class.sort_specs(specs) - end - - def local_search(query, base = nil) - case query - when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) - when String then specs_by_name(query) - when Gem::Dependency then search_by_dependency(query, base) - when DepProxy then search_by_dependency(query.dep, base) - else - raise "You can't search for a #{query.inspect}." - end - end - - alias_method :[], :search - - def <<(spec) - @specs[spec.name][spec.full_name] = spec - spec - end - - def each(&blk) - return enum_for(:each) unless blk - specs.values.each do |spec_sets| - spec_sets.values.each(&blk) - end - sources.each {|s| s.each(&blk) } - self - end - - def spec_names - names = specs.keys + sources.map(&:spec_names) - names.uniq! - names - end - - # returns a list of the dependencies - def unmet_dependency_names - dependency_names.select do |name| - name != "bundler" && search(name).empty? - end - end - - def dependency_names - names = [] - each do |spec| - spec.dependencies.each do |dep| - next if dep.type == :development - names << dep.name - end - end - names.uniq - end - - def use(other, override_dupes = false) - return unless other - other.each do |s| - if (dupes = search_by_spec(s)) && !dupes.empty? - # safe to << since it's a new array when it has contents - @all_specs[s.name] = dupes << s - next unless override_dupes - end - self << s - end - self - end - - def size - @sources.inject(@specs.size) do |size, source| - size += source.size - end - end - - # Whether all the specs in self are in other - # TODO: rename to #include? - def ==(other) - all? do |spec| - other_spec = other[spec].first - other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source - end - end - - def dependencies_eql?(spec, other_spec) - deps = spec.dependencies.select {|d| d.type != :development } - other_deps = other_spec.dependencies.select {|d| d.type != :development } - Set.new(deps) == Set.new(other_deps) - end - - def add_source(index) - raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index) - @sources << index - @sources.uniq! # need to use uniq! here instead of checking for the item before adding - end - - private - - def specs_by_name(name) - @specs[name].values - end - - def search_by_dependency(dependency, base = nil) - @cache[base || false] ||= {} - @cache[base || false][dependency] ||= begin - specs = specs_by_name(dependency.name) - specs += base if base - found = specs.select do |spec| - next true if spec.source.is_a?(Source::Gemspec) - if base # allow all platforms when searching from a lockfile - dependency.matches_spec?(spec) - else - dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform) - end - end - - found - end - end - - EMPTY_SEARCH = [].freeze - - def search_by_spec(spec) - spec = @specs[spec.name][spec.full_name] - spec ? [spec] : EMPTY_SEARCH - end - end -end diff --git a/lib/ruby/stdlib/bundler/injector.rb b/lib/ruby/stdlib/bundler/injector.rb deleted file mode 100644 index 1bb29f0b367..00000000000 --- a/lib/ruby/stdlib/bundler/injector.rb +++ /dev/null @@ -1,253 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Injector - INJECTED_GEMS = "injected gems".freeze - - def self.inject(new_deps, options = {}) - injector = new(new_deps, options) - injector.inject(Bundler.default_gemfile, Bundler.default_lockfile) - end - - def self.remove(gems, options = {}) - injector = new(gems, options) - injector.remove(Bundler.default_gemfile, Bundler.default_lockfile) - end - - def initialize(deps, options = {}) - @deps = deps - @options = options - end - - # @param [Pathname] gemfile_path The Gemfile in which to inject the new dependency. - # @param [Pathname] lockfile_path The lockfile in which to inject the new dependency. - # @return [Array] - def inject(gemfile_path, lockfile_path) - if Bundler.frozen_bundle? - # ensure the lock and Gemfile are synced - Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true) - end - - # temporarily unfreeze - Bundler.settings.temporary(:deployment => false, :frozen => false) do - # evaluate the Gemfile we have now - builder = Dsl.new - builder.eval_gemfile(gemfile_path) - - # don't inject any gems that are already in the Gemfile - @deps -= builder.dependencies - - # add new deps to the end of the in-memory Gemfile - # Set conservative versioning to false because - # we want to let the resolver resolve the version first - builder.eval_gemfile(INJECTED_GEMS, build_gem_lines(false)) if @deps.any? - - # resolve to see if the new deps broke anything - @definition = builder.to_definition(lockfile_path, {}) - @definition.resolve_remotely! - - # since nothing broke, we can add those gems to the gemfile - append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any? - - # since we resolved successfully, write out the lockfile - @definition.lock(Bundler.default_lockfile) - - # invalidate the cached Bundler.definition - Bundler.reset_paths! - - # return an array of the deps that we added - @deps - end - end - - # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. - # @param [Pathname] lockfile_path The lockfile from which to remove dependencies. - # @return [Array] - def remove(gemfile_path, lockfile_path) - # remove gems from each gemfiles we have - Bundler.definition.gemfiles.each do |path| - deps = remove_deps(path) - - show_warning("No gems were removed from the gemfile.") if deps.empty? - - deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep, false)} was removed." } - end - end - - private - - def conservative_version(spec) - version = spec.version - return ">= 0" if version.nil? - segments = version.segments - seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2 - - prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease? - "#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}" - end - - def version_prefix - if @options[:strict] - "= " - elsif @options[:optimistic] - ">= " - else - "~> " - end - end - - def build_gem_lines(conservative_versioning) - @deps.map do |d| - name = d.name.dump - - requirement = if conservative_versioning - ", \"#{conservative_version(@definition.specs[d.name][0])}\"" - else - ", #{d.requirement.as_list.map(&:dump).join(", ")}" - end - - if d.groups != Array(:default) - group = d.groups.size == 1 ? ", :group => #{d.groups.first.inspect}" : ", :groups => #{d.groups.inspect}" - end - - source = ", :source => \"#{d.source}\"" unless d.source.nil? - - %(gem #{name}#{requirement}#{group}#{source}) - end.join("\n") - end - - def append_to(gemfile_path, new_gem_lines) - gemfile_path.open("a") do |f| - f.puts - f.puts new_gem_lines - end - end - - # evalutes a gemfile to remove the specified gem - # from it. - def remove_deps(gemfile_path) - initial_gemfile = IO.readlines(gemfile_path) - - Bundler.ui.info "Removing gems from #{gemfile_path}" - - # evaluate the Gemfile we have - builder = Dsl.new - builder.eval_gemfile(gemfile_path) - - removed_deps = remove_gems_from_dependencies(builder, @deps, gemfile_path) - - # abort the opertion if no gems were removed - # no need to operate on gemfile furthur - return [] if removed_deps.empty? - - cleaned_gemfile = remove_gems_from_gemfile(@deps, gemfile_path) - - SharedHelpers.write_to_gemfile(gemfile_path, cleaned_gemfile) - - # check for errors - # including extra gems being removed - # or some gems not being removed - # and return the actual removed deps - cross_check_for_errors(gemfile_path, builder.dependencies, removed_deps, initial_gemfile) - end - - # @param [Dsl] builder Dsl object of current Gemfile. - # @param [Array] gems Array of names of gems to be removed. - # @param [Pathname] path of the Gemfile - # @return [Array] removed_deps Array of removed dependencies. - def remove_gems_from_dependencies(builder, gems, gemfile_path) - removed_deps = [] - - gems.each do |gem_name| - deleted_dep = builder.dependencies.find {|d| d.name == gem_name } - - if deleted_dep.nil? - raise GemfileError, "`#{gem_name}` is not specified in #{gemfile_path} so it could not be removed." - end - - builder.dependencies.delete(deleted_dep) - - removed_deps << deleted_dep - end - - removed_deps - end - - # @param [Array] gems Array of names of gems to be removed. - # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. - def remove_gems_from_gemfile(gems, gemfile_path) - patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/ - - # remove lines which match the regex - new_gemfile = IO.readlines(gemfile_path).reject {|line| line.match(patterns) } - - # remove lone \n and append them with other strings - new_gemfile.each_with_index do |_line, index| - if new_gemfile[index + 1] == "\n" - new_gemfile[index] += new_gemfile[index + 1] - new_gemfile.delete_at(index + 1) - end - end - - %w[group source env install_if].each {|block| remove_nested_blocks(new_gemfile, block) } - - new_gemfile.join.chomp - end - - # @param [Array] gemfile Array of gemfile contents. - # @param [String] block_name Name of block name to look for. - def remove_nested_blocks(gemfile, block_name) - nested_blocks = 0 - - # count number of nested blocks - gemfile.each_with_index {|line, index| nested_blocks += 1 if !gemfile[index + 1].nil? && gemfile[index + 1].include?(block_name) && line.include?(block_name) } - - while nested_blocks >= 0 - nested_blocks -= 1 - - gemfile.each_with_index do |line, index| - next unless !line.nil? && line.include?(block_name) - if gemfile[index + 1] =~ /^\s*end\s*$/ - gemfile[index] = nil - gemfile[index + 1] = nil - end - end - - gemfile.compact! - end - end - - # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. - # @param [Array] original_deps Array of original dependencies. - # @param [Array] removed_deps Array of removed dependencies. - # @param [Array] initial_gemfile Contents of original Gemfile before any operation. - def cross_check_for_errors(gemfile_path, original_deps, removed_deps, initial_gemfile) - # evalute the new gemfile to look for any failure cases - builder = Dsl.new - builder.eval_gemfile(gemfile_path) - - # record gems which were removed but not requested - extra_removed_gems = original_deps - builder.dependencies - - # if some extra gems were removed then raise error - # and revert Gemfile to original - unless extra_removed_gems.empty? - SharedHelpers.write_to_gemfile(gemfile_path, initial_gemfile.join) - - raise InvalidOption, "Gems could not be removed. #{extra_removed_gems.join(", ")} would also have been removed. Bundler cannot continue." - end - - # record gems which could not be removed due to some reasons - errored_deps = builder.dependencies.select {|d| d.gemfile == gemfile_path } & removed_deps.select {|d| d.gemfile == gemfile_path } - - show_warning "#{errored_deps.map(&:name).join(", ")} could not be removed." unless errored_deps.empty? - - # return actual removed dependencies - removed_deps - errored_deps - end - - def show_warning(message) - Bundler.ui.info Bundler.ui.add_color(message, :yellow) - end - end -end diff --git a/lib/ruby/stdlib/bundler/inline.rb b/lib/ruby/stdlib/bundler/inline.rb deleted file mode 100644 index 9d25f3261a1..00000000000 --- a/lib/ruby/stdlib/bundler/inline.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require "bundler/compatibility_guard" - -# Allows for declaring a Gemfile inline in a ruby script, optionally installing -# any gems that aren't already installed on the user's system. -# -# @note Every gem that is specified in this 'Gemfile' will be `require`d, as if -# the user had manually called `Bundler.require`. To avoid a requested gem -# being automatically required, add the `:require => false` option to the -# `gem` dependency declaration. -# -# @param install [Boolean] whether gems that aren't already installed on the -# user's system should be installed. -# Defaults to `false`. -# -# @param gemfile [Proc] a block that is evaluated as a `Gemfile`. -# -# @example Using an inline Gemfile -# -# #!/usr/bin/env ruby -# -# require 'bundler/inline' -# -# gemfile do -# source 'https://rubygems.org' -# gem 'json', require: false -# gem 'nap', require: 'rest' -# gem 'cocoapods', '~> 0.34.1' -# end -# -# puts Pod::VERSION # => "0.34.4" -# -def gemfile(install = false, options = {}, &gemfile) - require "bundler" - - opts = options.dup - ui = opts.delete(:ui) { Bundler::UI::Shell.new } - raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? - - old_root = Bundler.method(:root) - def Bundler.root - Bundler::SharedHelpers.pwd.expand_path - end - Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" - - Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? - builder = Bundler::Dsl.new - builder.instance_eval(&gemfile) - - definition = builder.to_definition(nil, true) - def definition.lock(*); end - definition.validate_runtime! - - missing_specs = proc do - definition.missing_specs? - end - - Bundler.ui = ui if install - if install || missing_specs.call - Bundler.settings.temporary(:inline => true) do - installer = Bundler::Installer.install(Bundler.root, definition, :system => true) - installer.post_install_messages.each do |name, message| - Bundler.ui.info "Post-install message from #{name}:\n#{message}" - end - end - end - - runtime = Bundler::Runtime.new(nil, definition) - runtime.setup.require -ensure - bundler_module = class << Bundler; self; end - bundler_module.send(:define_method, :root, old_root) if old_root -end diff --git a/lib/ruby/stdlib/bundler/installer.rb b/lib/ruby/stdlib/bundler/installer.rb deleted file mode 100644 index b49cfb67031..00000000000 --- a/lib/ruby/stdlib/bundler/installer.rb +++ /dev/null @@ -1,318 +0,0 @@ -# frozen_string_literal: true - -require "erb" -require "rubygems/dependency_installer" -require "bundler/worker" -require "bundler/installer/parallel_installer" -require "bundler/installer/standalone" -require "bundler/installer/gem_installer" - -module Bundler - class Installer - class << self - attr_accessor :ambiguous_gems - - Installer.ambiguous_gems = [] - end - - attr_reader :post_install_messages - - # Begins the installation process for Bundler. - # For more information see the #run method on this class. - def self.install(root, definition, options = {}) - installer = new(root, definition) - Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL_ALL, definition.dependencies) - installer.run(options) - Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL_ALL, definition.dependencies) - installer - end - - def initialize(root, definition) - @root = root - @definition = definition - @post_install_messages = {} - end - - # Runs the install procedures for a specific Gemfile. - # - # Firstly, this method will check to see if `Bundler.bundle_path` exists - # and if not then Bundler will create the directory. This is usually the same - # location as RubyGems which typically is the `~/.gem` directory - # unless other specified. - # - # Secondly, it checks if Bundler has been configured to be "frozen". - # Frozen ensures that the Gemfile and the Gemfile.lock file are matching. - # This stops a situation where a developer may update the Gemfile but may not run - # `bundle install`, which leads to the Gemfile.lock file not being correctly updated. - # If this file is not correctly updated then any other developer running - # `bundle install` will potentially not install the correct gems. - # - # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile. - # If there are no dependencies specified then Bundler returns a warning message stating - # so and this method returns. - # - # Fourthly, Bundler checks if the Gemfile.lock exists, and if so - # then proceeds to set up a definition based on the Gemfile and the Gemfile.lock. - # During this step Bundler will also download information about any new gems - # that are not in the Gemfile.lock and resolve any dependencies if needed. - # - # Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote. - # This then leads into the gems being installed, along with stubs for their executables, - # but only if the --binstubs option has been passed or Bundler.options[:bin] has been set - # earlier. - # - # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time - # that a user runs `bundle install` they will receive any updates from this process. - # - # Finally, if the user has specified the standalone flag, Bundler will generate the needed - # require paths and save them in a `setup.rb` file. See `bundle standalone --help` for more - # information. - def run(options) - create_bundle_path - - ProcessLock.lock do - if Bundler.frozen_bundle? - @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) - end - - if @definition.dependencies.empty? - Bundler.ui.warn "The Gemfile specifies no dependencies" - lock - return - end - - if resolve_if_needed(options) - ensure_specs_are_compatible! - warn_on_incompatible_bundler_deps - load_plugins - options.delete(:jobs) - else - options[:jobs] = 1 # to avoid the overhead of Bundler::Worker - end - install(options) - - lock unless Bundler.frozen_bundle? - Standalone.new(options[:standalone], @definition).generate if options[:standalone] - end - end - - def generate_bundler_executable_stubs(spec, options = {}) - if options[:binstubs_cmd] && spec.executables.empty? - options = {} - spec.runtime_dependencies.each do |dep| - bins = @definition.specs[dep].first.executables - options[dep.name] = bins unless bins.empty? - end - if options.any? - Bundler.ui.warn "#{spec.name} has no executables, but you may want " \ - "one from a gem it depends on." - options.each {|name, bins| Bundler.ui.warn " #{name} has: #{bins.join(", ")}" } - else - Bundler.ui.warn "There are no executables for the gem #{spec.name}." - end - return - end - - # double-assignment to avoid warnings about variables that will be used by ERB - bin_path = Bundler.bin_path - bin_path = bin_path - relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) - relative_gemfile_path = relative_gemfile_path - ruby_command = Thor::Util.ruby_command - ruby_command = ruby_command - template_path = File.expand_path("../templates/Executable", __FILE__) - if spec.name == "bundler" - template_path += ".bundler" - spec.executables = %(bundle) - end - template = File.read(template_path) - - exists = [] - spec.executables.each do |executable| - binstub_path = "#{bin_path}/#{executable}" - if File.exist?(binstub_path) && !options[:force] - exists << executable - next - end - - File.open(binstub_path, "w", 0o777 & ~File.umask) do |f| - if RUBY_VERSION >= "2.6" - f.puts ERB.new(template, :trim_mode => "-").result(binding) - else - f.puts ERB.new(template, nil, "-").result(binding) - end - end - end - - if options[:binstubs_cmd] && exists.any? - case exists.size - when 1 - Bundler.ui.warn "Skipped #{exists[0]} since it already exists." - when 2 - Bundler.ui.warn "Skipped #{exists.join(" and ")} since they already exist." - else - items = exists[0...-1].empty? ? nil : exists[0...-1].join(", ") - skipped = [items, exists[-1]].compact.join(" and ") - Bundler.ui.warn "Skipped #{skipped} since they already exist." - end - Bundler.ui.warn "If you want to overwrite skipped stubs, use --force." - end - end - - def generate_standalone_bundler_executable_stubs(spec) - # double-assignment to avoid warnings about variables that will be used by ERB - bin_path = Bundler.bin_path - unless path = Bundler.settings[:path] - raise "Can't standalone without an explicit path set" - end - standalone_path = Bundler.root.join(path).relative_path_from(bin_path) - standalone_path = standalone_path - template = File.read(File.expand_path("../templates/Executable.standalone", __FILE__)) - ruby_command = Thor::Util.ruby_command - ruby_command = ruby_command - - spec.executables.each do |executable| - next if executable == "bundle" - executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) - executable_path = executable_path - File.open "#{bin_path}/#{executable}", "w", 0o755 do |f| - if RUBY_VERSION >= "2.6" - f.puts ERB.new(template, :trim_mode => "-").result(binding) - else - f.puts ERB.new(template, nil, "-").result(binding) - end - end - end - end - - private - - # the order that the resolver provides is significant, since - # dependencies might affect the installation of a gem. - # that said, it's a rare situation (other than rake), and parallel - # installation is SO MUCH FASTER. so we let people opt in. - def install(options) - force = options["force"] - jobs = installation_parallelization(options) - install_in_parallel jobs, options[:standalone], force - end - - def installation_parallelization(options) - if jobs = options.delete(:jobs) - return jobs - end - - return 1 unless can_install_in_parallel? - - auto_config_jobs = Bundler.feature_flag.auto_config_jobs? - if jobs = Bundler.settings[:jobs] - if auto_config_jobs - jobs - else - [jobs.pred, 1].max - end - elsif auto_config_jobs - processor_count - else - 1 - end - end - - def processor_count - require "etc" - Etc.nprocessors - rescue - 1 - end - - def load_plugins - Bundler.rubygems.load_plugins - - requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) } - path_plugin_files = requested_path_gems.map do |spec| - begin - Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}") - rescue TypeError - error_message = "#{spec.name} #{spec.version} has an invalid gemspec" - raise Gem::InvalidSpecificationException, error_message - end - end.flatten - Bundler.rubygems.load_plugin_files(path_plugin_files) - end - - def ensure_specs_are_compatible! - system_ruby = Bundler::RubyVersion.system - rubygems_version = Gem::Version.create(Gem::VERSION) - @definition.specs.each do |spec| - if required_ruby_version = spec.required_ruby_version - unless required_ruby_version.satisfied_by?(system_ruby.gem_version) - raise InstallError, "#{spec.full_name} requires ruby version #{required_ruby_version}, " \ - "which is incompatible with the current version, #{system_ruby}" - end - end - next unless required_rubygems_version = spec.required_rubygems_version - unless required_rubygems_version.satisfied_by?(rubygems_version) - raise InstallError, "#{spec.full_name} requires rubygems version #{required_rubygems_version}, " \ - "which is incompatible with the current version, #{rubygems_version}" - end - end - end - - def warn_on_incompatible_bundler_deps - bundler_version = Gem::Version.create(Bundler::VERSION) - @definition.specs.each do |spec| - spec.dependencies.each do |dep| - next if dep.type == :development - next unless dep.name == "bundler".freeze - next if dep.requirement.satisfied_by?(bundler_version) - - Bundler.ui.warn "#{spec.name} (#{spec.version}) has dependency" \ - " #{SharedHelpers.pretty_dependency(dep)}" \ - ", which is unsatisfied by the current bundler version #{VERSION}" \ - ", so the dependency is being ignored" - end - end - end - - def can_install_in_parallel? - if Bundler.rubygems.provides?(">= 2.1.0") - true - else - Bundler.ui.warn "RubyGems #{Gem::VERSION} is not threadsafe, so your "\ - "gems will be installed one at a time. Upgrade to RubyGems 2.1.0 " \ - "or higher to enable parallel gem installation." - false - end - end - - def install_in_parallel(size, standalone, force = false) - spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force) - spec_installations.each do |installation| - post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message? - end - end - - def create_bundle_path - SharedHelpers.filesystem_access(Bundler.bundle_path.to_s) do |p| - Bundler.mkdir_p(p) - end unless Bundler.bundle_path.exist? - rescue Errno::EEXIST - raise PathError, "Could not install to path `#{Bundler.bundle_path}` " \ - "because a file already exists at that path. Either remove or rename the file so the directory can be created." - end - - # returns whether or not a re-resolve was needed - def resolve_if_needed(options) - if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? - return false if @definition.nothing_changed? && !@definition.missing_specs? - end - - options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! - true - end - - def lock(opts = {}) - @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections]) - end - end -end diff --git a/lib/ruby/stdlib/bundler/installer/gem_installer.rb b/lib/ruby/stdlib/bundler/installer/gem_installer.rb deleted file mode 100644 index e5e245f9706..00000000000 --- a/lib/ruby/stdlib/bundler/installer/gem_installer.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class GemInstaller - attr_reader :spec, :standalone, :worker, :force, :installer - - def initialize(spec, installer, standalone = false, worker = 0, force = false) - @spec = spec - @installer = installer - @standalone = standalone - @worker = worker - @force = force - end - - def install_from_spec - post_install_message = spec_settings ? install_with_settings : install - Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}" - generate_executable_stubs - return true, post_install_message - rescue Bundler::InstallHookError, Bundler::SecurityError, APIResponseMismatchError - raise - rescue Errno::ENOSPC - return false, out_of_space_message - rescue StandardError => e - return false, specific_failure_message(e) - end - - private - - def specific_failure_message(e) - message = "#{e.class}: #{e.message}\n" - message += " " + e.backtrace.join("\n ") + "\n\n" if Bundler.ui.debug? - message = message.lines.first + Bundler.ui.add_color(message.lines.drop(1).join, :clear) - message + Bundler.ui.add_color(failure_message, :red) - end - - def failure_message - return install_error_message if spec.source.options["git"] - "#{install_error_message}\n#{gem_install_message}" - end - - def install_error_message - "An error occurred while installing #{spec.name} (#{spec.version}), and Bundler cannot continue." - end - - def gem_install_message - source = spec.source - return unless source.respond_to?(:remotes) - - if source.remotes.size == 1 - "Make sure that `gem install #{spec.name} -v '#{spec.version}' --source '#{source.remotes.first}'` succeeds before bundling." - else - "Make sure that `gem install #{spec.name} -v '#{spec.version}'` succeeds before bundling." - end - end - - def spec_settings - # Fetch the build settings, if there are any - Bundler.settings["build.#{spec.name}"] - end - - def install - spec.source.install(spec, :force => force, :ensure_builtin_gems_cached => standalone, :build_args => Array(spec_settings)) - end - - def install_with_settings - # Build arguments are global, so this is mutexed - Bundler.rubygems.install_with_build_args([spec_settings]) { install } - end - - def out_of_space_message - "#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle." - end - - def generate_executable_stubs - return if Bundler.feature_flag.forget_cli_options? - return if Bundler.settings[:inline] - if Bundler.settings[:bin] && standalone - installer.generate_standalone_bundler_executable_stubs(spec) - elsif Bundler.settings[:bin] - installer.generate_bundler_executable_stubs(spec, :force => true) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/installer/parallel_installer.rb b/lib/ruby/stdlib/bundler/installer/parallel_installer.rb deleted file mode 100644 index f8a849ccfca..00000000000 --- a/lib/ruby/stdlib/bundler/installer/parallel_installer.rb +++ /dev/null @@ -1,233 +0,0 @@ -# frozen_string_literal: true - -require "bundler/worker" -require "bundler/installer/gem_installer" - -module Bundler - class ParallelInstaller - class SpecInstallation - attr_accessor :spec, :name, :post_install_message, :state, :error - def initialize(spec) - @spec = spec - @name = spec.name - @state = :none - @post_install_message = "" - @error = nil - end - - def installed? - state == :installed - end - - def enqueued? - state == :enqueued - end - - def failed? - state == :failed - end - - def installation_attempted? - installed? || failed? - end - - # Only true when spec in neither installed nor already enqueued - def ready_to_enqueue? - !enqueued? && !installation_attempted? - end - - def has_post_install_message? - !post_install_message.empty? - end - - def ignorable_dependency?(dep) - dep.type == :development || dep.name == @name - end - - # Checks installed dependencies against spec's dependencies to make - # sure needed dependencies have been installed. - def dependencies_installed?(all_specs) - installed_specs = all_specs.select(&:installed?).map(&:name) - dependencies.all? {|d| installed_specs.include? d.name } - end - - # Represents only the non-development dependencies, the ones that are - # itself and are in the total list. - def dependencies - @dependencies ||= begin - all_dependencies.reject {|dep| ignorable_dependency? dep } - end - end - - def missing_lockfile_dependencies(all_spec_names) - deps = all_dependencies.reject {|dep| ignorable_dependency? dep } - deps.reject {|dep| all_spec_names.include? dep.name } - end - - # Represents all dependencies - def all_dependencies - @spec.dependencies - end - - def to_s - "#<#{self.class} #{@spec.full_name} (#{state})>" - end - end - - def self.call(*args) - new(*args).call - end - - attr_reader :size - - def initialize(installer, all_specs, size, standalone, force) - @installer = installer - @size = size - @standalone = standalone - @force = force - @specs = all_specs.map {|s| SpecInstallation.new(s) } - @spec_set = all_specs - @rake = @specs.find {|s| s.name == "rake" } - end - - def call - # Since `autoload` has the potential for threading issues on 1.8.7 - # TODO: remove in bundler 2.0 - require "bundler/gem_remote_fetcher" if RUBY_VERSION < "1.9" - - check_for_corrupt_lockfile - - if @size > 1 - install_with_worker - else - install_serially - end - - handle_error if @specs.any?(&:failed?) - @specs - ensure - worker_pool && worker_pool.stop - end - - def check_for_corrupt_lockfile - missing_dependencies = @specs.map do |s| - [ - s, - s.missing_lockfile_dependencies(@specs.map(&:name)), - ] - end.reject { |a| a.last.empty? } - return if missing_dependencies.empty? - - warning = [] - warning << "Your lockfile was created by an old Bundler that left some things out." - if @size != 1 - warning << "Because of the missing DEPENDENCIES, we can only install gems one at a time, instead of installing #{@size} at a time." - @size = 1 - end - warning << "You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile." - warning << "The missing gems are:" - - missing_dependencies.each do |spec, missing| - warning << "* #{missing.map(&:name).join(", ")} depended upon by #{spec.name}" - end - - Bundler.ui.warn(warning.join("\n")) - end - - private - - def install_with_worker - enqueue_specs - process_specs until finished_installing? - end - - def install_serially - until finished_installing? - raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?) - spec_install.state = :enqueued - do_install(spec_install, 0) - end - end - - def worker_pool - @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda { |spec_install, worker_num| - do_install(spec_install, worker_num) - } - end - - def do_install(spec_install, worker_num) - Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install) - gem_installer = Bundler::GemInstaller.new( - spec_install.spec, @installer, @standalone, worker_num, @force - ) - success, message = begin - gem_installer.install_from_spec - rescue RuntimeError => e - raise e, "#{e}\n\n#{require_tree_for_spec(spec_install.spec)}" - end - if success - spec_install.state = :installed - spec_install.post_install_message = message unless message.nil? - else - spec_install.state = :failed - spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}" - end - Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL, spec_install) - spec_install - end - - # Dequeue a spec and save its post-install message and then enqueue the - # remaining specs. - # Some specs might've had to wait til this spec was installed to be - # processed so the call to `enqueue_specs` is important after every - # dequeue. - def process_specs - worker_pool.deq - enqueue_specs - end - - def finished_installing? - @specs.all? do |spec| - return true if spec.failed? - spec.installed? - end - end - - def handle_error - errors = @specs.select(&:failed?).map(&:error) - if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) } - raise exception - end - raise Bundler::InstallError, errors.map(&:to_s).join("\n\n") - end - - def require_tree_for_spec(spec) - tree = @spec_set.what_required(spec) - t = String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n") - tree.each_with_index do |s, depth| - t << " " * depth.succ << s.name - unless tree.last == s - t << %( was resolved to #{s.version}, which depends on) - end - t << %(\n) - end - t - end - - # Keys in the remains hash represent uninstalled gems specs. - # We enqueue all gem specs that do not have any dependencies. - # Later we call this lambda again to install specs that depended on - # previously installed specifications. We continue until all specs - # are installed. - def enqueue_specs - @specs.select(&:ready_to_enqueue?).each do |spec| - next if @rake && !@rake.installed? && spec.name != @rake.name - - if spec.dependencies_installed? @specs - spec.state = :enqueued - worker_pool.enq spec - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/installer/standalone.rb b/lib/ruby/stdlib/bundler/installer/standalone.rb deleted file mode 100644 index ce0c9df1ebc..00000000000 --- a/lib/ruby/stdlib/bundler/installer/standalone.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Standalone - def initialize(groups, definition) - @specs = groups.empty? ? definition.requested_specs : definition.specs_for(groups.map(&:to_sym)) - end - - def generate - SharedHelpers.filesystem_access(bundler_path) do |p| - FileUtils.mkdir_p(p) - end - File.open File.join(bundler_path, "setup.rb"), "w" do |file| - file.puts "require 'rbconfig'" - file.puts "# ruby 1.8.7 doesn't define RUBY_ENGINE" - file.puts "ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'" - file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]" - file.puts "path = File.expand_path('..', __FILE__)" - paths.each do |path| - file.puts %($:.unshift "\#{path}/#{path}") - end - end - end - - private - - def paths - @specs.map do |spec| - next if spec.name == "bundler" - Array(spec.require_paths).map do |path| - gem_path(path, spec).sub(version_dir, '#{ruby_engine}/#{ruby_version}') - # This is a static string intentionally. It's interpolated at a later time. - end - end.flatten - end - - def version_dir - "#{Bundler::RubyVersion.system.engine}/#{RbConfig::CONFIG["ruby_version"]}" - end - - def bundler_path - Bundler.root.join(Bundler.settings[:path], "bundler") - end - - def gem_path(path, spec) - full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path) - Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s - rescue TypeError - error_message = "#{spec.name} #{spec.version} has an invalid gemspec" - raise Gem::InvalidSpecificationException.new(error_message) - end - end -end diff --git a/lib/ruby/stdlib/bundler/lazy_specification.rb b/lib/ruby/stdlib/bundler/lazy_specification.rb deleted file mode 100644 index d9cb01f810e..00000000000 --- a/lib/ruby/stdlib/bundler/lazy_specification.rb +++ /dev/null @@ -1,123 +0,0 @@ -# frozen_string_literal: true - -require "uri" -require "bundler/match_platform" - -module Bundler - class LazySpecification - Identifier = Struct.new(:name, :version, :source, :platform, :dependencies) - class Identifier - include Comparable - def <=>(other) - return unless other.is_a?(Identifier) - [name, version, platform_string] <=> [other.name, other.version, other.platform_string] - end - - protected - - def platform_string - platform_string = platform.to_s - platform_string == Index::RUBY ? Index::NULL : platform_string - end - end - - include MatchPlatform - - attr_reader :name, :version, :dependencies, :platform - attr_accessor :source, :remote - - def initialize(name, version, platform, source = nil) - @name = name - @version = version - @dependencies = [] - @platform = platform || Gem::Platform::RUBY - @source = source - @specification = nil - end - - def full_name - if platform == Gem::Platform::RUBY || platform.nil? - "#{@name}-#{@version}" - else - "#{@name}-#{@version}-#{platform}" - end - end - - def ==(other) - identifier == other.identifier - end - - def satisfies?(dependency) - @name == dependency.name && dependency.requirement.satisfied_by?(Gem::Version.new(@version)) - end - - def to_lock - out = String.new - - if platform == Gem::Platform::RUBY || platform.nil? - out << " #{name} (#{version})\n" - else - out << " #{name} (#{version}-#{platform})\n" - end - - dependencies.sort_by(&:to_s).uniq.each do |dep| - next if dep.type == :development - out << " #{dep.to_lock}\n" - end - - out - end - - def __materialize__ - search_object = Bundler.feature_flag.specific_platform? || Bundler.settings[:force_ruby_platform] ? self : Dependency.new(name, version) - @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name - source.gemspec.tap {|s| s.source = source } - else - search = source.specs.search(search_object).last - if search && Gem::Platform.new(search.platform) != Gem::Platform.new(platform) && !search.runtime_dependencies.-(dependencies.reject {|d| d.type == :development }).empty? - Bundler.ui.warn "Unable to use the platform-specific (#{search.platform}) version of #{name} (#{version}) " \ - "because it has different dependencies from the #{platform} version. " \ - "To use the platform-specific version of the gem, run `bundle config specific_platform true` and install again." - search = source.specs.search(self).last - end - search.dependencies = dependencies if search && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) - search - end - end - - def respond_to?(*args) - super || @specification ? @specification.respond_to?(*args) : nil - end - - def to_s - @__to_s ||= if platform == Gem::Platform::RUBY || platform.nil? - "#{name} (#{version})" - else - "#{name} (#{version}-#{platform})" - end - end - - def identifier - @__identifier ||= Identifier.new(name, version, source, platform, dependencies) - end - - def git_version - return unless source.is_a?(Bundler::Source::Git) - " #{source.revision[0..6]}" - end - - private - - def to_ary - nil - end - - def method_missing(method, *args, &blk) - raise "LazySpecification has not been materialized yet (calling :#{method} #{args.inspect})" unless @specification - - return super unless respond_to?(method) - - @specification.send(method, *args, &blk) - end - end -end diff --git a/lib/ruby/stdlib/bundler/lockfile_generator.rb b/lib/ruby/stdlib/bundler/lockfile_generator.rb deleted file mode 100644 index 585077d18dc..00000000000 --- a/lib/ruby/stdlib/bundler/lockfile_generator.rb +++ /dev/null @@ -1,95 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class LockfileGenerator - attr_reader :definition - attr_reader :out - - # @private - def initialize(definition) - @definition = definition - @out = String.new - end - - def self.generate(definition) - new(definition).generate! - end - - def generate! - add_sources - add_platforms - add_dependencies - add_locked_ruby_version - add_bundled_with - - out - end - - private - - def add_sources - definition.send(:sources).lock_sources.each_with_index do |source, idx| - out << "\n" unless idx.zero? - - # Add the source header - out << source.to_lock - - # Find all specs for this source - specs = definition.resolve.select {|s| source.can_lock?(s) } - add_specs(specs) - end - end - - def add_specs(specs) - # This needs to be sorted by full name so that - # gems with the same name, but different platform - # are ordered consistently - specs.sort_by(&:full_name).each do |spec| - next if spec.name == "bundler".freeze - out << spec.to_lock - end - end - - def add_platforms - add_section("PLATFORMS", definition.platforms) - end - - def add_dependencies - out << "\nDEPENDENCIES\n" - - handled = [] - definition.dependencies.sort_by(&:to_s).each do |dep| - next if handled.include?(dep.name) - out << dep.to_lock - handled << dep.name - end - end - - def add_locked_ruby_version - return unless locked_ruby_version = definition.locked_ruby_version - add_section("RUBY VERSION", locked_ruby_version.to_s) - end - - def add_bundled_with - add_section("BUNDLED WITH", definition.locked_bundler_version.to_s) - end - - def add_section(name, value) - out << "\n#{name}\n" - case value - when Array - value.map(&:to_s).sort.each do |val| - out << " #{val}\n" - end - when Hash - value.to_a.sort_by {|k, _| k.to_s }.each do |key, val| - out << " #{key}: #{val}\n" - end - when String - out << " #{value}\n" - else - raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile" - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/lockfile_parser.rb b/lib/ruby/stdlib/bundler/lockfile_parser.rb deleted file mode 100644 index ff706fca1d5..00000000000 --- a/lib/ruby/stdlib/bundler/lockfile_parser.rb +++ /dev/null @@ -1,256 +0,0 @@ -# frozen_string_literal: true - -# Some versions of the Bundler 1.1 RC series introduced corrupted -# lockfiles. There were two major problems: -# -# * multiple copies of the same GIT section appeared in the lockfile -# * when this happened, those sections got multiple copies of gems -# in those sections. -# -# As a result, Bundler 1.1 contains code that fixes the earlier -# corruption. We will remove this fix-up code in Bundler 1.2. - -module Bundler - class LockfileParser - attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version - - BUNDLED = "BUNDLED WITH".freeze - DEPENDENCIES = "DEPENDENCIES".freeze - PLATFORMS = "PLATFORMS".freeze - RUBY = "RUBY VERSION".freeze - GIT = "GIT".freeze - GEM = "GEM".freeze - PATH = "PATH".freeze - PLUGIN = "PLUGIN SOURCE".freeze - SPECS = " specs:".freeze - OPTIONS = /^ ([a-z]+): (.*)$/i - SOURCE = [GIT, GEM, PATH, PLUGIN].freeze - - SECTIONS_BY_VERSION_INTRODUCED = { - # The strings have to be dup'ed for old RG on Ruby 2.3+ - # TODO: remove dup in Bundler 2.0 - Gem::Version.create("1.0".dup) => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze, - Gem::Version.create("1.10".dup) => [BUNDLED].freeze, - Gem::Version.create("1.12".dup) => [RUBY].freeze, - Gem::Version.create("1.13".dup) => [PLUGIN].freeze, - }.freeze - - KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze - - ENVIRONMENT_VERSION_SECTIONS = [BUNDLED, RUBY].freeze - - def self.sections_in_lockfile(lockfile_contents) - lockfile_contents.scan(/^\w[\w ]*$/).uniq - end - - def self.unknown_sections_in_lockfile(lockfile_contents) - sections_in_lockfile(lockfile_contents) - KNOWN_SECTIONS - end - - def self.sections_to_ignore(base_version = nil) - base_version &&= base_version.release - base_version ||= Gem::Version.create("1.0".dup) - attributes = [] - SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced| - next if version <= base_version - attributes += introduced - end - attributes - end - - def initialize(lockfile) - @platforms = [] - @sources = [] - @dependencies = {} - @state = nil - @specs = {} - - @rubygems_aggregate = Source::Rubygems.new - - if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) - raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \ - "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock." - end - - lockfile.split(/(?:\r?\n)+/).each do |line| - if SOURCE.include?(line) - @state = :source - parse_source(line) - elsif line == DEPENDENCIES - @state = :dependency - elsif line == PLATFORMS - @state = :platform - elsif line == RUBY - @state = :ruby - elsif line == BUNDLED - @state = :bundled_with - elsif line =~ /^[^\s]/ - @state = nil - elsif @state - send("parse_#{@state}", line) - end - end - @sources << @rubygems_aggregate unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - @specs = @specs.values.sort_by(&:identifier) - warn_for_outdated_bundler_version - rescue ArgumentError => e - Bundler.ui.debug(e) - raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \ - "and then `bundle install` to generate a new lockfile." - end - - def warn_for_outdated_bundler_version - return unless bundler_version - prerelease_text = bundler_version.prerelease? ? " --pre" : "" - current_version = Gem::Version.create(Bundler::VERSION) - case current_version.segments.first <=> bundler_version.segments.first - when -1 - raise LockfileError, "You must use Bundler #{bundler_version.segments.first} or greater with this lockfile." - when 0 - if current_version < bundler_version - Bundler.ui.warn "Warning: the running version of Bundler (#{current_version}) is older " \ - "than the version that created the lockfile (#{bundler_version}). We suggest you " \ - "upgrade to the latest version of Bundler by running `gem " \ - "install bundler#{prerelease_text}`.\n" - end - end - end - - private - - TYPES = { - GIT => Bundler::Source::Git, - GEM => Bundler::Source::Rubygems, - PATH => Bundler::Source::Path, - PLUGIN => Bundler::Plugin, - }.freeze - - def parse_source(line) - case line - when SPECS - case @type - when PATH - @current_source = TYPES[@type].from_lock(@opts) - @sources << @current_source - when GIT - @current_source = TYPES[@type].from_lock(@opts) - # Strip out duplicate GIT sections - if @sources.include?(@current_source) - @current_source = @sources.find {|s| s == @current_source } - else - @sources << @current_source - end - when GEM - if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - @opts["remotes"] = @opts.delete("remote") - @current_source = TYPES[@type].from_lock(@opts) - @sources << @current_source - else - Array(@opts["remote"]).each do |url| - @rubygems_aggregate.add_remote(url) - end - @current_source = @rubygems_aggregate - end - when PLUGIN - @current_source = Plugin.source_from_lock(@opts) - @sources << @current_source - end - when OPTIONS - value = $2 - value = true if value == "true" - value = false if value == "false" - - key = $1 - - if @opts[key] - @opts[key] = Array(@opts[key]) - @opts[key] << value - else - @opts[key] = value - end - when *SOURCE - @current_source = nil - @opts = {} - @type = line - else - parse_spec(line) - end - end - - space = / / - NAME_VERSION = / - ^(#{space}{2}|#{space}{4}|#{space}{6})(?!#{space}) # Exactly 2, 4, or 6 spaces at the start of the line - (.*?) # Name - (?:#{space}\(([^-]*) # Space, followed by version - (?:-(.*))?\))? # Optional platform - (!)? # Optional pinned marker - $ # Line end - /xo - - def parse_dependency(line) - return unless line =~ NAME_VERSION - spaces = $1 - return unless spaces.size == 2 - name = $2 - version = $3 - pinned = $5 - - version = version.split(",").map(&:strip) if version - - dep = Bundler::Dependency.new(name, version) - - if pinned && dep.name != "bundler" - spec = @specs.find {|_, v| v.name == dep.name } - dep.source = spec.last.source if spec - - # Path sources need to know what the default name / version - # to use in the case that there are no gemspecs present. A fake - # gemspec is created based on the version set on the dependency - # TODO: Use the version from the spec instead of from the dependency - if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path) - dep.source.name = name - dep.source.version = $1 - end - end - - @dependencies[dep.name] = dep - end - - def parse_spec(line) - return unless line =~ NAME_VERSION - spaces = $1 - name = $2 - version = $3 - platform = $4 - - if spaces.size == 4 - version = Gem::Version.new(version) - platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY - @current_spec = LazySpecification.new(name, version, platform) - @current_spec.source = @current_source - - # Avoid introducing multiple copies of the same spec (caused by - # duplicate GIT sections) - @specs[@current_spec.identifier] ||= @current_spec - elsif spaces.size == 6 - version = version.split(",").map(&:strip) if version - dep = Gem::Dependency.new(name, version) - @current_spec.dependencies << dep - end - end - - def parse_platform(line) - @platforms << Gem::Platform.new($1) if line =~ /^ (.*)$/ - end - - def parse_bundled_with(line) - line = line.strip - return unless Gem::Version.correct?(line) - @bundler_version = Gem::Version.create(line) - end - - def parse_ruby(line) - @ruby_version = line.strip - end - end -end diff --git a/lib/ruby/stdlib/bundler/match_platform.rb b/lib/ruby/stdlib/bundler/match_platform.rb deleted file mode 100644 index 56cbbfb95dc..00000000000 --- a/lib/ruby/stdlib/bundler/match_platform.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require "bundler/gem_helpers" - -module Bundler - module MatchPlatform - include GemHelpers - - def match_platform(p) - MatchPlatform.platforms_match?(platform, p) - end - - def self.platforms_match?(gemspec_platform, local_platform) - return true if gemspec_platform.nil? - return true if Gem::Platform::RUBY == gemspec_platform - return true if local_platform == gemspec_platform - gemspec_platform = Gem::Platform.new(gemspec_platform) - return true if GemHelpers.generic(gemspec_platform) === local_platform - return true if gemspec_platform === local_platform - - false - end - end -end diff --git a/lib/ruby/stdlib/bundler/mirror.rb b/lib/ruby/stdlib/bundler/mirror.rb deleted file mode 100644 index b15190e7e57..00000000000 --- a/lib/ruby/stdlib/bundler/mirror.rb +++ /dev/null @@ -1,223 +0,0 @@ -# frozen_string_literal: true - -require "socket" - -module Bundler - class Settings - # Class used to build the mirror set and then find a mirror for a given URI - # - # @param prober [Prober object, nil] by default a TCPSocketProbe, this object - # will be used to probe the mirror address to validate that the mirror replies. - class Mirrors - def initialize(prober = nil) - @all = Mirror.new - @prober = prober || TCPSocketProbe.new - @mirrors = {} - end - - # Returns a mirror for the given uri. - # - # Depending on the uri having a valid mirror or not, it may be a - # mirror that points to the provided uri - def for(uri) - if @all.validate!(@prober).valid? - @all - else - fetch_valid_mirror_for(Settings.normalize_uri(uri)) - end - end - - def each - @mirrors.each do |k, v| - yield k, v.uri.to_s - end - end - - def parse(key, value) - config = MirrorConfig.new(key, value) - mirror = if config.all? - @all - else - @mirrors[config.uri] ||= Mirror.new - end - config.update_mirror(mirror) - end - - private - - def fetch_valid_mirror_for(uri) - downcased = uri.to_s.downcase - mirror = @mirrors[downcased] || @mirrors[URI(downcased).host] || Mirror.new(uri) - mirror.validate!(@prober) - mirror = Mirror.new(uri) unless mirror.valid? - mirror - end - end - - # A mirror - # - # Contains both the uri that should be used as a mirror and the - # fallback timeout which will be used for probing if the mirror - # replies on time or not. - class Mirror - DEFAULT_FALLBACK_TIMEOUT = 0.1 - - attr_reader :uri, :fallback_timeout - - def initialize(uri = nil, fallback_timeout = 0) - self.uri = uri - self.fallback_timeout = fallback_timeout - @valid = nil - end - - def uri=(uri) - @uri = if uri.nil? - nil - else - URI(uri.to_s) - end - @valid = nil - end - - def fallback_timeout=(timeout) - case timeout - when true, "true" - @fallback_timeout = DEFAULT_FALLBACK_TIMEOUT - when false, "false" - @fallback_timeout = 0 - else - @fallback_timeout = timeout.to_i - end - @valid = nil - end - - def ==(other) - !other.nil? && uri == other.uri && fallback_timeout == other.fallback_timeout - end - - def valid? - return false if @uri.nil? - return @valid unless @valid.nil? - false - end - - def validate!(probe = nil) - @valid = false if uri.nil? - if @valid.nil? - @valid = fallback_timeout == 0 || (probe || TCPSocketProbe.new).replies?(self) - end - self - end - end - - # Class used to parse one configuration line - # - # Gets the configuration line and the value. - # This object provides a `update_mirror` method - # used to setup the given mirror value. - class MirrorConfig - attr_accessor :uri, :value - - def initialize(config_line, value) - uri, fallback = - config_line.match(%r{\Amirror\.(all|.+?)(\.fallback_timeout)?\/?\z}).captures - @fallback = !fallback.nil? - @all = false - if uri == "all" - @all = true - else - @uri = URI(uri).absolute? ? Settings.normalize_uri(uri) : uri - end - @value = value - end - - def all? - @all - end - - def update_mirror(mirror) - if @fallback - mirror.fallback_timeout = @value - else - mirror.uri = Settings.normalize_uri(@value) - end - end - end - - # Class used for probing TCP availability for a given mirror. - class TCPSocketProbe - def replies?(mirror) - MirrorSockets.new(mirror).any? do |socket, address, timeout| - begin - socket.connect_nonblock(address) - rescue Errno::EINPROGRESS - wait_for_writtable_socket(socket, address, timeout) - rescue RuntimeError # Connection failed somehow, again - false - end - end - end - - private - - def wait_for_writtable_socket(socket, address, timeout) - if IO.select(nil, [socket], nil, timeout) - probe_writtable_socket(socket, address) - else # TCP Handshake timed out, or there is something dropping packets - false - end - end - - def probe_writtable_socket(socket, address) - socket.connect_nonblock(address) - rescue Errno::EISCONN - true - rescue StandardError # Connection failed - false - end - end - end - - # Class used to build the list of sockets that correspond to - # a given mirror. - # - # One mirror may correspond to many different addresses, both - # because of it having many dns entries or because - # the network interface is both ipv4 and ipv5 - class MirrorSockets - def initialize(mirror) - @timeout = mirror.fallback_timeout - @addresses = Socket.getaddrinfo(mirror.uri.host, mirror.uri.port).map do |address| - SocketAddress.new(address[0], address[3], address[1]) - end - end - - def any? - @addresses.any? do |address| - socket = Socket.new(Socket.const_get(address.type), Socket::SOCK_STREAM, 0) - socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) - value = yield socket, address.to_socket_address, @timeout - socket.close unless socket.closed? - value - end - end - end - - # Socket address builder. - # - # Given a socket type, a host and a port, - # provides a method to build sockaddr string - class SocketAddress - attr_reader :type, :host, :port - - def initialize(type, host, port) - @type = type - @host = host - @port = port - end - - def to_socket_address - Socket.pack_sockaddr_in(@port, @host) - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin.rb b/lib/ruby/stdlib/bundler/plugin.rb deleted file mode 100644 index 53f9806b73d..00000000000 --- a/lib/ruby/stdlib/bundler/plugin.rb +++ /dev/null @@ -1,292 +0,0 @@ -# frozen_string_literal: true - -require "bundler/plugin/api" - -module Bundler - module Plugin - autoload :DSL, "bundler/plugin/dsl" - autoload :Events, "bundler/plugin/events" - autoload :Index, "bundler/plugin/index" - autoload :Installer, "bundler/plugin/installer" - autoload :SourceList, "bundler/plugin/source_list" - - class MalformattedPlugin < PluginError; end - class UndefinedCommandError < PluginError; end - class UnknownSourceError < PluginError; end - - PLUGIN_FILE_NAME = "plugins.rb".freeze - - module_function - - def reset! - instance_variables.each {|i| remove_instance_variable(i) } - - @sources = {} - @commands = {} - @hooks_by_event = Hash.new {|h, k| h[k] = [] } - @loaded_plugin_names = [] - end - - reset! - - # Installs a new plugin by the given name - # - # @param [Array] names the name of plugin to be installed - # @param [Hash] options various parameters as described in description. - # Refer to cli/plugin for available options - def install(names, options) - specs = Installer.new.install(names, options) - - save_plugins names, specs - rescue PluginError => e - if specs - specs_to_delete = Hash[specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) }] - specs_to_delete.values.each {|spec| Bundler.rm_rf(spec.full_gem_path) } - end - - Bundler.ui.error "Failed to install plugin #{name}: #{e.message}\n #{e.backtrace.join("\n ")}" - end - - # Evaluates the Gemfile with a limited DSL and installs the plugins - # specified by plugin method - # - # @param [Pathname] gemfile path - # @param [Proc] block that can be evaluated for (inline) Gemfile - def gemfile_install(gemfile = nil, &inline) - builder = DSL.new - if block_given? - builder.instance_eval(&inline) - else - builder.eval_gemfile(gemfile) - end - definition = builder.to_definition(nil, true) - - return if definition.dependencies.empty? - - plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p } - installed_specs = Installer.new.install_definition(definition) - - save_plugins plugins, installed_specs, builder.inferred_plugins - rescue RuntimeError => e - unless e.is_a?(GemfileError) - Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}" - end - raise - end - - # The index object used to store the details about the plugin - def index - @index ||= Index.new - end - - # The directory root for all plugin related data - # - # If run in an app, points to local root, in app_config_path - # Otherwise, points to global root, in Bundler.user_bundle_path("plugin") - def root - @root ||= if SharedHelpers.in_bundle? - local_root - else - global_root - end - end - - def local_root - Bundler.app_config_path.join("plugin") - end - - # The global directory root for all plugin related data - def global_root - Bundler.user_bundle_path("plugin") - end - - # The cache directory for plugin stuffs - def cache - @cache ||= root.join("cache") - end - - # To be called via the API to register to handle a command - def add_command(command, cls) - @commands[command] = cls - end - - # Checks if any plugin handles the command - def command?(command) - !index.command_plugin(command).nil? - end - - # To be called from Cli class to pass the command and argument to - # approriate plugin class - def exec_command(command, args) - raise UndefinedCommandError, "Command `#{command}` not found" unless command? command - - load_plugin index.command_plugin(command) unless @commands.key? command - - @commands[command].new.exec(command, args) - end - - # To be called via the API to register to handle a source plugin - def add_source(source, cls) - @sources[source] = cls - end - - # Checks if any plugin declares the source - def source?(name) - !index.source_plugin(name.to_s).nil? - end - - # @return [Class] that handles the source. The calss includes API::Source - def source(name) - raise UnknownSourceError, "Source #{name} not found" unless source? name - - load_plugin(index.source_plugin(name)) unless @sources.key? name - - @sources[name] - end - - # @param [Hash] The options that are present in the lock file - # @return [API::Source] the instance of the class that handles the source - # type passed in locked_opts - def source_from_lock(locked_opts) - src = source(locked_opts["type"]) - - src.new(locked_opts.merge("uri" => locked_opts["remote"])) - end - - # To be called via the API to register a hooks and corresponding block that - # will be called to handle the hook - def add_hook(event, &block) - unless Events.defined_event?(event) - raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" - end - @hooks_by_event[event.to_s] << block - end - - # Runs all the hooks that are registered for the passed event - # - # It passes the passed arguments and block to the block registered with - # the api. - # - # @param [String] event - def hook(event, *args, &arg_blk) - return unless Bundler.feature_flag.plugins? - unless Events.defined_event?(event) - raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" - end - - plugins = index.hook_plugins(event) - return unless plugins.any? - - (plugins - @loaded_plugin_names).each {|name| load_plugin(name) } - - @hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) } - end - - # currently only intended for specs - # - # @return [String, nil] installed path - def installed?(plugin) - Index.new.installed?(plugin) - end - - # Post installation processing and registering with index - # - # @param [Array] plugins list to be installed - # @param [Hash] specs of plugins mapped to installation path (currently they - # contain all the installed specs, including plugins) - # @param [Array] names of inferred source plugins that can be ignored - def save_plugins(plugins, specs, optional_plugins = []) - plugins.each do |name| - spec = specs[name] - validate_plugin! Pathname.new(spec.full_gem_path) - installed = register_plugin(name, spec, optional_plugins.include?(name)) - Bundler.ui.info "Installed plugin #{name}" if installed - end - end - - # Checks if the gem is good to be a plugin - # - # At present it only checks whether it contains plugins.rb file - # - # @param [Pathname] plugin_path the path plugin is installed at - # @raise [MalformattedPlugin] if plugins.rb file is not found - def validate_plugin!(plugin_path) - plugin_file = plugin_path.join(PLUGIN_FILE_NAME) - raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file? - end - - # Runs the plugins.rb file in an isolated namespace, records the plugin - # actions it registers for and then passes the data to index to be stored. - # - # @param [String] name the name of the plugin - # @param [Specification] spec of installed plugin - # @param [Boolean] optional_plugin, removed if there is conflict with any - # other plugin (used for default source plugins) - # - # @raise [MalformattedPlugin] if plugins.rb raises any error - def register_plugin(name, spec, optional_plugin = false) - commands = @commands - sources = @sources - hooks = @hooks_by_event - - @commands = {} - @sources = {} - @hooks_by_event = Hash.new {|h, k| h[k] = [] } - - load_paths = spec.load_paths - add_to_load_path(load_paths) - path = Pathname.new spec.full_gem_path - - begin - load path.join(PLUGIN_FILE_NAME), true - rescue StandardError => e - raise MalformattedPlugin, "#{e.class}: #{e.message}" - end - - if optional_plugin && @sources.keys.any? {|s| source? s } - Bundler.rm_rf(path) - false - else - index.register_plugin(name, path.to_s, load_paths, @commands.keys, - @sources.keys, @hooks_by_event.keys) - true - end - ensure - @commands = commands - @sources = sources - @hooks_by_event = hooks - end - - # Executes the plugins.rb file - # - # @param [String] name of the plugin - def load_plugin(name) - # Need to ensure before this that plugin root where the rest of gems - # are installed to be on load path to support plugin deps. Currently not - # done to avoid conflicts - path = index.plugin_path(name) - - add_to_load_path(index.load_paths(name)) - - load path.join(PLUGIN_FILE_NAME) - - @loaded_plugin_names << name - rescue RuntimeError => e - Bundler.ui.error "Failed loading plugin #{name}: #{e.message}" - raise - end - - def add_to_load_path(load_paths) - if insert_index = Bundler.rubygems.load_path_insert_index - $LOAD_PATH.insert(insert_index, *load_paths) - else - $LOAD_PATH.unshift(*load_paths) - end - end - - class << self - private :load_plugin, :register_plugin, :save_plugins, :validate_plugin!, - :add_to_load_path - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/api.rb b/lib/ruby/stdlib/bundler/plugin/api.rb deleted file mode 100644 index a2d5cbb4ac5..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/api.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # This is the interfacing class represents the API that we intend to provide - # the plugins to use. - # - # For plugins to be independent of the Bundler internals they shall limit their - # interactions to methods of this class only. This will save them from breaking - # when some internal change. - # - # Currently we are delegating the methods defined in Bundler class to - # itself. So, this class acts as a buffer. - # - # If there is some change in the Bundler class that is incompatible to its - # previous behavior or if otherwise desired, we can reimplement(or implement) - # the method to preserve compatibility. - # - # To use this, either the class can inherit this class or use it directly. - # For example of both types of use, refer the file `spec/plugins/command.rb` - # - # To use it without inheriting, you will have to create an object of this - # to use the functions (except for declaration functions like command, source, - # and hooks). - module Plugin - class API - autoload :Source, "bundler/plugin/api/source" - - # The plugins should declare that they handle a command through this helper. - # - # @param [String] command being handled by them - # @param [Class] (optional) class that handles the command. If not - # provided, the `self` class will be used. - def self.command(command, cls = self) - Plugin.add_command command, cls - end - - # The plugins should declare that they provide a installation source - # through this helper. - # - # @param [String] the source type they provide - # @param [Class] (optional) class that handles the source. If not - # provided, the `self` class will be used. - def self.source(source, cls = self) - cls.send :include, Bundler::Plugin::API::Source - Plugin.add_source source, cls - end - - def self.hook(event, &block) - Plugin.add_hook(event, &block) - end - - # The cache dir to be used by the plugins for storage - # - # @return [Pathname] path of the cache dir - def cache_dir - Plugin.cache.join("plugins") - end - - # A tmp dir to be used by plugins - # Accepts names that get concatenated as suffix - # - # @return [Pathname] object for the new directory created - def tmp(*names) - Bundler.tmp(["plugin", *names].join("-")) - end - - def method_missing(name, *args, &blk) - return Bundler.send(name, *args, &blk) if Bundler.respond_to?(name) - - return SharedHelpers.send(name, *args, &blk) if SharedHelpers.respond_to?(name) - - super - end - - def respond_to_missing?(name, include_private = false) - SharedHelpers.respond_to?(name, include_private) || - Bundler.respond_to?(name, include_private) || super - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/api/source.rb b/lib/ruby/stdlib/bundler/plugin/api/source.rb deleted file mode 100644 index 586477efb55..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/api/source.rb +++ /dev/null @@ -1,306 +0,0 @@ -# frozen_string_literal: true - -require "uri" - -module Bundler - module Plugin - class API - # This class provides the base to build source plugins - # All the method here are required to build a source plugin (except - # `uri_hash`, `gem_install_dir`; they are helpers). - # - # Defaults for methods, where ever possible are provided which is - # expected to work. But, all source plugins have to override - # `fetch_gemspec_files` and `install`. Defaults are also not provided for - # `remote!`, `cache!` and `unlock!`. - # - # The defaults shall work for most situations but nevertheless they can - # be (preferably should be) overridden as per the plugins' needs safely - # (as long as they behave as expected). - # On overriding `initialize` you should call super first. - # - # If required plugin should override `hash`, `==` and `eql?` methods to be - # able to match objects representing same sources, but may be created in - # different situation (like form gemfile and lockfile). The default ones - # checks only for class and uri, but elaborate source plugins may need - # more comparisons (e.g. git checking on branch or tag). - # - # @!attribute [r] uri - # @return [String] the remote specified with `source` block in Gemfile - # - # @!attribute [r] options - # @return [String] options passed during initialization (either from - # lockfile or Gemfile) - # - # @!attribute [r] name - # @return [String] name that can be used to uniquely identify a source - # - # @!attribute [rw] dependency_names - # @return [Array] Names of dependencies that the source should - # try to resolve. It is not necessary to use this list intenally. This - # is present to be compatible with `Definition` and is used by - # rubygems source. - module Source - attr_reader :uri, :options, :name - attr_accessor :dependency_names - - def initialize(opts) - @options = opts - @dependency_names = [] - @uri = opts["uri"] - @type = opts["type"] - @name = opts["name"] || "#{@type} at #{@uri}" - end - - # This is used by the default `spec` method to constructs the - # Specification objects for the gems and versions that can be installed - # by this source plugin. - # - # Note: If the spec method is overridden, this function is not necessary - # - # @return [Array] paths of the gemspec files for gems that can - # be installed - def fetch_gemspec_files - [] - end - - # Options to be saved in the lockfile so that the source plugin is able - # to check out same version of gem later. - # - # There options are passed when the source plugin is created from the - # lock file. - # - # @return [Hash] - def options_to_lock - {} - end - - # Install the gem specified by the spec at appropriate path. - # `install_path` provides a sufficient default, if the source can only - # satisfy one gem, but is not binding. - # - # @return [String] post installation message (if any) - def install(spec, opts) - raise MalformattedPlugin, "Source plugins need to override the install method." - end - - # It builds extensions, generates bins and installs them for the spec - # provided. - # - # It depends on `spec.loaded_from` to get full_gem_path. The source - # plugins should set that. - # - # It should be called in `install` after the plugin is done placing the - # gem at correct install location. - # - # It also runs Gem hooks `pre_install`, `post_build` and `post_install` - # - # Note: Do not override if you don't know what you are doing. - def post_install(spec, disable_exts = false) - opts = { :env_shebang => false, :disable_extensions => disable_exts } - installer = Bundler::Source::Path::Installer.new(spec, opts) - installer.post_install - end - - # A default installation path to install a single gem. If the source - # servers multiple gems, it's not of much use and the source should one - # of its own. - def install_path - @install_path ||= - begin - base_name = File.basename(URI.parse(uri).normalize.path) - - gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") - end - end - - # Parses the gemspec files to find the specs for the gems that can be - # satisfied by the source. - # - # Few important points to keep in mind: - # - If the gems are not installed then it shall return specs for all - # the gems it can satisfy - # - If gem is installed (that is to be detected by the plugin itself) - # then it shall return at least the specs that are installed. - # - The `loaded_from` for each of the specs shall be correct (it is - # used to find the load path) - # - # @return [Bundler::Index] index containing the specs - def specs - files = fetch_gemspec_files - - Bundler::Index.build do |index| - files.each do |file| - next unless spec = Bundler.load_gemspec(file) - Bundler.rubygems.set_installed_by_version(spec) - - spec.source = self - Bundler.rubygems.validate(spec) - - index << spec - end - end - end - - # Set internal representation to fetch the gems/specs from remote. - # - # When this is called, the source should try to fetch the specs and - # install from remote path. - def remote! - end - - # Set internal representation to fetch the gems/specs from app cache. - # - # When this is called, the source should try to fetch the specs and - # install from the path provided by `app_cache_path`. - def cached! - end - - # This is called to update the spec and installation. - # - # If the source plugin is loaded from lockfile or otherwise, it shall - # refresh the cache/specs (e.g. git sources can make a fresh clone). - def unlock! - end - - # Name of directory where plugin the is expected to cache the gems when - # #cache is called. - # - # Also this name is matched against the directories in cache for pruning - # - # This is used by `app_cache_path` - def app_cache_dirname - base_name = File.basename(URI.parse(uri).normalize.path) - "#{base_name}-#{uri_hash}" - end - - # This method is called while caching to save copy of the gems that the - # source can resolve to path provided by `app_cache_app`so that they can - # be reinstalled from the cache without querying the remote (i.e. an - # alternative to remote) - # - # This is stored with the app and source plugins should try to provide - # specs and install only from this cache when `cached!` is called. - # - # This cache is different from the internal caching that can be done - # at sub paths of `cache_path` (from API). This can be though as caching - # by bundler. - def cache(spec, custom_path = nil) - new_cache_path = app_cache_path(custom_path) - - FileUtils.rm_rf(new_cache_path) - FileUtils.cp_r(install_path, new_cache_path) - FileUtils.touch(app_cache_path.join(".bundlecache")) - end - - # This shall check if two source object represent the same source. - # - # The comparison shall take place only on the attribute that can be - # inferred from the options passed from Gemfile and not on attibutes - # that are used to pin down the gem to specific version (e.g. Git - # sources should compare on branch and tag but not on commit hash) - # - # The sources objects are constructed from Gemfile as well as from - # lockfile. To converge the sources, it is necessary that they match. - # - # The same applies for `eql?` and `hash` - def ==(other) - other.is_a?(self.class) && uri == other.uri - end - - # When overriding `eql?` please preserve the behaviour as mentioned in - # docstring for `==` method. - alias_method :eql?, :== - - # When overriding `hash` please preserve the behaviour as mentioned in - # docstring for `==` method, i.e. two methods equal by above comparison - # should have same hash. - def hash - [self.class, uri].hash - end - - # A helper method, not necessary if not used internally. - def installed? - File.directory?(install_path) - end - - # The full path where the plugin should cache the gem so that it can be - # installed latter. - # - # Note: Do not override if you don't know what you are doing. - def app_cache_path(custom_path = nil) - @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) - end - - # Used by definition. - # - # Note: Do not override if you don't know what you are doing. - def unmet_deps - specs.unmet_dependency_names - end - - # Note: Do not override if you don't know what you are doing. - def can_lock?(spec) - spec.source == self - end - - # Generates the content to be entered into the lockfile. - # Saves type and remote and also calls to `options_to_lock`. - # - # Plugin should use `options_to_lock` to save information in lockfile - # and not override this. - # - # Note: Do not override if you don't know what you are doing. - def to_lock - out = String.new("#{LockfileParser::PLUGIN}\n") - out << " remote: #{@uri}\n" - out << " type: #{@type}\n" - options_to_lock.each do |opt, value| - out << " #{opt}: #{value}\n" - end - out << " specs:\n" - end - - def to_s - "plugin source for #{options[:type]} with uri #{uri}" - end - - # Note: Do not override if you don't know what you are doing. - def include?(other) - other == self - end - - def uri_hash - SharedHelpers.digest(:SHA1).hexdigest(uri) - end - - # Note: Do not override if you don't know what you are doing. - def gem_install_dir - Bundler.install_path - end - - # It is used to obtain the full_gem_path. - # - # spec's loaded_from path is expanded against this to get full_gem_path - # - # Note: Do not override if you don't know what you are doing. - def root - Bundler.root - end - - # @private - # Returns true - def bundler_plugin_api_source? - true - end - - # @private - # This API on source might not be stable, and for now we expect plugins - # to download all specs in `#specs`, so we implement the method for - # compatibility purposes and leave it undocumented (and don't support) - # overriding it) - def double_check_for(*); end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/dsl.rb b/lib/ruby/stdlib/bundler/plugin/dsl.rb deleted file mode 100644 index 4bfc8437e0e..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/dsl.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module Plugin - # Dsl to parse the Gemfile looking for plugins to install - class DSL < Bundler::Dsl - class PluginGemfileError < PluginError; end - alias_method :_gem, :gem # To use for plugin installation as gem - - # So that we don't have to override all there methods to dummy ones - # explicitly. - # They will be handled by method_missing - [:gemspec, :gem, :path, :install_if, :platforms, :env].each {|m| undef_method m } - - # This lists the plugins that was added automatically and not specified by - # the user. - # - # When we encounter :type attribute with a source block, we add a plugin - # by name bundler-source- to list of plugins to be installed. - # - # These plugins are optional and are not installed when there is conflict - # with any other plugin. - attr_reader :inferred_plugins - - def initialize - super - @sources = Plugin::SourceList.new - @inferred_plugins = [] # The source plugins inferred from :type - end - - def plugin(name, *args) - _gem(name, *args) - end - - def method_missing(name, *args) - raise PluginGemfileError, "Undefined local variable or method `#{name}' for Gemfile" unless Bundler::Dsl.method_defined? name - end - - def source(source, *args, &blk) - options = args.last.is_a?(Hash) ? args.pop.dup : {} - options = normalize_hash(options) - return super unless options.key?("type") - - plugin_name = "bundler-source-#{options["type"]}" - - return if @dependencies.any? {|d| d.name == plugin_name } - - plugin(plugin_name) - @inferred_plugins << plugin_name - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/events.rb b/lib/ruby/stdlib/bundler/plugin/events.rb deleted file mode 100644 index bc037d1af50..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/events.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module Plugin - module Events - def self.define(const, event) - const = const.to_sym.freeze - if const_defined?(const) && const_get(const) != event - raise ArgumentError, "Attempting to reassign #{const} to a different value" - end - const_set(const, event) unless const_defined?(const) - @events ||= {} - @events[event] = const - end - private_class_method :define - - def self.reset - @events.each_value do |const| - remove_const(const) - end - @events = nil - end - private_class_method :reset - - # Check if an event has been defined - # @param event [String] An event to check - # @return [Boolean] A boolean indicating if the event has been defined - def self.defined_event?(event) - @events ||= {} - @events.key?(event) - end - - # @!parse - # A hook called before each individual gem is installed - # Includes a Bundler::ParallelInstaller::SpecInstallation. - # No state, error, post_install_message will be present as nothing has installed yet - # GEM_BEFORE_INSTALL = "before-install" - define :GEM_BEFORE_INSTALL, "before-install" - - # @!parse - # A hook called after each individual gem is installed - # Includes a Bundler::ParallelInstaller::SpecInstallation. - # - If state is failed, an error will be present. - # - If state is success, a post_install_message may be present. - # GEM_AFTER_INSTALL = "after-install" - define :GEM_AFTER_INSTALL, "after-install" - - # @!parse - # A hook called before any gems install - # Includes an Array of Bundler::Dependency objects - # GEM_BEFORE_INSTALL_ALL = "before-install-all" - define :GEM_BEFORE_INSTALL_ALL, "before-install-all" - - # @!parse - # A hook called after any gems install - # Includes an Array of Bundler::Dependency objects - # GEM_AFTER_INSTALL_ALL = "after-install-all" - define :GEM_AFTER_INSTALL_ALL, "after-install-all" - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/index.rb b/lib/ruby/stdlib/bundler/plugin/index.rb deleted file mode 100644 index f09587dfda7..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/index.rb +++ /dev/null @@ -1,162 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # Manages which plugins are installed and their sources. This also is supposed to map - # which plugin does what (currently the features are not implemented so this class is - # now a stub class). - module Plugin - class Index - class CommandConflict < PluginError - def initialize(plugin, commands) - msg = "Command(s) `#{commands.join("`, `")}` declared by #{plugin} are already registered." - super msg - end - end - - class SourceConflict < PluginError - def initialize(plugin, sources) - msg = "Source(s) `#{sources.join("`, `")}` declared by #{plugin} are already registered." - super msg - end - end - - attr_reader :commands - - def initialize - @plugin_paths = {} - @commands = {} - @sources = {} - @hooks = {} - @load_paths = {} - - begin - load_index(global_index_file, true) - rescue GenericSystemCallError - # no need to fail when on a read-only FS, for example - nil - end - load_index(local_index_file) if SharedHelpers.in_bundle? - end - - # This function is to be called when a new plugin is installed. This - # function shall add the functions of the plugin to existing maps and also - # the name to source location. - # - # @param [String] name of the plugin to be registered - # @param [String] path where the plugin is installed - # @param [Array] load_paths for the plugin - # @param [Array] commands that are handled by the plugin - # @param [Array] sources that are handled by the plugin - def register_plugin(name, path, load_paths, commands, sources, hooks) - old_commands = @commands.dup - - common = commands & @commands.keys - raise CommandConflict.new(name, common) unless common.empty? - commands.each {|c| @commands[c] = name } - - common = sources & @sources.keys - raise SourceConflict.new(name, common) unless common.empty? - sources.each {|k| @sources[k] = name } - - hooks.each {|e| (@hooks[e] ||= []) << name } - - @plugin_paths[name] = path - @load_paths[name] = load_paths - save_index - rescue StandardError - @commands = old_commands - raise - end - - # Path of default index file - def index_file - Plugin.root.join("index") - end - - # Path where the global index file is stored - def global_index_file - Plugin.global_root.join("index") - end - - # Path where the local index file is stored - def local_index_file - Plugin.local_root.join("index") - end - - def plugin_path(name) - Pathname.new @plugin_paths[name] - end - - def load_paths(name) - @load_paths[name] - end - - # Fetch the name of plugin handling the command - def command_plugin(command) - @commands[command] - end - - def installed?(name) - @plugin_paths[name] - end - - def source?(source) - @sources.key? source - end - - def source_plugin(name) - @sources[name] - end - - # Returns the list of plugin names handling the passed event - def hook_plugins(event) - @hooks[event] || [] - end - - private - - # Reads the index file from the directory and initializes the instance - # variables. - # - # It skips the sources if the second param is true - # @param [Pathname] index file path - # @param [Boolean] is the index file global index - def load_index(index_file, global = false) - SharedHelpers.filesystem_access(index_file, :read) do |index_f| - valid_file = index_f && index_f.exist? && !index_f.size.zero? - break unless valid_file - - data = index_f.read - - require "bundler/yaml_serializer" - index = YAMLSerializer.load(data) - - @commands.merge!(index["commands"]) - @hooks.merge!(index["hooks"]) - @load_paths.merge!(index["load_paths"]) - @plugin_paths.merge!(index["plugin_paths"]) - @sources.merge!(index["sources"]) unless global - end - end - - # Should be called when any of the instance variables change. Stores the - # instance variables in YAML format. (The instance variables are supposed - # to be only String key value pairs) - def save_index - index = { - "commands" => @commands, - "hooks" => @hooks, - "load_paths" => @load_paths, - "plugin_paths" => @plugin_paths, - "sources" => @sources, - } - - require "bundler/yaml_serializer" - SharedHelpers.filesystem_access(index_file) do |index_f| - FileUtils.mkdir_p(index_f.dirname) - File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) } - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/installer.rb b/lib/ruby/stdlib/bundler/plugin/installer.rb deleted file mode 100644 index 5379c38979c..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/installer.rb +++ /dev/null @@ -1,96 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # Handles the installation of plugin in appropriate directories. - # - # This class is supposed to be wrapper over the existing gem installation infra - # but currently it itself handles everything as the Source's subclasses (e.g. Source::RubyGems) - # are heavily dependent on the Gemfile. - module Plugin - class Installer - autoload :Rubygems, "bundler/plugin/installer/rubygems" - autoload :Git, "bundler/plugin/installer/git" - - def install(names, options) - version = options[:version] || [">= 0"] - Bundler.settings.temporary(:lockfile_uses_separate_rubygems_sources => false, :disable_multisource => false) do - if options[:git] - install_git(names, version, options) - else - sources = options[:source] || Bundler.rubygems.sources - install_rubygems(names, version, sources) - end - end - end - - # Installs the plugin from Definition object created by limited parsing of - # Gemfile searching for plugins to be installed - # - # @param [Definition] definition object - # @return [Hash] map of names to their specs they are installed with - def install_definition(definition) - def definition.lock(*); end - definition.resolve_remotely! - specs = definition.specs - - install_from_specs specs - end - - private - - def install_git(names, version, options) - uri = options.delete(:git) - options["uri"] = uri - - source_list = SourceList.new - source_list.add_git_source(options) - - # To support both sources - if options[:source] - source_list.add_rubygems_source("remotes" => options[:source]) - end - - deps = names.map {|name| Dependency.new name, version } - - definition = Definition.new(nil, deps, source_list, true) - install_definition(definition) - end - - # Installs the plugin from rubygems source and returns the path where the - # plugin was installed - # - # @param [String] name of the plugin gem to search in the source - # @param [Array] version of the gem to install - # @param [String, Array] source(s) to resolve the gem - # - # @return [Hash] map of names to the specs of plugins installed - def install_rubygems(names, version, sources) - deps = names.map {|name| Dependency.new name, version } - - source_list = SourceList.new - source_list.add_rubygems_source("remotes" => sources) - - definition = Definition.new(nil, deps, source_list, true) - install_definition(definition) - end - - # Installs the plugins and deps from the provided specs and returns map of - # gems to their paths - # - # @param specs to install - # - # @return [Hash] map of names to the specs - def install_from_specs(specs) - paths = {} - - specs.each do |spec| - spec.source.install spec - - paths[spec.name] = spec - end - - paths - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/installer/git.rb b/lib/ruby/stdlib/bundler/plugin/installer/git.rb deleted file mode 100644 index fbb6c5e40e6..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/installer/git.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module Plugin - class Installer - class Git < Bundler::Source::Git - def cache_path - @cache_path ||= begin - git_scope = "#{base_name}-#{uri_hash}" - - Plugin.cache.join("bundler", "git", git_scope) - end - end - - def install_path - @install_path ||= begin - git_scope = "#{base_name}-#{shortref_for_path(revision)}" - - Plugin.root.join("bundler", "gems", git_scope) - end - end - - def version_message(spec) - "#{spec.name} #{spec.version}" - end - - def root - Plugin.root - end - - def generate_bin(spec, disable_extensions = false) - # Need to find a way without code duplication - # For now, we can ignore this - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/installer/rubygems.rb b/lib/ruby/stdlib/bundler/plugin/installer/rubygems.rb deleted file mode 100644 index 7ae74fa93b3..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/installer/rubygems.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module Plugin - class Installer - class Rubygems < Bundler::Source::Rubygems - def version_message(spec) - "#{spec.name} #{spec.version}" - end - - private - - def requires_sudo? - false # Will change on implementation of project level plugins - end - - def rubygems_dir - Plugin.root - end - - def cache_path - Plugin.cache - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/plugin/source_list.rb b/lib/ruby/stdlib/bundler/plugin/source_list.rb deleted file mode 100644 index f0e212205ff..00000000000 --- a/lib/ruby/stdlib/bundler/plugin/source_list.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # SourceList object to be used while parsing the Gemfile, setting the - # approptiate options to be used with Source classes for plugin installation - module Plugin - class SourceList < Bundler::SourceList - def add_git_source(options = {}) - add_source_to_list Plugin::Installer::Git.new(options), git_sources - end - - def add_rubygems_source(options = {}) - add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources - end - - def all_sources - path_sources + git_sources + rubygems_sources + [metadata_source] - end - - private - - def rubygems_aggregate_class - Plugin::Installer::Rubygems - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/process_lock.rb b/lib/ruby/stdlib/bundler/process_lock.rb deleted file mode 100644 index cba4fcdba5f..00000000000 --- a/lib/ruby/stdlib/bundler/process_lock.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class ProcessLock - def self.lock(bundle_path = Bundler.bundle_path) - lock_file_path = File.join(bundle_path, "bundler.lock") - has_lock = false - - File.open(lock_file_path, "w") do |f| - f.flock(File::LOCK_EX) - has_lock = true - yield - f.flock(File::LOCK_UN) - end - rescue Errno::EACCES, Errno::ENOLCK, *[SharedHelpers.const_get_safely(:ENOTSUP, Errno)].compact - # In the case the user does not have access to - # create the lock file or is using NFS where - # locks are not available we skip locking. - yield - ensure - FileUtils.rm_f(lock_file_path) if has_lock - end - end -end diff --git a/lib/ruby/stdlib/bundler/psyched_yaml.rb b/lib/ruby/stdlib/bundler/psyched_yaml.rb deleted file mode 100644 index e654416a5a2..00000000000 --- a/lib/ruby/stdlib/bundler/psyched_yaml.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -# Psych could be a gem, so try to ask for it -begin - gem "psych" -rescue LoadError -end if defined?(gem) - -# Psych could be in the stdlib -# but it's too late if Syck is already loaded -begin - require "psych" unless defined?(Syck) -rescue LoadError - # Apparently Psych wasn't available. Oh well. -end - -# At least load the YAML stdlib, whatever that may be -require "yaml" unless defined?(YAML.dump) - -module Bundler - # On encountering invalid YAML, - # Psych raises Psych::SyntaxError - if defined?(::Psych::SyntaxError) - YamlLibrarySyntaxError = ::Psych::SyntaxError - else # Syck raises ArgumentError - YamlLibrarySyntaxError = ::ArgumentError - end -end - -require "bundler/deprecate" -begin - Bundler::Deprecate.skip_during do - require "rubygems/safe_yaml" - end -rescue LoadError - # it's OK if the file isn't there -end diff --git a/lib/ruby/stdlib/bundler/remote_specification.rb b/lib/ruby/stdlib/bundler/remote_specification.rb deleted file mode 100644 index 23e12343307..00000000000 --- a/lib/ruby/stdlib/bundler/remote_specification.rb +++ /dev/null @@ -1,114 +0,0 @@ -# frozen_string_literal: true - -require "uri" - -module Bundler - # Represents a lazily loaded gem specification, where the full specification - # is on the source server in rubygems' "quick" index. The proxy object is to - # be seeded with what we're given from the source's abbreviated index - the - # full specification will only be fetched when necessary. - class RemoteSpecification - include MatchPlatform - include Comparable - - attr_reader :name, :version, :platform - attr_writer :dependencies - attr_accessor :source, :remote - - def initialize(name, version, platform, spec_fetcher) - @name = name - @version = Gem::Version.create version - @platform = platform - @spec_fetcher = spec_fetcher - @dependencies = nil - end - - # Needed before installs, since the arch matters then and quick - # specs don't bother to include the arch in the platform string - def fetch_platform - @platform = _remote_specification.platform - end - - def full_name - if platform == Gem::Platform::RUBY || platform.nil? - "#{@name}-#{@version}" - else - "#{@name}-#{@version}-#{platform}" - end - end - - # Compare this specification against another object. Using sort_obj - # is compatible with Gem::Specification and other Bundler or RubyGems - # objects. Otherwise, use the default Object comparison. - def <=>(other) - if other.respond_to?(:sort_obj) - sort_obj <=> other.sort_obj - else - super - end - end - - # Because Rubyforge cannot be trusted to provide valid specifications - # once the remote gem is downloaded, the backend specification will - # be swapped out. - def __swap__(spec) - SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) - @_remote_specification = spec - end - - # Create a delegate used for sorting. This strategy is copied from - # RubyGems 2.23 and ensures that Bundler's specifications can be - # compared and sorted with RubyGems' own specifications. - # - # @see #<=> - # @see Gem::Specification#sort_obj - # - # @return [Array] an object you can use to compare and sort this - # specification against other specifications - def sort_obj - [@name, @version, @platform == Gem::Platform::RUBY ? -1 : 1] - end - - def to_s - "#<#{self.class} name=#{name} version=#{version} platform=#{platform}>" - end - - def dependencies - @dependencies ||= begin - deps = method_missing(:dependencies) - - # allow us to handle when the specs dependencies are an array of array of string - # see https://github.com/bundler/bundler/issues/5797 - deps = deps.map {|d| d.is_a?(Gem::Dependency) ? d : Gem::Dependency.new(*d) } - - deps - end - end - - def git_version - return unless loaded_from && source.is_a?(Bundler::Source::Git) - " #{source.revision[0..6]}" - end - - private - - def to_ary - nil - end - - def _remote_specification - @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform]) - @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ - " missing from the server! Try installing with `--full-index` as a workaround.") - end - - def method_missing(method, *args, &blk) - _remote_specification.send(method, *args, &blk) - end - - def respond_to?(method, include_all = false) - super || _remote_specification.respond_to?(method, include_all) - end - public :respond_to? - end -end diff --git a/lib/ruby/stdlib/bundler/resolver.rb b/lib/ruby/stdlib/bundler/resolver.rb deleted file mode 100644 index 545b4cc88ac..00000000000 --- a/lib/ruby/stdlib/bundler/resolver.rb +++ /dev/null @@ -1,373 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Resolver - require "bundler/vendored_molinillo" - require "bundler/resolver/spec_group" - - # Figures out the best possible configuration of gems that satisfies - # the list of passed dependencies and any child dependencies without - # causing any gem activation errors. - # - # ==== Parameters - # *dependencies:: The list of dependencies to resolve - # - # ==== Returns - # ,nil:: If the list of dependencies can be resolved, a - # collection of gemspecs is returned. Otherwise, nil is returned. - def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) - platforms = Set.new(platforms) if platforms - base = SpecSet.new(base) unless base.is_a?(SpecSet) - resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) - result = resolver.start(requirements) - SpecSet.new(result) - end - - def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) - @index = index - @source_requirements = source_requirements - @base = base - @resolver = Molinillo::Resolver.new(self, self) - @search_for = {} - @base_dg = Molinillo::DependencyGraph.new - @base.each do |ls| - dep = Dependency.new(ls.name, ls.version) - @base_dg.add_vertex(ls.name, DepProxy.new(dep, ls.platform), true) - end - additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } - @platforms = platforms - @gem_version_promoter = gem_version_promoter - @allow_bundler_dependency_conflicts = Bundler.feature_flag.allow_bundler_dependency_conflicts? - @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? - end - - def start(requirements) - @gem_version_promoter.prerelease_specified = @prerelease_specified = {} - requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? } - - verify_gemfile_dependencies_are_found!(requirements) - dg = @resolver.resolve(requirements, @base_dg) - dg.map(&:payload). - reject {|sg| sg.name.end_with?("\0") }. - map(&:to_specs).flatten - rescue Molinillo::VersionConflict => e - message = version_conflict_message(e) - raise VersionConflict.new(e.conflicts.keys.uniq, message) - rescue Molinillo::CircularDependencyError => e - names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" } - raise CyclicDependencyError, "Your bundle requires gems that depend" \ - " on each other, creating an infinite loop. Please remove" \ - " #{names.count > 1 ? "either " : ""}#{names.join(" or ")}" \ - " and try again." - end - - include Molinillo::UI - - # Conveys debug information to the user. - # - # @param [Integer] depth the current depth of the resolution process. - # @return [void] - def debug(depth = 0) - return unless debug? - debug_info = yield - debug_info = debug_info.inspect unless debug_info.is_a?(String) - STDERR.puts debug_info.split("\n").map {|s| " " * depth + s } - end - - def debug? - return @debug_mode if defined?(@debug_mode) - @debug_mode = ENV["DEBUG_RESOLVER"] || ENV["DEBUG_RESOLVER_TREE"] || false - end - - def before_resolution - Bundler.ui.info "Resolving dependencies...", debug? - end - - def after_resolution - Bundler.ui.info "" - end - - def indicate_progress - Bundler.ui.info ".", false unless debug? - end - - include Molinillo::SpecificationProvider - - def dependencies_for(specification) - specification.dependencies_for_activated_platforms - end - - def search_for(dependency) - platform = dependency.__platform - dependency = dependency.dep unless dependency.is_a? Gem::Dependency - search = @search_for[dependency] ||= begin - index = index_for(dependency) - results = index.search(dependency, @base[dependency.name]) - - if vertex = @base_dg.vertex_named(dependency.name) - locked_requirement = vertex.payload.requirement - end - - if !@prerelease_specified[dependency.name] && (!@use_gvp || locked_requirement.nil?) - # Move prereleases to the beginning of the list, so they're considered - # last during resolution. - pre, results = results.partition {|spec| spec.version.prerelease? } - results = pre + results - end - - spec_groups = if results.any? - nested = [] - results.each do |spec| - version, specs = nested.last - if version == spec.version - specs << spec - else - nested << [spec.version, [spec]] - end - end - nested.reduce([]) do |groups, (version, specs)| - next groups if locked_requirement && !locked_requirement.satisfied_by?(version) - spec_group = SpecGroup.new(specs) - spec_group.ignores_bundler_dependencies = @allow_bundler_dependency_conflicts - groups << spec_group - end - else - [] - end - # GVP handles major itself, but it's still a bit risky to trust it with it - # until we get it settled with new behavior. For 2.x it can take over all cases. - if !@use_gvp - spec_groups - else - @gem_version_promoter.sort_versions(dependency, spec_groups) - end - end - search.select {|sg| sg.for?(platform) }.each {|sg| sg.activate_platform!(platform) } - end - - def index_for(dependency) - source = @source_requirements[dependency.name] - if source - source.specs - elsif @lockfile_uses_separate_rubygems_sources - Index.build do |idx| - if dependency.all_sources - dependency.all_sources.each {|s| idx.add_source(s.specs) if s } - else - idx.add_source @source_requirements[:default].specs - end - end - else - @index - end - end - - def name_for(dependency) - dependency.name - end - - def name_for_explicit_dependency_source - Bundler.default_gemfile.basename.to_s - rescue - "Gemfile" - end - - def name_for_locking_dependency_source - Bundler.default_lockfile.basename.to_s - rescue - "Gemfile.lock" - end - - def requirement_satisfied_by?(requirement, activated, spec) - return false unless requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) - spec.activate_platform!(requirement.__platform) if !@platforms || @platforms.include?(requirement.__platform) - true - end - - def relevant_sources_for_vertex(vertex) - if vertex.root? - [@source_requirements[vertex.name]] - elsif @lockfile_uses_separate_rubygems_sources - vertex.recursive_predecessors.map do |v| - @source_requirements[v.name] - end << @source_requirements[:default] - end - end - - def sort_dependencies(dependencies, activated, conflicts) - dependencies.sort_by do |dependency| - dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name)) - name = name_for(dependency) - vertex = activated.vertex_named(name) - [ - @base_dg.vertex_named(name) ? 0 : 1, - vertex.payload ? 0 : 1, - vertex.root? ? 0 : 1, - amount_constrained(dependency), - conflicts[name] ? 0 : 1, - vertex.payload ? 0 : search_for(dependency).count, - self.class.platform_sort_key(dependency.__platform), - ] - end - end - - # Sort platforms from most general to most specific - def self.sort_platforms(platforms) - platforms.sort_by do |platform| - platform_sort_key(platform) - end - end - - def self.platform_sort_key(platform) - return ["", "", ""] if Gem::Platform::RUBY == platform - platform.to_a.map {|part| part || "" } - end - - private - - # returns an integer \in (-\infty, 0] - # a number closer to 0 means the dependency is less constraining - # - # dependencies w/ 0 or 1 possibilities (ignoring version requirements) - # are given very negative values, so they _always_ sort first, - # before dependencies that are unconstrained - def amount_constrained(dependency) - @amount_constrained ||= {} - @amount_constrained[dependency.name] ||= begin - if (base = @base[dependency.name]) && !base.empty? - dependency.requirement.satisfied_by?(base.first.version) ? 0 : 1 - else - all = index_for(dependency).search(dependency.name).size - - if all <= 1 - all - 1_000_000 - else - search = search_for(dependency) - search = @prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? } - search - all - end - end - end - end - - def verify_gemfile_dependencies_are_found!(requirements) - requirements.each do |requirement| - name = requirement.name - next if name == "bundler" - next unless search_for(requirement).empty? - - cache_message = begin - " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? - rescue GemfileNotFound - nil - end - - if (base = @base[name]) && !base.empty? - version = base.first.version - message = "You have requested:\n" \ - " #{name} #{requirement.requirement}\n\n" \ - "The bundle currently has #{name} locked at #{version}.\n" \ - "Try running `bundle update #{name}`\n\n" \ - "If you are updating multiple gems in your Gemfile at once,\n" \ - "try passing them all to `bundle update`" - elsif source = @source_requirements[name] - specs = source.specs[name] - versions_with_platforms = specs.map {|s| [s.version, s.platform] } - message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n") - message << if versions_with_platforms.any? - "The source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}" - else - "The source does not contain any versions of '#{name}'" - end - else - message = "Could not find gem '#{requirement}' in any of the gem sources " \ - "listed in your Gemfile#{cache_message}." - end - raise GemNotFound, message - end - end - - def formatted_versions_with_platforms(versions_with_platforms) - version_platform_strs = versions_with_platforms.map do |vwp| - version = vwp.first - platform = vwp.last - version_platform_str = String.new(version.to_s) - version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY - version_platform_str - end - version_platform_strs.join(", ") - end - - def version_conflict_message(e) - e.message_with_trees( - :solver_name => "Bundler", - :possibility_type => "gem", - :reduce_trees => lambda do |trees| - # called first, because we want to reduce the amount of work required to find maximal empty sets - trees = trees.uniq {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } } - - # bail out if tree size is too big for Array#combination to make any sense - return trees if trees.size > 15 - maximal = 1.upto(trees.size).map do |size| - trees.map(&:last).flatten(1).combination(size).to_a - end.flatten(1).select do |deps| - Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement))) - end.min_by(&:size) - trees.reject! {|t| !maximal.include?(t.last) } if maximal - - trees = trees.sort_by {|t| t.flatten.map(&:to_s) } - trees.uniq! {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } } - - trees.sort_by {|t| t.reverse.map(&:name) } - end, - :printable_requirement => lambda {|req| SharedHelpers.pretty_dependency(req) }, - :additional_message_for_conflict => lambda do |o, name, conflict| - if name == "bundler" - o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION})) - other_bundler_required = !conflict.requirement.requirement.satisfied_by?(Gem::Version.new Bundler::VERSION) - end - - if name == "bundler" && other_bundler_required - o << "\n" - o << "This Gemfile requires a different version of Bundler.\n" - o << "Perhaps you need to update Bundler by running `gem install bundler`?\n" - end - if conflict.locked_requirement - o << "\n" - o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n) - o << %(the gems in your Gemfile, which may resolve the conflict.\n) - elsif !conflict.existing - o << "\n" - - relevant_sources = if conflict.requirement.source - [conflict.requirement.source] - elsif conflict.requirement.all_sources - conflict.requirement.all_sources - elsif @lockfile_uses_separate_rubygems_sources - # every conflict should have an explicit group of sources when we - # enforce strict pinning - raise "no source set for #{conflict}" - else - [] - end.compact.map(&:to_s).uniq.sort - - o << "Could not find gem '#{SharedHelpers.pretty_dependency(conflict.requirement)}'" - if conflict.requirement_trees.first.size > 1 - o << ", which is required by " - o << "gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}'," - end - o << " " - - o << if relevant_sources.empty? - "in any of the sources.\n" - else - "in any of the relevant sources:\n #{relevant_sources * "\n "}\n" - end - end - end, - :version_for_spec => lambda {|spec| spec.version } - ) - end - end -end diff --git a/lib/ruby/stdlib/bundler/resolver/spec_group.rb b/lib/ruby/stdlib/bundler/resolver/spec_group.rb deleted file mode 100644 index 34d043aed7f..00000000000 --- a/lib/ruby/stdlib/bundler/resolver/spec_group.rb +++ /dev/null @@ -1,106 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Resolver - class SpecGroup - include GemHelpers - - attr_accessor :name, :version, :source - attr_accessor :ignores_bundler_dependencies - - def initialize(all_specs) - raise ArgumentError, "cannot initialize with an empty value" unless exemplary_spec = all_specs.first - @name = exemplary_spec.name - @version = exemplary_spec.version - @source = exemplary_spec.source - - @activated_platforms = [] - @dependencies = nil - @specs = Hash.new do |specs, platform| - specs[platform] = select_best_platform_match(all_specs, platform) - end - @ignores_bundler_dependencies = true - end - - def to_specs - @activated_platforms.map do |p| - next unless s = @specs[p] - lazy_spec = LazySpecification.new(name, version, s.platform, source) - lazy_spec.dependencies.replace s.dependencies - lazy_spec - end.compact - end - - def activate_platform!(platform) - return unless for?(platform) - return if @activated_platforms.include?(platform) - @activated_platforms << platform - end - - def for?(platform) - spec = @specs[platform] - !spec.nil? - end - - def to_s - @to_s ||= "#{name} (#{version})" - end - - def dependencies_for_activated_platforms - dependencies = @activated_platforms.map {|p| __dependencies[p] } - metadata_dependencies = @activated_platforms.map do |platform| - metadata_dependencies(@specs[platform], platform) - end - dependencies.concat(metadata_dependencies).flatten - end - - def ==(other) - return unless other.is_a?(SpecGroup) - name == other.name && - version == other.version && - source == other.source - end - - def eql?(other) - name.eql?(other.name) && - version.eql?(other.version) && - source.eql?(other.source) - end - - def hash - to_s.hash ^ source.hash - end - - private - - def __dependencies - @dependencies = Hash.new do |dependencies, platform| - dependencies[platform] = [] - if spec = @specs[platform] - spec.dependencies.each do |dep| - next if dep.type == :development - next if @ignores_bundler_dependencies && dep.name == "bundler".freeze - dependencies[platform] << DepProxy.new(dep, platform) - end - end - dependencies[platform] - end - end - - def metadata_dependencies(spec, platform) - return [] unless spec - # Only allow endpoint specifications since they won't hit the network to - # fetch the full gemspec when calling required_ruby_version - return [] if !spec.is_a?(EndpointSpecification) && !spec.is_a?(Gem::Specification) - dependencies = [] - if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none? - dependencies << DepProxy.new(Gem::Dependency.new("ruby\0", spec.required_ruby_version), platform) - end - if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none? - dependencies << DepProxy.new(Gem::Dependency.new("rubygems\0", spec.required_rubygems_version), platform) - end - dependencies - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/retry.rb b/lib/ruby/stdlib/bundler/retry.rb deleted file mode 100644 index 244606dcc93..00000000000 --- a/lib/ruby/stdlib/bundler/retry.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # General purpose class for retrying code that may fail - class Retry - attr_accessor :name, :total_runs, :current_run - - class << self - def default_attempts - default_retries + 1 - end - alias_method :attempts, :default_attempts - - def default_retries - Bundler.settings[:retry] - end - end - - def initialize(name, exceptions = nil, retries = self.class.default_retries) - @name = name - @retries = retries - @exceptions = Array(exceptions) || [] - @total_runs = @retries + 1 # will run once, then upto attempts.times - end - - def attempt(&block) - @current_run = 0 - @failed = false - @error = nil - run(&block) while keep_trying? - @result - end - alias_method :attempts, :attempt - - private - - def run(&block) - @failed = false - @current_run += 1 - @result = block.call - rescue => e - fail_attempt(e) - end - - def fail_attempt(e) - @failed = true - if last_attempt? || @exceptions.any? {|k| e.is_a?(k) } - Bundler.ui.info "" unless Bundler.ui.debug? - raise e - end - return true unless name - Bundler.ui.info "" unless Bundler.ui.debug? # Add new line incase dots preceded this - Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug? - end - - def keep_trying? - return true if current_run.zero? - return false if last_attempt? - return true if @failed - end - - def last_attempt? - current_run >= total_runs - end - end -end diff --git a/lib/ruby/stdlib/bundler/ruby_dsl.rb b/lib/ruby/stdlib/bundler/ruby_dsl.rb deleted file mode 100644 index f6ba220cd55..00000000000 --- a/lib/ruby/stdlib/bundler/ruby_dsl.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module RubyDsl - def ruby(*ruby_version) - options = ruby_version.last.is_a?(Hash) ? ruby_version.pop : {} - ruby_version.flatten! - raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil? - raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil? - - if options[:engine] == "ruby" && options[:engine_version] && - ruby_version != Array(options[:engine_version]) - raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" - end - @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version]) - end - end -end diff --git a/lib/ruby/stdlib/bundler/ruby_version.rb b/lib/ruby/stdlib/bundler/ruby_version.rb deleted file mode 100644 index e6c31a94c91..00000000000 --- a/lib/ruby/stdlib/bundler/ruby_version.rb +++ /dev/null @@ -1,152 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class RubyVersion - attr_reader :versions, - :patchlevel, - :engine, - :engine_versions, - :gem_version, - :engine_gem_version - - def initialize(versions, patchlevel, engine, engine_version) - # The parameters to this method must satisfy the - # following constraints, which are verified in - # the DSL: - # - # * If an engine is specified, an engine version - # must also be specified - # * If an engine version is specified, an engine - # must also be specified - # * If the engine is "ruby", the engine version - # must not be specified, or the engine version - # specified must match the version. - - @versions = Array(versions).map do |v| - op, v = Gem::Requirement.parse(v) - op == "=" ? v.to_s : "#{op} #{v}" - end - - @gem_version = Gem::Requirement.create(@versions.first).requirements.first.last - @input_engine = engine && engine.to_s - @engine = engine && engine.to_s || "ruby" - @engine_versions = (engine_version && Array(engine_version)) || @versions - @engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last - @patchlevel = patchlevel - end - - def to_s(versions = self.versions) - output = String.new("ruby #{versions_string(versions)}") - output << "p#{patchlevel}" if patchlevel - output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby" - - output - end - - # @private - PATTERN = / - ruby\s - ([\d.]+) # ruby version - (?:p(-?\d+))? # optional patchlevel - (?:\s\((\S+)\s(.+)\))? # optional engine info - /xo - - # Returns a RubyVersion from the given string. - # @param [String] the version string to match. - # @return [RubyVersion,Nil] The version if the string is a valid RubyVersion - # description, and nil otherwise. - def self.from_string(string) - new($1, $2, $3, $4) if string =~ PATTERN - end - - def single_version_string - to_s(gem_version) - end - - def ==(other) - versions == other.versions && - engine == other.engine && - engine_versions == other.engine_versions && - patchlevel == other.patchlevel - end - - def host - @host ||= [ - RbConfig::CONFIG["host_cpu"], - RbConfig::CONFIG["host_vendor"], - RbConfig::CONFIG["host_os"] - ].join("-") - end - - # Returns a tuple of these things: - # [diff, this, other] - # The priority of attributes are - # 1. engine - # 2. ruby_version - # 3. engine_version - def diff(other) - raise ArgumentError, "Can only diff with a RubyVersion, not a #{other.class}" unless other.is_a?(RubyVersion) - if engine != other.engine && @input_engine - [:engine, engine, other.engine] - elsif versions.empty? || !matches?(versions, other.gem_version) - [:version, versions_string(versions), versions_string(other.versions)] - elsif @input_engine && !matches?(engine_versions, other.engine_gem_version) - [:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)] - elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel)) - [:patchlevel, patchlevel, other.patchlevel] - end - end - - def versions_string(versions) - Array(versions).join(", ") - end - - def self.system - ruby_engine = if defined?(RUBY_ENGINE) && !RUBY_ENGINE.nil? - RUBY_ENGINE.dup - else - # not defined in ruby 1.8.7 - "ruby" - end - # :sob: mocking RUBY_VERSION breaks stuff on 1.8.7 - ruby_version = ENV.fetch("BUNDLER_SPEC_RUBY_VERSION") { RUBY_VERSION }.dup - ruby_engine_version = case ruby_engine - when "ruby" - ruby_version - when "rbx" - Rubinius::VERSION.dup - when "jruby" - JRUBY_VERSION.dup - else - RUBY_ENGINE_VERSION.dup - end - patchlevel = RUBY_PATCHLEVEL.to_s - - @ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version) - end - - def to_gem_version_with_patchlevel - @gem_version_with_patch ||= begin - Gem::Version.create("#{@gem_version}.#{@patchlevel}") - rescue ArgumentError - @gem_version - end - end - - def exact? - return @exact if defined?(@exact) - @exact = versions.all? {|v| Gem::Requirement.create(v).exact? } - end - - private - - def matches?(requirements, version) - # Handles RUBY_PATCHLEVEL of -1 for instances like ruby-head - return requirements == version if requirements.to_s == "-1" || version.to_s == "-1" - - Array(requirements).all? do |requirement| - Gem::Requirement.create(requirement).satisfied_by?(Gem::Version.create(version)) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/rubygems_ext.rb b/lib/ruby/stdlib/bundler/rubygems_ext.rb deleted file mode 100644 index e9f0eac3558..00000000000 --- a/lib/ruby/stdlib/bundler/rubygems_ext.rb +++ /dev/null @@ -1,210 +0,0 @@ -# frozen_string_literal: true - -require "pathname" - -if defined?(Gem::QuickLoader) - # Gem Prelude makes me a sad panda :'( - Gem::QuickLoader.load_full_rubygems_library -end - -require "rubygems" -require "rubygems/specification" - -begin - # Possible use in Gem::Specification#source below and require - # shouldn't be deferred. - require "rubygems/source" -rescue LoadError - # Not available before RubyGems 2.0.0, ignore - nil -end - -require "bundler/match_platform" - -module Gem - @loaded_stacks = Hash.new {|h, k| h[k] = [] } - - class Specification - attr_accessor :remote, :location, :relative_loaded_from - - if instance_methods(false).map(&:to_sym).include?(:source) - remove_method :source - attr_writer :source - def source - (defined?(@source) && @source) || Gem::Source::Installed.new - end - else - attr_accessor :source - end - - alias_method :rg_full_gem_path, :full_gem_path - alias_method :rg_loaded_from, :loaded_from - - attr_writer :full_gem_path unless instance_methods.include?(:full_gem_path=) - - def full_gem_path - # this cannot check source.is_a?(Bundler::Plugin::API::Source) - # because that _could_ trip the autoload, and if there are unresolved - # gems at that time, this method could be called inside another require, - # thus raising with that constant being undefined. Better to check a method - if source.respond_to?(:path) || (source.respond_to?(:bundler_plugin_api_source?) && source.bundler_plugin_api_source?) - Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.untaint - else - rg_full_gem_path - end - end - - def loaded_from - if relative_loaded_from - source.path.join(relative_loaded_from).to_s - else - rg_loaded_from - end - end - - def load_paths - return full_require_paths if respond_to?(:full_require_paths) - - require_paths.map do |require_path| - if require_path.include?(full_gem_path) - require_path - else - File.join(full_gem_path, require_path) - end - end - end - - if method_defined?(:extension_dir) - alias_method :rg_extension_dir, :extension_dir - def extension_dir - @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name) - File.expand_path(File.join(extensions_dir, source.extension_dir_name)) - else - rg_extension_dir - end - end - end - - # RubyGems 1.8+ used only. - methods = instance_methods(false) - gem_dir = methods.first.is_a?(String) ? "gem_dir" : :gem_dir - remove_method :gem_dir if methods.include?(gem_dir) - def gem_dir - full_gem_path - end - - def groups - @groups ||= [] - end - - def git_version - return unless loaded_from && source.is_a?(Bundler::Source::Git) - " #{source.revision[0..6]}" - end - - def to_gemfile(path = nil) - gemfile = String.new("source 'https://rubygems.org'\n") - gemfile << dependencies_to_gemfile(nondevelopment_dependencies) - unless development_dependencies.empty? - gemfile << "\n" - gemfile << dependencies_to_gemfile(development_dependencies, :development) - end - gemfile - end - - def nondevelopment_dependencies - dependencies - development_dependencies - end - - private - - def dependencies_to_gemfile(dependencies, group = nil) - gemfile = String.new - if dependencies.any? - gemfile << "group :#{group} do\n" if group - dependencies.each do |dependency| - gemfile << " " if group - gemfile << %(gem "#{dependency.name}") - req = dependency.requirements_list.first - gemfile << %(, "#{req}") if req - gemfile << "\n" - end - gemfile << "end\n" if group - end - gemfile - end - end - - class Dependency - attr_accessor :source, :groups, :all_sources - - alias_method :eql?, :== - - def encode_with(coder) - to_yaml_properties.each do |ivar| - coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar) - end - end - - def to_yaml_properties - instance_variables.reject {|p| ["@source", "@groups", "@all_sources"].include?(p.to_s) } - end - - def to_lock - out = String.new(" #{name}") - unless requirement.none? - reqs = requirement.requirements.map {|o, v| "#{o} #{v}" }.sort.reverse - out << " (#{reqs.join(", ")})" - end - out - end - - # Backport of performance enhancement added to RubyGems 1.4 - def matches_spec?(spec) - # name can be a Regexp, so use === - return false unless name === spec.name - return true if requirement.none? - - requirement.satisfied_by?(spec.version) - end unless allocate.respond_to?(:matches_spec?) - end - - class Requirement - # Backport of performance enhancement added to RubyGems 1.4 - def none? - # note that it might be tempting to replace with with RubyGems 2.0's - # improved implementation. Don't. It requires `DefaultRequirement` to be - # defined, and more importantantly, these overrides are not used when the - # running RubyGems defines these methods - to_s == ">= 0" - end unless allocate.respond_to?(:none?) - - # Backport of performance enhancement added to RubyGems 2.2 - def exact? - return false unless @requirements.size == 1 - @requirements[0][0] == "=" - end unless allocate.respond_to?(:exact?) - end - - class Platform - JAVA = Gem::Platform.new("java") unless defined?(JAVA) - MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN) - MSWIN64 = Gem::Platform.new("mswin64") unless defined?(MSWIN64) - MINGW = Gem::Platform.new("x86-mingw32") unless defined?(MINGW) - X64_MINGW = Gem::Platform.new("x64-mingw32") unless defined?(X64_MINGW) - - undef_method :hash if method_defined? :hash - def hash - @cpu.hash ^ @os.hash ^ @version.hash - end - - undef_method :eql? if method_defined? :eql? - alias_method :eql?, :== - end -end - -module Gem - class Specification - include ::Bundler::MatchPlatform - end -end diff --git a/lib/ruby/stdlib/bundler/rubygems_gem_installer.rb b/lib/ruby/stdlib/bundler/rubygems_gem_installer.rb deleted file mode 100644 index 64b3c6d2707..00000000000 --- a/lib/ruby/stdlib/bundler/rubygems_gem_installer.rb +++ /dev/null @@ -1,106 +0,0 @@ -# frozen_string_literal: true - -require "rubygems/installer" - -module Bundler - class RubyGemsGemInstaller < Gem::Installer - unless respond_to?(:at) - def self.at(*args) - new(*args) - end - end - - attr_reader :options - - def initialize(gem, options = {}) - @options = {} - super - end - - def check_executable_overwrite(filename) - # Bundler needs to install gems regardless of binstub overwriting - end - - def pre_install_checks - super && validate_bundler_checksum(options[:bundler_expected_checksum]) - end - - def build_extensions - extension_cache_path = options[:bundler_extension_cache_path] - return super unless extension_cache_path && extension_dir = Bundler.rubygems.spec_extension_dir(spec) - - extension_dir = Pathname.new(extension_dir) - build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?) - if build_complete && !options[:force] - SharedHelpers.filesystem_access(extension_dir.parent, &:mkpath) - SharedHelpers.filesystem_access(extension_cache_path) do - FileUtils.cp_r extension_cache_path, spec.extension_dir - end - else - super - if extension_dir.directory? # not made for gems without extensions - SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath) - SharedHelpers.filesystem_access(extension_cache_path) do - FileUtils.cp_r extension_dir, extension_cache_path - end - end - end - end - - private - - def validate_bundler_checksum(checksum) - return true if Bundler.settings[:disable_checksum_validation] - return true unless checksum - return true unless source = @package.instance_variable_get(:@gem) - return true unless source.respond_to?(:with_read_io) - digest = source.with_read_io do |io| - digest = SharedHelpers.digest(:SHA256).new - digest << io.read(16_384) until io.eof? - io.rewind - send(checksum_type(checksum), digest) - end - unless digest == checksum - raise SecurityError, <<-MESSAGE - Bundler cannot continue installing #{spec.name} (#{spec.version}). - The checksum for the downloaded `#{spec.full_name}.gem` does not match \ - the checksum given by the server. This means the contents of the downloaded \ - gem is different from what was uploaded to the server, and could be a potential security issue. - - To resolve this issue: - 1. delete the downloaded gem located at: `#{spec.gem_dir}/#{spec.full_name}.gem` - 2. run `bundle install` - - If you wish to continue installing the downloaded gem, and are certain it does not pose a \ - security issue despite the mismatching checksum, do the following: - 1. run `bundle config disable_checksum_validation true` to turn off checksum verification - 2. run `bundle install` - - (More info: The expected SHA256 checksum was #{checksum.inspect}, but the \ - checksum for the downloaded gem was #{digest.inspect}.) - MESSAGE - end - true - end - - def checksum_type(checksum) - case checksum.length - when 64 then :hexdigest! - when 44 then :base64digest! - else raise InstallError, "The given checksum for #{spec.full_name} (#{checksum.inspect}) is not a valid SHA256 hexdigest nor base64digest" - end - end - - def hexdigest!(digest) - digest.hexdigest! - end - - def base64digest!(digest) - if digest.respond_to?(:base64digest!) - digest.base64digest! - else - [digest.digest!].pack("m0") - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/rubygems_integration.rb b/lib/ruby/stdlib/bundler/rubygems_integration.rb deleted file mode 100644 index 783d106e7b7..00000000000 --- a/lib/ruby/stdlib/bundler/rubygems_integration.rb +++ /dev/null @@ -1,898 +0,0 @@ -# frozen_string_literal: true - -require "monitor" -require "rubygems" -require "rubygems/config_file" - -module Bundler - class RubygemsIntegration - if defined?(Gem::Ext::Builder::CHDIR_MONITOR) - EXT_LOCK = Gem::Ext::Builder::CHDIR_MONITOR - else - EXT_LOCK = Monitor.new - end - - def self.version - @version ||= Gem::Version.new(Gem::VERSION) - end - - def self.provides?(req_str) - Gem::Requirement.new(req_str).satisfied_by?(version) - end - - def initialize - @replaced_methods = {} - end - - def version - self.class.version - end - - def provides?(req_str) - self.class.provides?(req_str) - end - - def build_args - Gem::Command.build_args - end - - def build_args=(args) - Gem::Command.build_args = args - end - - def load_path_insert_index - Gem.load_path_insert_index - end - - def loaded_specs(name) - Gem.loaded_specs[name] - end - - def mark_loaded(spec) - if spec.respond_to?(:activated=) - current = Gem.loaded_specs[spec.name] - current.activated = false if current - spec.activated = true - end - Gem.loaded_specs[spec.name] = spec - end - - def validate(spec) - Bundler.ui.silence { spec.validate(false) } - rescue Gem::InvalidSpecificationException => e - error_message = "The gemspec at #{spec.loaded_from} is not valid. Please fix this gemspec.\n" \ - "The validation error was '#{e.message}'\n" - raise Gem::InvalidSpecificationException.new(error_message) - rescue Errno::ENOENT - nil - end - - def set_installed_by_version(spec, installed_by_version = Gem::VERSION) - return unless spec.respond_to?(:installed_by_version=) - spec.installed_by_version = Gem::Version.create(installed_by_version) - end - - def spec_missing_extensions?(spec, default = true) - return spec.missing_extensions? if spec.respond_to?(:missing_extensions?) - - return false if spec_default_gem?(spec) - return false if spec.extensions.empty? - - default - end - - def spec_default_gem?(spec) - spec.respond_to?(:default_gem?) && spec.default_gem? - end - - def spec_matches_for_glob(spec, glob) - return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob) - - spec.load_paths.map do |lp| - Dir["#{lp}/#{glob}#{suffix_pattern}"] - end.flatten(1) - end - - def spec_extension_dir(spec) - return unless spec.respond_to?(:extension_dir) - spec.extension_dir - end - - def stub_set_spec(stub, spec) - stub.instance_variable_set(:@spec, spec) - end - - def path(obj) - obj.to_s - end - - def platforms - return [Gem::Platform::RUBY] if Bundler.settings[:force_ruby_platform] - Gem.platforms - end - - def configuration - require "bundler/psyched_yaml" - Gem.configuration - rescue Gem::SystemExitException, LoadError => e - Bundler.ui.error "#{e.class}: #{e.message}" - Bundler.ui.trace e - raise - rescue YamlLibrarySyntaxError => e - raise YamlSyntaxError.new(e, "Your RubyGems configuration, which is " \ - "usually located in ~/.gemrc, contains invalid YAML syntax.") - end - - def ruby_engine - Gem.ruby_engine - end - - def read_binary(path) - Gem.read_binary(path) - end - - def inflate(obj) - if defined?(Gem::Util) - Gem::Util.inflate(obj) - else - Gem.inflate(obj) - end - end - - def sources=(val) - # Gem.configuration creates a new Gem::ConfigFile, which by default will read ~/.gemrc - # If that file exists, its settings (including sources) will overwrite the values we - # are about to set here. In order to avoid that, we force memoizing the config file now. - configuration - - Gem.sources = val - end - - def sources - Gem.sources - end - - def gem_dir - Gem.dir - end - - def gem_bindir - Gem.bindir - end - - def user_home - Gem.user_home - end - - def gem_path - Gem.path - end - - def reset - Gem::Specification.reset - end - - def post_reset_hooks - Gem.post_reset_hooks - end - - def suffix_pattern - Gem.suffix_pattern - end - - def gem_cache - gem_path.map {|p| File.expand_path("cache", p) } - end - - def spec_cache_dirs - @spec_cache_dirs ||= begin - dirs = gem_path.map {|dir| File.join(dir, "specifications") } - dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in RubyGems 2.0.3 or earlier - dirs.uniq.select {|dir| File.directory? dir } - end - end - - def marshal_spec_dir - Gem::MARSHAL_SPEC_DIR - end - - def config_map - Gem::ConfigMap - end - - def repository_subdirectories - %w[cache doc gems specifications] - end - - def clear_paths - Gem.clear_paths - end - - def bin_path(gem, bin, ver) - Gem.bin_path(gem, bin, ver) - end - - def path_separator - File::PATH_SEPARATOR - end - - def preserve_paths - # this is a no-op outside of RubyGems 1.8 - yield - end - - def loaded_gem_paths - # RubyGems 2.2+ can put binary extension into dedicated folders, - # therefore use RubyGems facilities to obtain their load paths. - if Gem::Specification.method_defined? :full_require_paths - loaded_gem_paths = Gem.loaded_specs.map {|_, s| s.full_require_paths } - loaded_gem_paths.flatten - else - $LOAD_PATH.select do |p| - Bundler.rubygems.gem_path.any? {|gp| p =~ /^#{Regexp.escape(gp)}/ } - end - end - end - - def load_plugins - Gem.load_plugins if Gem.respond_to?(:load_plugins) - end - - def load_plugin_files(files) - Gem.load_plugin_files(files) if Gem.respond_to?(:load_plugin_files) - end - - def ui=(obj) - Gem::DefaultUserInteraction.ui = obj - end - - def ext_lock - EXT_LOCK - end - - def fetch_specs(all, pre, &blk) - require "rubygems/spec_fetcher" - specs = Gem::SpecFetcher.new.list(all, pre) - specs.each { yield } if block_given? - specs - end - - def fetch_prerelease_specs - fetch_specs(false, true) - rescue Gem::RemoteFetcher::FetchError - {} # if we can't download them, there aren't any - end - - # TODO: This is for older versions of RubyGems... should we support the - # X-Gemfile-Source header on these old versions? - # Maybe the newer implementation will work on older RubyGems? - # It seems difficult to keep this implementation and still send the header. - def fetch_all_remote_specs(remote) - old_sources = Bundler.rubygems.sources - Bundler.rubygems.sources = [remote.uri.to_s] - # Fetch all specs, minus prerelease specs - spec_list = fetch_specs(true, false) - # Then fetch the prerelease specs - fetch_prerelease_specs.each {|k, v| spec_list[k].concat(v) } - - spec_list.values.first - ensure - Bundler.rubygems.sources = old_sources - end - - def with_build_args(args) - ext_lock.synchronize do - old_args = build_args - begin - self.build_args = args - yield - ensure - self.build_args = old_args - end - end - end - - def install_with_build_args(args) - with_build_args(args) { yield } - end - - def gem_from_path(path, policy = nil) - require "rubygems/format" - Gem::Format.from_file_by_path(path, policy) - end - - def spec_from_gem(path, policy = nil) - require "rubygems/security" - require "bundler/psyched_yaml" - gem_from_path(path, security_policies[policy]).spec - rescue Gem::Package::FormatError - raise GemspecError, "Could not read gem at #{path}. It may be corrupted." - rescue Exception, Gem::Exception, Gem::Security::Exception => e - if e.is_a?(Gem::Security::Exception) || - e.message =~ /unknown trust policy|unsigned gem/i || - e.message =~ /couldn't verify (meta)?data signature/i - raise SecurityError, - "The gem #{File.basename(path, ".gem")} can't be installed because " \ - "the security policy didn't allow it, with the message: #{e.message}" - else - raise e - end - end - - def build(spec, skip_validation = false) - require "rubygems/builder" - Gem::Builder.new(spec).build - end - - def build_gem(gem_dir, spec) - build(spec) - end - - def download_gem(spec, uri, path) - uri = Bundler.settings.mirror_for(uri) - fetcher = Gem::RemoteFetcher.new(configuration[:http_proxy]) - Bundler::Retry.new("download gem from #{uri}").attempts do - fetcher.download(spec, uri, path) - end - end - - def security_policy_keys - %w[High Medium Low AlmostNo No].map {|level| "#{level}Security" } - end - - def security_policies - @security_policies ||= begin - require "rubygems/security" - Gem::Security::Policies - rescue LoadError, NameError - {} - end - end - - def reverse_rubygems_kernel_mixin - # Disable rubygems' gem activation system - kernel = (class << ::Kernel; self; end) - [kernel, ::Kernel].each do |k| - if k.private_method_defined?(:gem_original_require) - redefine_method(k, :require, k.instance_method(:gem_original_require)) - end - end - end - - def binstubs_call_gem? - true - end - - def stubs_provide_full_functionality? - false - end - - def replace_gem(specs, specs_by_name) - reverse_rubygems_kernel_mixin - - executables = nil - - kernel = (class << ::Kernel; self; end) - [kernel, ::Kernel].each do |kernel_class| - redefine_method(kernel_class, :gem) do |dep, *reqs| - executables ||= specs.map(&:executables).flatten if ::Bundler.rubygems.binstubs_call_gem? - if executables && executables.include?(File.basename(caller.first.split(":").first)) - break - end - - reqs.pop if reqs.last.is_a?(Hash) - - unless dep.respond_to?(:name) && dep.respond_to?(:requirement) - dep = Gem::Dependency.new(dep, reqs) - end - - if spec = specs_by_name[dep.name] - return true if dep.matches_spec?(spec) - end - - message = if spec.nil? - "#{dep.name} is not part of the bundle." \ - " Add it to your #{Bundler.default_gemfile.basename}." - else - "can't activate #{dep}, already activated #{spec.full_name}. " \ - "Make sure all dependencies are added to Gemfile." - end - - e = Gem::LoadError.new(message) - e.name = dep.name - if e.respond_to?(:requirement=) - e.requirement = dep.requirement - elsif e.respond_to?(:version_requirement=) - e.version_requirement = dep.requirement - end - raise e - end - - # backwards compatibility shim, see https://github.com/bundler/bundler/issues/5102 - kernel_class.send(:public, :gem) if Bundler.feature_flag.setup_makes_kernel_gem_public? - end - end - - def stub_source_index(specs) - Gem::SourceIndex.send(:alias_method, :old_initialize, :initialize) - redefine_method(Gem::SourceIndex, :initialize) do |*args| - @gems = {} - # You're looking at this thinking: Oh! This is how I make those - # rubygems deprecations go away! - # - # You'd be correct BUT using of this method in production code - # must be approved by the rubygems team itself! - # - # This is your warning. If you use this and don't have approval - # we can't protect you. - # - Deprecate.skip_during do - self.spec_dirs = *args - add_specs(*specs) - end - end - end - - # Used to make bin stubs that are not created by bundler work - # under bundler. The new Gem.bin_path only considers gems in - # +specs+ - def replace_bin_path(specs, specs_by_name) - gem_class = (class << Gem; self; end) - - redefine_method(gem_class, :find_spec_for_exe) do |gem_name, *args| - exec_name = args.first - - spec_with_name = specs_by_name[gem_name] - spec = if exec_name - if spec_with_name && spec_with_name.executables.include?(exec_name) - spec_with_name - else - specs.find {|s| s.executables.include?(exec_name) } - end - else - spec_with_name - end - - unless spec - message = "can't find executable #{exec_name} for gem #{gem_name}" - if !exec_name || spec_with_name.nil? - message += ". #{gem_name} is not currently included in the bundle, " \ - "perhaps you meant to add it to your #{Bundler.default_gemfile.basename}?" - end - raise Gem::Exception, message - end - - raise Gem::Exception, "no default executable for #{spec.full_name}" unless exec_name ||= spec.default_executable - - unless spec.name == gem_name - Bundler::SharedHelpers.major_deprecation 2, - "Bundler is using a binstub that was created for a different gem (#{spec.name}).\n" \ - "You should run `bundle binstub #{gem_name}` " \ - "to work around a system/bundle conflict." - end - spec - end - - redefine_method(gem_class, :activate_bin_path) do |name, *args| - exec_name = args.first - return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" - - # Copy of Rubygems activate_bin_path impl - requirement = args.last - spec = find_spec_for_exe name, exec_name, [requirement] - - gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) - gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) - File.exist?(gem_bin) ? gem_bin : gem_from_path_bin - end - - redefine_method(gem_class, :bin_path) do |name, *args| - exec_name = args.first - return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" - - spec = find_spec_for_exe(name, *args) - exec_name ||= spec.default_executable - - gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) - gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) - File.exist?(gem_bin) ? gem_bin : gem_from_path_bin - end - end - - # Because Bundler has a static view of what specs are available, - # we don't #refresh, so stub it out. - def replace_refresh - gem_class = (class << Gem; self; end) - redefine_method(gem_class, :refresh) {} - end - - # Replace or hook into RubyGems to provide a bundlerized view - # of the world. - def replace_entrypoints(specs) - specs_by_name = specs.reduce({}) do |h, s| - h[s.name] = s - h - end - - replace_gem(specs, specs_by_name) - stub_rubygems(specs) - replace_bin_path(specs, specs_by_name) - replace_refresh - - Gem.clear_paths - end - - # This backports the correct segment generation code from RubyGems 1.4+ - # by monkeypatching it into the method in RubyGems 1.3.6 and 1.3.7. - def backport_segment_generation - redefine_method(Gem::Version, :segments) do - @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s| - /^\d+$/ =~ s ? s.to_i : s - end - end - end - - # This backport fixes the marshaling of @segments. - def backport_yaml_initialize - redefine_method(Gem::Version, :yaml_initialize) do |_, map| - @version = map["version"] - @segments = nil - @hash = nil - end - end - - # This backports base_dir which replaces installation path - # RubyGems 1.8+ - def backport_base_dir - redefine_method(Gem::Specification, :base_dir) do - return Gem.dir unless loaded_from - File.dirname File.dirname loaded_from - end - end - - def backport_cache_file - redefine_method(Gem::Specification, :cache_dir) do - @cache_dir ||= File.join base_dir, "cache" - end - - redefine_method(Gem::Specification, :cache_file) do - @cache_file ||= File.join cache_dir, "#{full_name}.gem" - end - end - - def backport_spec_file - redefine_method(Gem::Specification, :spec_dir) do - @spec_dir ||= File.join base_dir, "specifications" - end - - redefine_method(Gem::Specification, :spec_file) do - @spec_file ||= File.join spec_dir, "#{full_name}.gemspec" - end - end - - def undo_replacements - @replaced_methods.each do |(sym, klass), method| - redefine_method(klass, sym, method) - end - if Binding.public_method_defined?(:source_location) - post_reset_hooks.reject! {|proc| proc.binding.source_location[0] == __FILE__ } - else - post_reset_hooks.reject! {|proc| proc.binding.eval("__FILE__") == __FILE__ } - end - @replaced_methods.clear - end - - def redefine_method(klass, method, unbound_method = nil, &block) - visibility = method_visibility(klass, method) - begin - if (instance_method = klass.instance_method(method)) && method != :initialize - # doing this to ensure we also get private methods - klass.send(:remove_method, method) - end - rescue NameError - # method isn't defined - nil - end - @replaced_methods[[method, klass]] = instance_method - if unbound_method - klass.send(:define_method, method, unbound_method) - klass.send(visibility, method) - elsif block - klass.send(:define_method, method, &block) - klass.send(visibility, method) - end - end - - def method_visibility(klass, method) - if klass.private_method_defined?(method) - :private - elsif klass.protected_method_defined?(method) - :protected - else - :public - end - end - - # RubyGems 1.4 through 1.6 - class Legacy < RubygemsIntegration - def initialize - super - backport_base_dir - backport_cache_file - backport_spec_file - backport_yaml_initialize - end - - def stub_rubygems(specs) - # RubyGems versions lower than 1.7 use SourceIndex#from_gems_in - source_index_class = (class << Gem::SourceIndex; self; end) - redefine_method(source_index_class, :from_gems_in) do |*args| - Gem::SourceIndex.new.tap do |source_index| - source_index.spec_dirs = *args - source_index.add_specs(*specs) - end - end - end - - def all_specs - Gem.source_index.gems.values - end - - def find_name(name) - Gem.source_index.find_name(name) - end - - def validate(spec) - # These versions of RubyGems always validate in "packaging" mode, - # which is too strict for the kinds of checks we care about. As a - # result, validation is disabled on versions of RubyGems below 1.7. - end - - def post_reset_hooks - [] - end - - def reset - end - end - - # RubyGems versions 1.3.6 and 1.3.7 - class Ancient < Legacy - def initialize - super - backport_segment_generation - end - end - - # RubyGems 1.7 - class Transitional < Legacy - def stub_rubygems(specs) - stub_source_index(specs) - end - - def validate(spec) - # Missing summary is downgraded to a warning in later versions, - # so we set it to an empty string to prevent an exception here. - spec.summary ||= "" - RubygemsIntegration.instance_method(:validate).bind(self).call(spec) - end - end - - # RubyGems 1.8.5-1.8.19 - class Modern < RubygemsIntegration - def stub_rubygems(specs) - Gem::Specification.all = specs - - Gem.post_reset do - Gem::Specification.all = specs - end - - stub_source_index(specs) - end - - def all_specs - Gem::Specification.to_a - end - - def find_name(name) - Gem::Specification.find_all_by_name name - end - end - - # RubyGems 1.8.0 to 1.8.4 - class AlmostModern < Modern - # RubyGems [>= 1.8.0, < 1.8.5] has a bug that changes Gem.dir whenever - # you call Gem::Installer#install with an :install_dir set. We have to - # change it back for our sudo mode to work. - def preserve_paths - old_dir = gem_dir - old_path = gem_path - yield - Gem.use_paths(old_dir, old_path) - end - end - - # RubyGems 1.8.20+ - class MoreModern < Modern - # RubyGems 1.8.20 and adds the skip_validation parameter, so that's - # when we start passing it through. - def build(spec, skip_validation = false) - require "rubygems/builder" - Gem::Builder.new(spec).build(skip_validation) - end - end - - # RubyGems 2.0 - class Future < RubygemsIntegration - def stub_rubygems(specs) - Gem::Specification.all = specs - - Gem.post_reset do - Gem::Specification.all = specs - end - - redefine_method((class << Gem; self; end), :finish_resolve) do |*| - [] - end - end - - def all_specs - Gem::Specification.to_a - end - - def find_name(name) - Gem::Specification.find_all_by_name name - end - - def fetch_specs(source, remote, name) - path = source + "#{name}.#{Gem.marshal_version}.gz" - fetcher = gem_remote_fetcher - fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri - string = fetcher.fetch_path(path) - Bundler.load_marshal(string) - rescue Gem::RemoteFetcher::FetchError => e - # it's okay for prerelease to fail - raise e unless name == "prerelease_specs" - end - - def fetch_all_remote_specs(remote) - source = remote.uri.is_a?(URI) ? remote.uri : URI.parse(source.to_s) - - specs = fetch_specs(source, remote, "specs") - pres = fetch_specs(source, remote, "prerelease_specs") || [] - - specs.concat(pres) - end - - def download_gem(spec, uri, path) - uri = Bundler.settings.mirror_for(uri) - fetcher = gem_remote_fetcher - fetcher.headers = { "X-Gemfile-Source" => spec.remote.original_uri.to_s } if spec.remote.original_uri - Bundler::Retry.new("download gem from #{uri}").attempts do - fetcher.download(spec, uri, path) - end - end - - def gem_remote_fetcher - require "resolv" - proxy = configuration[:http_proxy] - dns = Resolv::DNS.new - Bundler::GemRemoteFetcher.new(proxy, dns) - end - - def gem_from_path(path, policy = nil) - require "rubygems/package" - p = Gem::Package.new(path) - p.security_policy = policy if policy - p - end - - def build(spec, skip_validation = false) - require "rubygems/package" - Gem::Package.build(spec, skip_validation) - end - - def repository_subdirectories - Gem::REPOSITORY_SUBDIRECTORIES - end - - def install_with_build_args(args) - yield - end - - def path_separator - Gem.path_separator - end - end - - # RubyGems 2.1.0 - class MoreFuture < Future - def initialize - super - backport_ext_builder_monitor - end - - def all_specs - require "bundler/remote_specification" - Gem::Specification.stubs.map do |stub| - StubSpecification.from_stub(stub) - end - end - - def backport_ext_builder_monitor - # So we can avoid requiring "rubygems/ext" in its entirety - Gem.module_eval <<-RB, __FILE__, __LINE__ + 1 - module Ext - end - RB - - require "rubygems/ext/builder" - - Gem::Ext::Builder.class_eval do - unless const_defined?(:CHDIR_MONITOR) - const_set(:CHDIR_MONITOR, EXT_LOCK) - end - - remove_const(:CHDIR_MUTEX) if const_defined?(:CHDIR_MUTEX) - const_set(:CHDIR_MUTEX, const_get(:CHDIR_MONITOR)) - end - end - - if Gem::Specification.respond_to?(:stubs_for) - def find_name(name) - Gem::Specification.stubs_for(name).map(&:to_spec) - end - else - def find_name(name) - Gem::Specification.stubs.find_all do |spec| - spec.name == name - end.map(&:to_spec) - end - end - - def use_gemdeps(gemfile) - ENV["BUNDLE_GEMFILE"] ||= File.expand_path(gemfile) - require "bundler/gemdeps" - runtime = Bundler.setup - Bundler.ui = nil - activated_spec_names = runtime.requested_specs.map(&:to_spec).sort_by(&:name) - [Gemdeps.new(runtime), activated_spec_names] - end - - if provides?(">= 2.5.2") - # RubyGems-generated binstubs call Kernel#gem - def binstubs_call_gem? - false - end - - # only 2.5.2+ has all of the stub methods we want to use, and since this - # is a performance optimization _only_, - # we'll restrict ourselves to the most - # recent RG versions instead of all versions that have stubs - def stubs_provide_full_functionality? - true - end - end - end - end - - def self.rubygems - @rubygems ||= if RubygemsIntegration.provides?(">= 2.1.0") - RubygemsIntegration::MoreFuture.new - elsif RubygemsIntegration.provides?(">= 1.99.99") - RubygemsIntegration::Future.new - elsif RubygemsIntegration.provides?(">= 1.8.20") - RubygemsIntegration::MoreModern.new - elsif RubygemsIntegration.provides?(">= 1.8.5") - RubygemsIntegration::Modern.new - elsif RubygemsIntegration.provides?(">= 1.8.0") - RubygemsIntegration::AlmostModern.new - elsif RubygemsIntegration.provides?(">= 1.7.0") - RubygemsIntegration::Transitional.new - elsif RubygemsIntegration.provides?(">= 1.4.0") - RubygemsIntegration::Legacy.new - else # RubyGems 1.3.6 and 1.3.7 - RubygemsIntegration::Ancient.new - end - end -end diff --git a/lib/ruby/stdlib/bundler/runtime.rb b/lib/ruby/stdlib/bundler/runtime.rb deleted file mode 100644 index 762e7b3ec66..00000000000 --- a/lib/ruby/stdlib/bundler/runtime.rb +++ /dev/null @@ -1,322 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Runtime - include SharedHelpers - - def initialize(root, definition) - @root = root - @definition = definition - end - - def setup(*groups) - @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle? - - groups.map!(&:to_sym) - - # Has to happen first - clean_load_path - - specs = groups.any? ? @definition.specs_for(groups) : requested_specs - - SharedHelpers.set_bundle_environment - Bundler.rubygems.replace_entrypoints(specs) - - # Activate the specs - load_paths = specs.map do |spec| - unless spec.loaded_from - raise GemNotFound, "#{spec.full_name} is missing. Run `bundle install` to get it." - end - - check_for_activated_spec!(spec) - - Bundler.rubygems.mark_loaded(spec) - spec.load_paths.reject {|path| $LOAD_PATH.include?(path) } - end.reverse.flatten - - # See Gem::Specification#add_self_to_load_path (since RubyGems 1.8) - if insert_index = Bundler.rubygems.load_path_insert_index - # Gem directories must come after -I and ENV['RUBYLIB'] - $LOAD_PATH.insert(insert_index, *load_paths) - else - # We are probably testing in core, -I and RUBYLIB don't apply - $LOAD_PATH.unshift(*load_paths) - end - - setup_manpath - - lock(:preserve_unknown_sections => true) - - self - end - - REQUIRE_ERRORS = [ - /^no such file to load -- (.+)$/i, - /^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i, - /^Missing API definition file in (.+)$/i, - /^cannot load such file -- (.+)$/i, - /^dlopen\([^)]*\): Library not loaded: (.+)$/i, - ].freeze - - def require(*groups) - groups.map!(&:to_sym) - groups = [:default] if groups.empty? - - @definition.dependencies.each do |dep| - # Skip the dependency if it is not in any of the requested groups, or - # not for the current platform, or doesn't match the gem constraints. - next unless (dep.groups & groups).any? && dep.should_include? - - required_file = nil - - begin - # Loop through all the specified autorequires for the - # dependency. If there are none, use the dependency's name - # as the autorequire. - Array(dep.autorequire || dep.name).each do |file| - # Allow `require: true` as an alias for `require: ` - file = dep.name if file == true - required_file = file - begin - Kernel.require file - rescue RuntimeError => e - raise e if e.is_a?(LoadError) # we handle this a little later - raise Bundler::GemRequireError.new e, - "There was an error while trying to load the gem '#{file}'." - end - end - rescue LoadError => e - REQUIRE_ERRORS.find {|r| r =~ e.message } - raise if dep.autorequire || $1 != required_file - - if dep.autorequire.nil? && dep.name.include?("-") - begin - namespaced_file = dep.name.tr("-", "/") - Kernel.require namespaced_file - rescue LoadError => e - REQUIRE_ERRORS.find {|r| r =~ e.message } - raise if $1 != namespaced_file - end - end - end - end - end - - def self.definition_method(meth) - define_method(meth) do - raise ArgumentError, "no definition when calling Runtime##{meth}" unless @definition - @definition.send(meth) - end - end - private_class_method :definition_method - - definition_method :requested_specs - definition_method :specs - definition_method :dependencies - definition_method :current_dependencies - definition_method :requires - - def lock(opts = {}) - return if @definition.nothing_changed? && !@definition.unlocking? - @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections]) - end - - alias_method :gems, :specs - - def cache(custom_path = nil) - cache_path = Bundler.app_cache(custom_path) - SharedHelpers.filesystem_access(cache_path) do |p| - FileUtils.mkdir_p(p) - end unless File.exist?(cache_path) - - Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}" - - specs_to_cache = Bundler.settings[:cache_all_platforms] ? @definition.resolve.materialized_for_all_platforms : specs - specs_to_cache.each do |spec| - next if spec.name == "bundler" - next if spec.source.is_a?(Source::Gemspec) - spec.source.send(:fetch_gem, spec) if Bundler.settings[:cache_all_platforms] && spec.source.respond_to?(:fetch_gem, true) - spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache) - end - - Dir[cache_path.join("*/.git")].each do |git_dir| - FileUtils.rm_rf(git_dir) - FileUtils.touch(File.expand_path("../.bundlecache", git_dir)) - end - - prune_cache(cache_path) unless Bundler.settings[:no_prune] - end - - def prune_cache(cache_path) - SharedHelpers.filesystem_access(cache_path) do |p| - FileUtils.mkdir_p(p) - end unless File.exist?(cache_path) - resolve = @definition.resolve - prune_gem_cache(resolve, cache_path) - prune_git_and_path_cache(resolve, cache_path) - end - - def clean(dry_run = false) - gem_bins = Dir["#{Gem.dir}/bin/*"] - git_dirs = Dir["#{Gem.dir}/bundler/gems/*"] - git_cache_dirs = Dir["#{Gem.dir}/cache/bundler/git/*"] - gem_dirs = Dir["#{Gem.dir}/gems/*"] - gem_files = Dir["#{Gem.dir}/cache/*.gem"] - gemspec_files = Dir["#{Gem.dir}/specifications/*.gemspec"] - extension_dirs = Dir["#{Gem.dir}/extensions/*/*/*"] - spec_gem_paths = [] - # need to keep git sources around - spec_git_paths = @definition.spec_git_paths - spec_git_cache_dirs = [] - spec_gem_executables = [] - spec_cache_paths = [] - spec_gemspec_paths = [] - spec_extension_paths = [] - specs.each do |spec| - spec_gem_paths << spec.full_gem_path - # need to check here in case gems are nested like for the rails git repo - md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path) - spec_git_paths << md[1] if md - spec_gem_executables << spec.executables.collect do |executable| - e = "#{Bundler.rubygems.gem_bindir}/#{executable}" - [e, "#{e}.bat"] - end - spec_cache_paths << spec.cache_file - spec_gemspec_paths << spec.spec_file - spec_extension_paths << spec.extension_dir if spec.respond_to?(:extension_dir) - spec_git_cache_dirs << spec.source.cache_path.to_s if spec.source.is_a?(Bundler::Source::Git) - end - spec_gem_paths.uniq! - spec_gem_executables.flatten! - - stale_gem_bins = gem_bins - spec_gem_executables - stale_git_dirs = git_dirs - spec_git_paths - ["#{Gem.dir}/bundler/gems/extensions"] - stale_git_cache_dirs = git_cache_dirs - spec_git_cache_dirs - stale_gem_dirs = gem_dirs - spec_gem_paths - stale_gem_files = gem_files - spec_cache_paths - stale_gemspec_files = gemspec_files - spec_gemspec_paths - stale_extension_dirs = extension_dirs - spec_extension_paths - - removed_stale_gem_dirs = stale_gem_dirs.collect {|dir| remove_dir(dir, dry_run) } - removed_stale_git_dirs = stale_git_dirs.collect {|dir| remove_dir(dir, dry_run) } - output = removed_stale_gem_dirs + removed_stale_git_dirs - - unless dry_run - stale_files = stale_gem_bins + stale_gem_files + stale_gemspec_files - stale_files.each do |file| - SharedHelpers.filesystem_access(File.dirname(file)) do |_p| - FileUtils.rm(file) if File.exist?(file) - end - end - - stale_dirs = stale_git_cache_dirs + stale_extension_dirs - stale_dirs.each do |stale_dir| - SharedHelpers.filesystem_access(stale_dir) do |dir| - FileUtils.rm_rf(dir) if File.exist?(dir) - end - end - end - - output - end - - private - - def prune_gem_cache(resolve, cache_path) - cached = Dir["#{cache_path}/*.gem"] - - cached = cached.delete_if do |path| - spec = Bundler.rubygems.spec_from_gem path - - resolve.any? do |s| - s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git) - end - end - - if cached.any? - Bundler.ui.info "Removing outdated .gem files from #{Bundler.settings.app_cache_path}" - - cached.each do |path| - Bundler.ui.info " * #{File.basename(path)}" - File.delete(path) - end - end - end - - def prune_git_and_path_cache(resolve, cache_path) - cached = Dir["#{cache_path}/*/.bundlecache"] - - cached = cached.delete_if do |path| - name = File.basename(File.dirname(path)) - - resolve.any? do |s| - source = s.source - source.respond_to?(:app_cache_dirname) && source.app_cache_dirname == name - end - end - - if cached.any? - Bundler.ui.info "Removing outdated git and path gems from #{Bundler.settings.app_cache_path}" - - cached.each do |path| - path = File.dirname(path) - Bundler.ui.info " * #{File.basename(path)}" - FileUtils.rm_rf(path) - end - end - end - - def setup_manpath - # Add man/ subdirectories from activated bundles to MANPATH for man(1) - manuals = $LOAD_PATH.map do |path| - man_subdir = path.sub(/lib$/, "man") - man_subdir unless Dir[man_subdir + "/man?/"].empty? - end.compact - - return if manuals.empty? - Bundler::SharedHelpers.set_env "MANPATH", manuals.concat( - ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) - ).uniq.join(File::PATH_SEPARATOR) - end - - def remove_dir(dir, dry_run) - full_name = Pathname.new(dir).basename.to_s - - parts = full_name.split("-") - name = parts[0..-2].join("-") - version = parts.last - output = "#{name} (#{version})" - - if dry_run - Bundler.ui.info "Would have removed #{output}" - else - Bundler.ui.info "Removing #{output}" - FileUtils.rm_rf(dir) - end - - output - end - - def check_for_activated_spec!(spec) - return unless activated_spec = Bundler.rubygems.loaded_specs(spec.name) - return if activated_spec.version == spec.version - - suggestion = if Bundler.rubygems.spec_default_gem?(activated_spec) - "Since #{spec.name} is a default gem, you can either remove your dependency on it" \ - " or try updating to a newer version of bundler that supports #{spec.name} as a default gem." - else - "Prepending `bundle exec` to your command may solve this." - end - - e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \ - "but your Gemfile requires #{spec.name} #{spec.version}. #{suggestion}" - e.name = spec.name - if e.respond_to?(:requirement=) - e.requirement = Gem::Requirement.new(spec.version.to_s) - else - e.version_requirement = Gem::Requirement.new(spec.version.to_s) - end - raise e - end - end -end diff --git a/lib/ruby/stdlib/bundler/settings.rb b/lib/ruby/stdlib/bundler/settings.rb deleted file mode 100644 index fe68d510ffa..00000000000 --- a/lib/ruby/stdlib/bundler/settings.rb +++ /dev/null @@ -1,463 +0,0 @@ -# frozen_string_literal: true - -require "uri" - -module Bundler - class Settings - autoload :Mirror, "bundler/mirror" - autoload :Mirrors, "bundler/mirror" - autoload :Validator, "bundler/settings/validator" - - BOOL_KEYS = %w[ - allow_bundler_dependency_conflicts - allow_deployment_source_credential_changes - allow_offline_install - auto_clean_without_path - auto_install - auto_config_jobs - cache_all - cache_all_platforms - cache_command_is_package - console_command - default_install_uses_path - deployment - deployment_means_frozen - disable_checksum_validation - disable_exec_load - disable_local_branch_check - disable_multisource - disable_platform_warnings - disable_shared_gems - disable_version_check - error_on_stderr - force_ruby_platform - forget_cli_options - frozen - gem.coc - gem.mit - global_path_appends_ruby_scope - global_gem_cache - ignore_messages - init_gems_rb - list_command - lockfile_uses_separate_rubygems_sources - major_deprecations - no_install - no_prune - only_update_to_newer_versions - path_relative_to_cwd - path.system - plugins - prefer_gems_rb - print_only_version_number - setup_makes_kernel_gem_public - silence_root_warning - skip_default_git_sources - specific_platform - suppress_install_using_messages - unlock_source_unlocks_spec - update_requires_all_flag - use_gem_version_promoter_for_major_updates - viz_command - ].freeze - - NUMBER_KEYS = %w[ - jobs - redirect - retry - ssl_verify_mode - timeout - ].freeze - - ARRAY_KEYS = %w[ - with - without - ].freeze - - DEFAULT_CONFIG = { - :disable_version_check => true, - :redirect => 5, - :retry => 3, - :timeout => 10, - }.freeze - - def initialize(root = nil) - @root = root - @local_config = load_config(local_config_file) - @global_config = load_config(global_config_file) - @temporary = {} - end - - def [](name) - key = key_for(name) - value = @temporary.fetch(key) do - @local_config.fetch(key) do - ENV.fetch(key) do - @global_config.fetch(key) do - DEFAULT_CONFIG.fetch(name) do - nil - end end end end end - - converted_value(value, name) - end - - def set_command_option(key, value) - if Bundler.feature_flag.forget_cli_options? - temporary(key => value) - value - else - command = if value.nil? - "bundle config --delete #{key}" - else - "bundle config #{key} #{Array(value).join(":")}" - end - - Bundler::SharedHelpers.major_deprecation 2,\ - "flags passed to commands " \ - "will no longer be automatically remembered. Instead please set flags " \ - "you want remembered between commands using `bundle config " \ - " `, i.e. `#{command}`" - - set_local(key, value) - end - end - - def set_command_option_if_given(key, value) - return if value.nil? - set_command_option(key, value) - end - - def set_local(key, value) - local_config_file || raise(GemfileNotFound, "Could not locate Gemfile") - - set_key(key, value, @local_config, local_config_file) - end - - def temporary(update) - existing = Hash[update.map {|k, _| [k, @temporary[key_for(k)]] }] - update.each do |k, v| - set_key(k, v, @temporary, nil) - end - return unless block_given? - begin - yield - ensure - existing.each {|k, v| set_key(k, v, @temporary, nil) } - end - end - - def set_global(key, value) - set_key(key, value, @global_config, global_config_file) - end - - def all - env_keys = ENV.keys.grep(/\ABUNDLE_.+/) - - keys = @temporary.keys | @global_config.keys | @local_config.keys | env_keys - - keys.map do |key| - key.sub(/^BUNDLE_/, "").gsub(/__/, ".").downcase - end - end - - def local_overrides - repos = {} - all.each do |k| - repos[$'] = self[k] if k =~ /^local\./ - end - repos - end - - def mirror_for(uri) - uri = URI(uri.to_s) unless uri.is_a?(URI) - gem_mirrors.for(uri.to_s).uri - end - - def credentials_for(uri) - self[uri.to_s] || self[uri.host] - end - - def gem_mirrors - all.inject(Mirrors.new) do |mirrors, k| - mirrors.parse(k, self[k]) if k.start_with?("mirror.") - mirrors - end - end - - def locations(key) - key = key_for(key) - locations = {} - locations[:temporary] = @temporary[key] if @temporary.key?(key) - locations[:local] = @local_config[key] if @local_config.key?(key) - locations[:env] = ENV[key] if ENV[key] - locations[:global] = @global_config[key] if @global_config.key?(key) - locations[:default] = DEFAULT_CONFIG[key] if DEFAULT_CONFIG.key?(key) - locations - end - - def pretty_values_for(exposed_key) - key = key_for(exposed_key) - - locations = [] - - if @temporary.key?(key) - locations << "Set for the current command: #{converted_value(@temporary[key], exposed_key).inspect}" - end - - if @local_config.key?(key) - locations << "Set for your local app (#{local_config_file}): #{converted_value(@local_config[key], exposed_key).inspect}" - end - - if value = ENV[key] - locations << "Set via #{key}: #{converted_value(value, exposed_key).inspect}" - end - - if @global_config.key?(key) - locations << "Set for the current user (#{global_config_file}): #{converted_value(@global_config[key], exposed_key).inspect}" - end - - return ["You have not configured a value for `#{exposed_key}`"] if locations.empty? - locations - end - - # for legacy reasons, in Bundler 1, the ruby scope isnt appended when the setting comes from ENV or the global config, - # nor do we respect :disable_shared_gems - def path - key = key_for(:path) - path = ENV[key] || @global_config[key] - if path && !@temporary.key?(key) && !@local_config.key?(key) - return Path.new(path, Bundler.feature_flag.global_path_appends_ruby_scope?, false, false) - end - - system_path = self["path.system"] || (self[:disable_shared_gems] == false) - Path.new(self[:path], true, system_path, Bundler.feature_flag.default_install_uses_path?) - end - - Path = Struct.new(:explicit_path, :append_ruby_scope, :system_path, :default_install_uses_path) do - def path - path = base_path - path = File.join(path, Bundler.ruby_scope) if append_ruby_scope && !use_system_gems? - path - end - - def use_system_gems? - return true if system_path - return false if explicit_path - !default_install_uses_path - end - - def base_path - path = explicit_path - path ||= ".bundle" unless use_system_gems? - path ||= Bundler.rubygems.gem_dir - path - end - - def base_path_relative_to_pwd - base_path = Pathname.new(self.base_path) - expanded_base_path = base_path.expand_path(Bundler.root) - relative_path = expanded_base_path.relative_path_from(Pathname.pwd) - if relative_path.to_s.start_with?("..") - relative_path = base_path if base_path.absolute? - else - relative_path = Pathname.new(File.join(".", relative_path)) - end - relative_path - rescue ArgumentError - expanded_base_path - end - - def validate! - return unless explicit_path && system_path - path = Bundler.settings.pretty_values_for(:path) - path.unshift(nil, "path:") unless path.empty? - system_path = Bundler.settings.pretty_values_for("path.system") - system_path.unshift(nil, "path.system:") unless system_path.empty? - disable_shared_gems = Bundler.settings.pretty_values_for(:disable_shared_gems) - disable_shared_gems.unshift(nil, "disable_shared_gems:") unless disable_shared_gems.empty? - raise InvalidOption, - "Using a custom path while using system gems is unsupported.\n#{path.join("\n")}\n#{system_path.join("\n")}\n#{disable_shared_gems.join("\n")}" - end - end - - def allow_sudo? - key = key_for(:path) - path_configured = @temporary.key?(key) || @local_config.key?(key) - !path_configured - end - - def ignore_config? - ENV["BUNDLE_IGNORE_CONFIG"] - end - - def app_cache_path - @app_cache_path ||= self[:cache_path] || "vendor/cache" - end - - def validate! - all.each do |raw_key| - [@local_config, ENV, @global_config].each do |settings| - value = converted_value(settings[key_for(raw_key)], raw_key) - Validator.validate!(raw_key, value, settings.to_hash.dup) - end - end - end - - def key_for(key) - key = Settings.normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key - key = key.to_s.gsub(".", "__").upcase - "BUNDLE_#{key}" - end - - private - - def parent_setting_for(name) - split_specific_setting_for(name)[0] - end - - def specific_gem_for(name) - split_specific_setting_for(name)[1] - end - - def split_specific_setting_for(name) - name.split(".") - end - - def is_bool(name) - BOOL_KEYS.include?(name.to_s) || BOOL_KEYS.include?(parent_setting_for(name.to_s)) - end - - def to_bool(value) - case value - when nil, /\A(false|f|no|n|0|)\z/i, false - false - else - true - end - end - - def is_num(key) - NUMBER_KEYS.include?(key.to_s) - end - - def is_array(key) - ARRAY_KEYS.include?(key.to_s) - end - - def to_array(value) - return [] unless value - value.split(":").map(&:to_sym) - end - - def array_to_s(array) - array = Array(array) - return nil if array.empty? - array.join(":").tr(" ", ":") - end - - def set_key(raw_key, value, hash, file) - raw_key = raw_key.to_s - value = array_to_s(value) if is_array(raw_key) - - key = key_for(raw_key) - - return if hash[key] == value - - hash[key] = value - hash.delete(key) if value.nil? - - Validator.validate!(raw_key, converted_value(value, raw_key), hash) - - return unless file - SharedHelpers.filesystem_access(file) do |p| - FileUtils.mkdir_p(p.dirname) - require "bundler/yaml_serializer" - p.open("w") {|f| f.write(YAMLSerializer.dump(hash)) } - end - end - - def converted_value(value, key) - if is_array(key) - to_array(value) - elsif value.nil? - nil - elsif is_bool(key) || value == "false" - to_bool(value) - elsif is_num(key) - value.to_i - else - value.to_s - end - end - - def global_config_file - if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty? - Pathname.new(ENV["BUNDLE_CONFIG"]) - else - begin - Bundler.user_bundle_path("config") - rescue PermissionError, GenericSystemCallError - nil - end - end - end - - def local_config_file - Pathname.new(@root).join("config") if @root - end - - CONFIG_REGEX = %r{ # rubocop:disable Style/RegexpLiteral - ^ - (BUNDLE_.+):\s # the key - (?: !\s)? # optional exclamation mark found with ruby 1.9.3 - (['"]?) # optional opening quote - (.* # contents of the value - (?: # optionally, up until the next key - (\n(?!BUNDLE).+)* - ) - ) - \2 # matching closing quote - $ - }xo - - def load_config(config_file) - return {} if !config_file || ignore_config? - SharedHelpers.filesystem_access(config_file, :read) do |file| - valid_file = file.exist? && !file.size.zero? - return {} unless valid_file - require "bundler/yaml_serializer" - YAMLSerializer.load file.read - end - end - - PER_URI_OPTIONS = %w[ - fallback_timeout - ].freeze - - NORMALIZE_URI_OPTIONS_PATTERN = - / - \A - (\w+\.)? # optional prefix key - (https?.*?) # URI - (\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key - \z - /ix - - # TODO: duplicates Rubygems#normalize_uri - # TODO: is this the correct place to validate mirror URIs? - def self.normalize_uri(uri) - uri = uri.to_s - if uri =~ NORMALIZE_URI_OPTIONS_PATTERN - prefix = $1 - uri = $2 - suffix = $3 - end - uri = "#{uri}/" unless uri.end_with?("/") - uri = URI(uri) - unless uri.absolute? - raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri) - end - "#{prefix}#{uri}#{suffix}" - end - end -end diff --git a/lib/ruby/stdlib/bundler/settings/validator.rb b/lib/ruby/stdlib/bundler/settings/validator.rb deleted file mode 100644 index 0a57ea7f038..00000000000 --- a/lib/ruby/stdlib/bundler/settings/validator.rb +++ /dev/null @@ -1,102 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Settings - class Validator - class Rule - attr_reader :description - - def initialize(keys, description, &validate) - @keys = keys - @description = description - @validate = validate - end - - def validate!(key, value, settings) - instance_exec(key, value, settings, &@validate) - end - - def fail!(key, value, *reasons) - reasons.unshift @description - raise InvalidOption, "Setting `#{key}` to #{value.inspect} failed:\n#{reasons.map {|r| " - #{r}" }.join("\n")}" - end - - def set(settings, key, value, *reasons) - hash_key = k(key) - return if settings[hash_key] == value - reasons.unshift @description - Bundler.ui.info "Setting `#{key}` to #{value.inspect}, since #{reasons.join(", ")}" - if value.nil? - settings.delete(hash_key) - else - settings[hash_key] = value - end - end - - def k(key) - Bundler.settings.key_for(key) - end - end - - def self.rules - @rules ||= Hash.new {|h, k| h[k] = [] } - end - private_class_method :rules - - def self.rule(keys, description, &blk) - rule = Rule.new(keys, description, &blk) - keys.each {|k| rules[k] << rule } - end - private_class_method :rule - - def self.validate!(key, value, settings) - rules_to_validate = rules[key] - rules_to_validate.each {|rule| rule.validate!(key, value, settings) } - end - - rule %w[path path.system], "path and path.system are mutually exclusive" do |key, value, settings| - if key == "path" && value - set(settings, "path.system", nil) - elsif key == "path.system" && value - set(settings, :path, nil) - end - end - - rule %w[with without], "a group cannot be in both `with` & `without` simultaneously" do |key, value, settings| - with = settings.fetch(k(:with), "").split(":").map(&:to_sym) - without = settings.fetch(k(:without), "").split(":").map(&:to_sym) - - other_key = key == "with" ? :without : :with - other_setting = key == "with" ? without : with - - conflicting = with & without - if conflicting.any? - fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict") - end - end - - rule %w[path], "relative paths are expanded relative to the current working directory" do |key, value, settings| - next if value.nil? - - path = Pathname.new(value) - next if !path.relative? || !Bundler.feature_flag.path_relative_to_cwd? - - path = path.expand_path - - root = begin - Bundler.root - rescue GemfileNotFound - Pathname.pwd.expand_path - end - - path = begin - path.relative_path_from(root) - rescue ArgumentError - path - end - - set(settings, key, path.to_s) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/setup.rb b/lib/ruby/stdlib/bundler/setup.rb deleted file mode 100644 index ac6a5bf8618..00000000000 --- a/lib/ruby/stdlib/bundler/setup.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require "bundler/shared_helpers" - -if Bundler::SharedHelpers.in_bundle? - require "bundler" - - if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"] - begin - Bundler.setup - rescue Bundler::BundlerError => e - puts "\e[31m#{e.message}\e[0m" - puts e.backtrace.join("\n") if ENV["DEBUG"] - if e.is_a?(Bundler::GemNotFound) - puts "\e[33mRun `bundle install` to install missing gems.\e[0m" - end - exit e.status_code - end - else - Bundler.setup - end - - # Add bundler to the load path after disabling system gems - bundler_lib = File.expand_path("../..", __FILE__) - $LOAD_PATH.unshift(bundler_lib) unless $LOAD_PATH.include?(bundler_lib) - - Bundler.ui = nil -end diff --git a/lib/ruby/stdlib/bundler/shared_helpers.rb b/lib/ruby/stdlib/bundler/shared_helpers.rb deleted file mode 100644 index 3e2fe24b7a9..00000000000 --- a/lib/ruby/stdlib/bundler/shared_helpers.rb +++ /dev/null @@ -1,384 +0,0 @@ -# frozen_string_literal: true - -require "bundler/compatibility_guard" - -require "pathname" -require "rubygems" - -require "bundler/version" -require "bundler/constants" -require "bundler/rubygems_integration" -require "bundler/current_ruby" - -module Gem - class Dependency - # This is only needed for RubyGems < 1.4 - unless method_defined? :requirement - def requirement - version_requirements - end - end - end -end - -module Bundler - module SharedHelpers - def root - gemfile = find_gemfile - raise GemfileNotFound, "Could not locate Gemfile" unless gemfile - Pathname.new(gemfile).untaint.expand_path.parent - end - - def default_gemfile - gemfile = find_gemfile(:order_matters) - raise GemfileNotFound, "Could not locate Gemfile" unless gemfile - Pathname.new(gemfile).untaint.expand_path - end - - def default_lockfile - gemfile = default_gemfile - - case gemfile.basename.to_s - when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked")) - else Pathname.new("#{gemfile}.lock") - end.untaint - end - - def default_bundle_dir - bundle_dir = find_directory(".bundle") - return nil unless bundle_dir - - bundle_dir = Pathname.new(bundle_dir) - - global_bundle_dir = Bundler.user_home.join(".bundle") - return nil if bundle_dir == global_bundle_dir - - bundle_dir - end - - def in_bundle? - find_gemfile - end - - def chdir(dir, &blk) - Bundler.rubygems.ext_lock.synchronize do - Dir.chdir dir, &blk - end - end - - def pwd - Bundler.rubygems.ext_lock.synchronize do - Pathname.pwd - end - end - - def with_clean_git_env(&block) - keys = %w[GIT_DIR GIT_WORK_TREE] - old_env = keys.inject({}) do |h, k| - h.update(k => ENV[k]) - end - - keys.each {|key| ENV.delete(key) } - - block.call - ensure - keys.each {|key| ENV[key] = old_env[key] } - end - - def set_bundle_environment - set_bundle_variables - set_path - set_rubyopt - set_rubylib - end - - # Rescues permissions errors raised by file system operations - # (ie. Errno:EACCESS, Errno::EAGAIN) and raises more friendly errors instead. - # - # @param path [String] the path that the action will be attempted to - # @param action [Symbol, #to_s] the type of operation that will be - # performed. For example: :write, :read, :exec - # - # @yield path - # - # @raise [Bundler::PermissionError] if Errno:EACCES is raised in the - # given block - # @raise [Bundler::TemporaryResourceError] if Errno:EAGAIN is raised in the - # given block - # - # @example - # filesystem_access("vendor/cache", :write) do - # FileUtils.mkdir_p("vendor/cache") - # end - # - # @see {Bundler::PermissionError} - def filesystem_access(path, action = :write, &block) - # Use block.call instead of yield because of a bug in Ruby 2.2.2 - # See https://github.com/bundler/bundler/issues/5341 for details - block.call(path.dup.untaint) - rescue Errno::EACCES - raise PermissionError.new(path, action) - rescue Errno::EAGAIN - raise TemporaryResourceError.new(path, action) - rescue Errno::EPROTO - raise VirtualProtocolError.new - rescue Errno::ENOSPC - raise NoSpaceOnDeviceError.new(path, action) - rescue *[const_get_safely(:ENOTSUP, Errno)].compact - raise OperationNotSupportedError.new(path, action) - rescue Errno::EEXIST, Errno::ENOENT - raise - rescue SystemCallError => e - raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.") - end - - def const_get_safely(constant_name, namespace) - const_in_namespace = namespace.constants.include?(constant_name.to_s) || - namespace.constants.include?(constant_name.to_sym) - return nil unless const_in_namespace - namespace.const_get(constant_name) - end - - def major_deprecation(major_version, message) - if Bundler.bundler_major_version >= major_version - require "bundler/errors" - raise DeprecatedError, "[REMOVED FROM #{major_version}.0] #{message}" - end - - return unless prints_major_deprecations? - @major_deprecation_ui ||= Bundler::UI::Shell.new("no-color" => true) - ui = Bundler.ui.is_a?(@major_deprecation_ui.class) ? Bundler.ui : @major_deprecation_ui - ui.warn("[DEPRECATED FOR #{major_version}.0] #{message}") - end - - def print_major_deprecations! - multiple_gemfiles = search_up(".") do |dir| - gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) } - next if gemfiles.empty? - break false if gemfiles.size == 1 - end - if multiple_gemfiles && Bundler.bundler_major_version == 1 - Bundler::SharedHelpers.major_deprecation 2, \ - "gems.rb and gems.locked will be preferred to Gemfile and Gemfile.lock." - end - - if RUBY_VERSION < "2" - major_deprecation(2, "Bundler will only support ruby >= 2.0, you are running #{RUBY_VERSION}") - end - return if Bundler.rubygems.provides?(">= 2") - major_deprecation(2, "Bundler will only support rubygems >= 2.0, you are running #{Bundler.rubygems.version}") - end - - def trap(signal, override = false, &block) - prior = Signal.trap(signal) do - block.call - prior.call unless override - end - end - - def ensure_same_dependencies(spec, old_deps, new_deps) - new_deps = new_deps.reject {|d| d.type == :development } - old_deps = old_deps.reject {|d| d.type == :development } - - without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) } - new_deps.map!(&without_type) - old_deps.map!(&without_type) - - extra_deps = new_deps - old_deps - return if extra_deps.empty? - - Bundler.ui.debug "#{spec.full_name} from #{spec.remote} has either corrupted API or lockfile dependencies" \ - " (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})" - raise APIResponseMismatchError, - "Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \ - "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem." - end - - def pretty_dependency(dep, print_source = false) - msg = String.new(dep.name) - msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default - - if dep.is_a?(Bundler::Dependency) - platform_string = dep.platforms.join(", ") - msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY - end - - msg << " from the `#{dep.source}` source" if print_source && dep.source - msg - end - - def md5_available? - return @md5_available if defined?(@md5_available) - @md5_available = begin - require "openssl" - OpenSSL::Digest::MD5.digest("") - true - rescue LoadError - true - rescue OpenSSL::Digest::DigestError - false - end - end - - def digest(name) - require "digest" - Digest(name) - end - - def write_to_gemfile(gemfile_path, contents) - filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } } - end - - private - - def validate_bundle_path - path_separator = Bundler.rubygems.path_separator - return unless Bundler.bundle_path.to_s.split(path_separator).size > 1 - message = "Your bundle path contains text matching #{path_separator.inspect}, " \ - "which is the path separator for your system. Bundler cannot " \ - "function correctly when the Bundle path contains the " \ - "system's PATH separator. Please change your " \ - "bundle path to not match #{path_separator.inspect}." \ - "\nYour current bundle path is '#{Bundler.bundle_path}'." - raise Bundler::PathError, message - end - - def find_gemfile(order_matters = false) - given = ENV["BUNDLE_GEMFILE"] - return given if given && !given.empty? - names = gemfile_names - names.reverse! if order_matters && Bundler.feature_flag.prefer_gems_rb? - find_file(*names) - end - - def gemfile_names - ["Gemfile", "gems.rb"] - end - - def find_file(*names) - search_up(*names) do |filename| - return filename if File.file?(filename) - end - end - - def find_directory(*names) - search_up(*names) do |dirname| - return dirname if File.directory?(dirname) - end - end - - def search_up(*names) - previous = nil - current = File.expand_path(SharedHelpers.pwd).untaint - - until !File.directory?(current) || current == previous - if ENV["BUNDLE_SPEC_RUN"] - # avoid stepping above the tmp directory when testing - gemspec = if ENV["BUNDLE_RUBY"] && ENV["BUNDLE_GEM"] - # for Ruby Core - "lib/bundler.gemspec" - else - "bundler.gemspec" - end - - # avoid stepping above the tmp directory when testing - return nil if File.file?(File.join(current, gemspec)) - end - - names.each do |name| - filename = File.join(current, name) - yield filename - end - previous = current - current = File.expand_path("..", current) - end - end - - def set_env(key, value) - raise ArgumentError, "new key #{key}" unless EnvironmentPreserver::BUNDLER_KEYS.include?(key) - orig_key = "#{EnvironmentPreserver::BUNDLER_PREFIX}#{key}" - orig = ENV[key] - orig ||= EnvironmentPreserver::INTENTIONALLY_NIL - ENV[orig_key] ||= orig - - ENV[key] = value - end - public :set_env - - def set_bundle_variables - begin - exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) - unless File.exist?(exe_file) - exe_file = File.expand_path("../../../exe/bundle", __FILE__) - end - Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file - rescue Gem::GemNotFoundException - exe_file = File.expand_path("../../../exe/bundle", __FILE__) - # for Ruby core repository - exe_file = File.expand_path("../../../../bin/bundle", __FILE__) unless File.exist?(exe_file) - Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file - end - - # Set BUNDLE_GEMFILE - Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile(:order_matters).to_s - Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION - end - - def set_path - validate_bundle_path - paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR) - paths.unshift "#{Bundler.bundle_path}/bin" - Bundler::SharedHelpers.set_env "PATH", paths.uniq.join(File::PATH_SEPARATOR) - end - - def set_rubyopt - rubyopt = [ENV["RUBYOPT"]].compact - return if !rubyopt.empty? && rubyopt.first =~ %r{-rbundler/setup} - rubyopt.unshift %(-rbundler/setup) - Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ") - end - - def set_rubylib - rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR) - rubylib.unshift bundler_ruby_lib - Bundler::SharedHelpers.set_env "RUBYLIB", rubylib.uniq.join(File::PATH_SEPARATOR) - end - - def bundler_ruby_lib - resolve_path File.expand_path("../..", __FILE__) - end - - def clean_load_path - # handle 1.9 where system gems are always on the load path - return unless defined?(::Gem) - - bundler_lib = bundler_ruby_lib - - loaded_gem_paths = Bundler.rubygems.loaded_gem_paths - - $LOAD_PATH.reject! do |p| - next if resolve_path(p).start_with?(bundler_lib) - loaded_gem_paths.delete(p) - end - $LOAD_PATH.uniq! - end - - def resolve_path(path) - expanded = File.expand_path(path) - return expanded unless File.respond_to?(:realpath) && File.exist?(expanded) - - File.realpath(expanded) - end - - def prints_major_deprecations? - require "bundler" - deprecation_release = Bundler::VERSION.split(".").drop(1).include?("99") - return false if !deprecation_release && !Bundler.settings[:major_deprecations] - require "bundler/deprecate" - return false if Bundler::Deprecate.skip - true - end - - extend self - end -end diff --git a/lib/ruby/stdlib/bundler/similarity_detector.rb b/lib/ruby/stdlib/bundler/similarity_detector.rb deleted file mode 100644 index b7f3ee7afad..00000000000 --- a/lib/ruby/stdlib/bundler/similarity_detector.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class SimilarityDetector - SimilarityScore = Struct.new(:string, :distance) - - # initialize with an array of words to be matched against - def initialize(corpus) - @corpus = corpus - end - - # return an array of words similar to 'word' from the corpus - def similar_words(word, limit = 3) - words_by_similarity = @corpus.map {|w| SimilarityScore.new(w, levenshtein_distance(word, w)) } - words_by_similarity.select {|s| s.distance <= limit }.sort_by(&:distance).map(&:string) - end - - # return the result of 'similar_words', concatenated into a list - # (eg "a, b, or c") - def similar_word_list(word, limit = 3) - words = similar_words(word, limit) - if words.length == 1 - words[0] - elsif words.length > 1 - [words[0..-2].join(", "), words[-1]].join(" or ") - end - end - - protected - - # http://www.informit.com/articles/article.aspx?p=683059&seqNum=36 - def levenshtein_distance(this, that, ins = 2, del = 2, sub = 1) - # ins, del, sub are weighted costs - return nil if this.nil? - return nil if that.nil? - dm = [] # distance matrix - - # Initialize first row values - dm[0] = (0..this.length).collect {|i| i * ins } - fill = [0] * (this.length - 1) - - # Initialize first column values - (1..that.length).each do |i| - dm[i] = [i * del, fill.flatten] - end - - # populate matrix - (1..that.length).each do |i| - (1..this.length).each do |j| - # critical comparison - dm[i][j] = [ - dm[i - 1][j - 1] + (this[j - 1] == that[i - 1] ? 0 : sub), - dm[i][j - 1] + ins, - dm[i - 1][j] + del - ].min - end - end - - # The last value in matrix is the Levenshtein distance between the strings - dm[that.length][this.length] - end - end -end diff --git a/lib/ruby/stdlib/bundler/source.rb b/lib/ruby/stdlib/bundler/source.rb deleted file mode 100644 index 26a3625bb17..00000000000 --- a/lib/ruby/stdlib/bundler/source.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Source - autoload :Gemspec, "bundler/source/gemspec" - autoload :Git, "bundler/source/git" - autoload :Metadata, "bundler/source/metadata" - autoload :Path, "bundler/source/path" - autoload :Rubygems, "bundler/source/rubygems" - - attr_accessor :dependency_names - - def unmet_deps - specs.unmet_dependency_names - end - - def version_message(spec) - message = "#{spec.name} #{spec.version}" - message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil? - - if Bundler.locked_gems - locked_spec = Bundler.locked_gems.specs.find {|s| s.name == spec.name } - locked_spec_version = locked_spec.version if locked_spec - if locked_spec_version && spec.version != locked_spec_version - message += Bundler.ui.add_color(" (was #{locked_spec_version})", version_color(spec.version, locked_spec_version)) - end - end - - message - end - - def can_lock?(spec) - spec.source == self - end - - # it's possible that gems from one source depend on gems from some - # other source, so now we download gemspecs and iterate over those - # dependencies, looking for gems we don't have info on yet. - def double_check_for(*); end - - def dependency_names_to_double_check - specs.dependency_names - end - - def include?(other) - other == self - end - - def inspect - "#<#{self.class}:0x#{object_id} #{self}>" - end - - def path? - instance_of?(Bundler::Source::Path) - end - - def extension_cache_path(spec) - return unless Bundler.feature_flag.global_gem_cache? - return unless source_slug = extension_cache_slug(spec) - Bundler.user_cache.join( - "extensions", Gem::Platform.local.to_s, Bundler.ruby_scope, - source_slug, spec.full_name - ) - end - - private - - def version_color(spec_version, locked_spec_version) - if Gem::Version.correct?(spec_version) && Gem::Version.correct?(locked_spec_version) - # display yellow if there appears to be a regression - earlier_version?(spec_version, locked_spec_version) ? :yellow : :green - else - # default to green if the versions cannot be directly compared - :green - end - end - - def earlier_version?(spec_version, locked_spec_version) - Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version) - end - - def print_using_message(message) - if !message.include?("(was ") && Bundler.feature_flag.suppress_install_using_messages? - Bundler.ui.debug message - else - Bundler.ui.info message - end - end - - def extension_cache_slug(_) - nil - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/gemspec.rb b/lib/ruby/stdlib/bundler/source/gemspec.rb deleted file mode 100644 index 7e3447e7765..00000000000 --- a/lib/ruby/stdlib/bundler/source/gemspec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Source - class Gemspec < Path - attr_reader :gemspec - - def initialize(options) - super - @gemspec = options["gemspec"] - end - - def as_path_source - Path.new(options) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/git.rb b/lib/ruby/stdlib/bundler/source/git.rb deleted file mode 100644 index 0b00608bdd6..00000000000 --- a/lib/ruby/stdlib/bundler/source/git.rb +++ /dev/null @@ -1,329 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_fileutils" -require "uri" - -module Bundler - class Source - class Git < Path - autoload :GitProxy, "bundler/source/git/git_proxy" - - attr_reader :uri, :ref, :branch, :options, :submodules - - def initialize(options) - @options = options - @glob = options["glob"] || DEFAULT_GLOB - - @allow_cached = false - @allow_remote = false - - # Stringify options that could be set as symbols - %w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] } - - @uri = options["uri"] || "" - @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri) - @branch = options["branch"] - @ref = options["ref"] || options["branch"] || options["tag"] || "master" - @submodules = options["submodules"] - @name = options["name"] - @version = options["version"].to_s.strip.gsub("-", ".pre.") - - @copied = false - @local = false - end - - def self.from_lock(options) - new(options.merge("uri" => options.delete("remote"))) - end - - def to_lock - out = String.new("GIT\n") - out << " remote: #{@uri}\n" - out << " revision: #{revision}\n" - %w[ref branch tag submodules].each do |opt| - out << " #{opt}: #{options[opt]}\n" if options[opt] - end - out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB - out << " specs:\n" - end - - def hash - [self.class, uri, ref, branch, name, version, submodules].hash - end - - def eql?(other) - other.is_a?(Git) && uri == other.uri && ref == other.ref && - branch == other.branch && name == other.name && - version == other.version && submodules == other.submodules - end - - alias_method :==, :eql? - - def to_s - at = if local? - path - elsif user_ref = options["ref"] - if ref =~ /\A[a-z0-9]{4,}\z/i - shortref_for_display(user_ref) - else - user_ref - end - else - ref - end - - rev = begin - "@#{shortref_for_display(revision)}" - rescue GitError - nil - end - - "#{@safe_uri} (at #{at}#{rev})" - end - - def name - File.basename(@uri, ".git") - end - - # This is the path which is going to contain a specific - # checkout of the git repository. When using local git - # repos, this is set to the local repo. - def install_path - @install_path ||= begin - git_scope = "#{base_name}-#{shortref_for_path(revision)}" - - path = Bundler.install_path.join(git_scope) - - if !path.exist? && Bundler.requires_sudo? - Bundler.user_bundle_path.join(Bundler.ruby_scope).join(git_scope) - else - path - end - end - end - - alias_method :path, :install_path - - def extension_dir_name - "#{base_name}-#{shortref_for_path(revision)}" - end - - def unlock! - git_proxy.revision = nil - options["revision"] = nil - - @unlocked = true - end - - def local_override!(path) - return false if local? - - path = Pathname.new(path) - path = path.expand_path(Bundler.root) unless path.relative? - - unless options["branch"] || Bundler.settings[:disable_local_branch_check] - raise GitError, "Cannot use local override for #{name} at #{path} because " \ - ":branch is not specified in Gemfile. Specify a branch or use " \ - "`bundle config --delete` to remove the local override" - end - - unless path.exist? - raise GitError, "Cannot use local override for #{name} because #{path} " \ - "does not exist. Check `bundle config --delete` to remove the local override" - end - - set_local!(path) - - # Create a new git proxy without the cached revision - # so the Gemfile.lock always picks up the new revision. - @git_proxy = GitProxy.new(path, uri, ref) - - if git_proxy.branch != options["branch"] && !Bundler.settings[:disable_local_branch_check] - raise GitError, "Local override for #{name} at #{path} is using branch " \ - "#{git_proxy.branch} but Gemfile specifies #{options["branch"]}" - end - - changed = cached_revision && cached_revision != git_proxy.revision - - if changed && !@unlocked && !git_proxy.contains?(cached_revision) - raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \ - "but the current branch in your local override for #{name} does not contain such commit. " \ - "Please make sure your branch is up to date." - end - - changed - end - - def specs(*) - set_local!(app_cache_path) if has_app_cache? && !local? - - if requires_checkout? && !@copied - fetch - git_proxy.copy_to(install_path, submodules) - serialize_gemspecs_in(install_path) - @copied = true - end - - local_specs - end - - def install(spec, options = {}) - force = options[:force] - - print_using_message "Using #{version_message(spec)} from #{self}" - - if (requires_checkout? && !@copied) || force - Bundler.ui.debug " * Checking out revision: #{ref}" - git_proxy.copy_to(install_path, submodules) - serialize_gemspecs_in(install_path) - @copied = true - end - - generate_bin_options = { :disable_extensions => !Bundler.rubygems.spec_missing_extensions?(spec), :build_args => options[:build_args] } - generate_bin(spec, generate_bin_options) - - requires_checkout? ? spec.post_install_message : nil - end - - def cache(spec, custom_path = nil) - app_cache_path = app_cache_path(custom_path) - return unless Bundler.feature_flag.cache_all? - return if path == app_cache_path - cached! - FileUtils.rm_rf(app_cache_path) - git_proxy.checkout if requires_checkout? - git_proxy.copy_to(app_cache_path, @submodules) - serialize_gemspecs_in(app_cache_path) - end - - def load_spec_files - super - rescue PathError => e - Bundler.ui.trace e - raise GitError, "#{self} is not yet checked out. Run `bundle install` first." - end - - # This is the path which is going to contain a cache - # of the git repository. When using the same git repository - # across different projects, this cache will be shared. - # When using local git repos, this is set to the local repo. - def cache_path - @cache_path ||= begin - if Bundler.requires_sudo? || Bundler.feature_flag.global_gem_cache? - Bundler.user_cache - else - Bundler.bundle_path.join("cache", "bundler") - end.join("git", git_scope) - end - end - - def app_cache_dirname - "#{base_name}-#{shortref_for_path(cached_revision || revision)}" - end - - def revision - git_proxy.revision - end - - def allow_git_ops? - @allow_remote || @allow_cached - end - - private - - def serialize_gemspecs_in(destination) - destination = destination.expand_path(Bundler.root) if destination.relative? - Dir["#{destination}/#{@glob}"].each do |spec_path| - # Evaluate gemspecs and cache the result. Gemspecs - # in git might require git or other dependencies. - # The gemspecs we cache should already be evaluated. - spec = Bundler.load_gemspec(spec_path) - next unless spec - Bundler.rubygems.set_installed_by_version(spec) - Bundler.rubygems.validate(spec) - File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) } - end - end - - def set_local!(path) - @local = true - @local_specs = @git_proxy = nil - @cache_path = @install_path = path - end - - def has_app_cache? - cached_revision && super - end - - def local? - @local - end - - def requires_checkout? - allow_git_ops? && !local? - end - - def base_name - File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*}, ""), ".git") - end - - def shortref_for_display(ref) - ref[0..6] - end - - def shortref_for_path(ref) - ref[0..11] - end - - def uri_hash - if uri =~ %r{^\w+://(\w+@)?} - # Downcase the domain component of the URI - # and strip off a trailing slash, if one is present - input = URI.parse(uri).normalize.to_s.sub(%r{/$}, "") - else - # If there is no URI scheme, assume it is an ssh/git URI - input = uri - end - SharedHelpers.digest(:SHA1).hexdigest(input) - end - - def cached_revision - options["revision"] - end - - def cached? - cache_path.exist? - end - - def git_proxy - @git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision, self) - end - - def fetch - git_proxy.checkout - rescue GitError => e - raise unless Bundler.feature_flag.allow_offline_install? - Bundler.ui.warn "Using cached git data because of network errors:\n#{e}" - end - - # no-op, since we validate when re-serializing the gemspec - def validate_spec(_spec); end - - if Bundler.rubygems.stubs_provide_full_functionality? - def load_gemspec(file) - stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent) - stub.full_gem_path = Pathname.new(file).dirname.expand_path(root).to_s.untaint - StubSpecification.from_stub(stub) - end - end - - def git_scope - "#{base_name}-#{uri_hash}" - end - - def extension_cache_slug(_) - extension_dir_name - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/git/git_proxy.rb b/lib/ruby/stdlib/bundler/source/git/git_proxy.rb deleted file mode 100644 index cd964f7e564..00000000000 --- a/lib/ruby/stdlib/bundler/source/git/git_proxy.rb +++ /dev/null @@ -1,262 +0,0 @@ -# frozen_string_literal: true - -require "shellwords" -require "tempfile" -module Bundler - class Source - class Git - class GitNotInstalledError < GitError - def initialize - msg = String.new - msg << "You need to install git to be able to use gems from git repositories. " - msg << "For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git" - super msg - end - end - - class GitNotAllowedError < GitError - def initialize(command) - msg = String.new - msg << "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, " - msg << "this error message could probably be more useful. Please submit a ticket at http://github.com/bundler/bundler/issues " - msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}" - super msg - end - end - - class GitCommandError < GitError - def initialize(command, path = nil, extra_info = nil) - msg = String.new - msg << "Git error: command `git #{command}` in directory #{SharedHelpers.pwd} has failed." - msg << "\n#{extra_info}" if extra_info - msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path && path.exist? - super msg - end - end - - class MissingGitRevisionError < GitError - def initialize(ref, repo) - msg = "Revision #{ref} does not exist in the repository #{repo}. Maybe you misspelled it?" - super msg - end - end - - # The GitProxy is responsible to interact with git repositories. - # All actions required by the Git source is encapsulated in this - # object. - class GitProxy - attr_accessor :path, :uri, :ref - attr_writer :revision - - def initialize(path, uri, ref, revision = nil, git = nil) - @path = path - @uri = uri - @ref = ref - @revision = revision - @git = git - raise GitNotInstalledError.new if allow? && !Bundler.git_present? - end - - def revision - return @revision if @revision - - begin - @revision ||= find_local_revision - rescue GitCommandError - raise MissingGitRevisionError.new(ref, URICredentialsFilter.credential_filtered_uri(uri)) - end - - @revision - end - - def branch - @branch ||= allowed_in_path do - git("rev-parse --abbrev-ref HEAD").strip - end - end - - def contains?(commit) - allowed_in_path do - result = git_null("branch --contains #{commit}") - $? == 0 && result =~ /^\* (.*)$/ - end - end - - def version - git("--version").match(/(git version\s*)?((\.?\d+)+).*/)[2] - end - - def full_version - git("--version").sub("git version", "").strip - end - - def checkout - return if path.exist? && has_revision_cached? - extra_ref = "#{Shellwords.shellescape(ref)}:#{Shellwords.shellescape(ref)}" if ref && ref.start_with?("refs/") - - Bundler.ui.info "Fetching #{URICredentialsFilter.credential_filtered_uri(uri)}" - - unless path.exist? - SharedHelpers.filesystem_access(path.dirname) do |p| - FileUtils.mkdir_p(p) - end - git_retry %(clone #{uri_escaped_with_configured_credentials} "#{path}" --bare --no-hardlinks --quiet) - return unless extra_ref - end - - in_path do - git_retry %(fetch --force --quiet --tags #{uri_escaped_with_configured_credentials} "refs/heads/*:refs/heads/*" #{extra_ref}) - end - end - - def copy_to(destination, submodules = false) - # method 1 - unless File.exist?(destination.join(".git")) - begin - SharedHelpers.filesystem_access(destination.dirname) do |p| - FileUtils.mkdir_p(p) - end - SharedHelpers.filesystem_access(destination) do |p| - FileUtils.rm_rf(p) - end - git_retry %(clone --no-checkout --quiet "#{path}" "#{destination}") - File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination) - rescue Errno::EEXIST => e - file_path = e.message[%r{.*?(/.*)}, 1] - raise GitError, "Bundler could not install a gem because it needs to " \ - "create a directory, but a file exists - #{file_path}. Please delete " \ - "this file and try again." - end - end - # method 2 - SharedHelpers.chdir(destination) do - git_retry %(fetch --force --quiet --tags "#{path}") - - begin - git "reset --hard #{@revision}" - rescue GitCommandError - raise MissingGitRevisionError.new(@revision, URICredentialsFilter.credential_filtered_uri(uri)) - end - - if submodules - git_retry "submodule update --init --recursive" - elsif Gem::Version.create(version) >= Gem::Version.create("2.9.0") - git_retry "submodule deinit --all --force" - end - end - end - - private - - # TODO: Do not rely on /dev/null. - # Given that open3 is not cross platform until Ruby 1.9.3, - # the best solution is to pipe to /dev/null if it exists. - # If it doesn't, everything will work fine, but the user - # will get the $stderr messages as well. - def git_null(command) - git("#{command} 2>#{Bundler::NULL}", false) - end - - def git_retry(command) - Bundler::Retry.new("`git #{URICredentialsFilter.credential_filtered_string(command, uri)}`", GitNotAllowedError).attempts do - git(command) - end - end - - def git(command, check_errors = true, error_msg = nil) - command_with_no_credentials = URICredentialsFilter.credential_filtered_string(command, uri) - raise GitNotAllowedError.new(command_with_no_credentials) unless allow? - - out = SharedHelpers.with_clean_git_env do - capture_and_filter_stderr(uri) { `git #{command}` } - end - - stdout_with_no_credentials = URICredentialsFilter.credential_filtered_string(out, uri) - raise GitCommandError.new(command_with_no_credentials, path, error_msg) if check_errors && !$?.success? - stdout_with_no_credentials - end - - def has_revision_cached? - return unless @revision - in_path { git("cat-file -e #{@revision}") } - true - rescue GitError - false - end - - def remove_cache - FileUtils.rm_rf(path) - end - - def find_local_revision - allowed_in_path do - git("rev-parse --verify #{Shellwords.shellescape(ref)}", true).strip - end - end - - # Escape the URI for git commands - def uri_escaped_with_configured_credentials - remote = configured_uri_for(uri) - if Bundler::WINDOWS - # Windows quoting requires double quotes only, with double quotes - # inside the string escaped by being doubled. - '"' + remote.gsub('"') { '""' } + '"' - else - # Bash requires single quoted strings, with the single quotes escaped - # by ending the string, escaping the quote, and restarting the string. - "'" + remote.gsub("'") { "'\\''" } + "'" - end - end - - # Adds credentials to the URI as Fetcher#configured_uri_for does - def configured_uri_for(uri) - if /https?:/ =~ uri - remote = URI(uri) - config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host] - remote.userinfo ||= config_auth - remote.to_s - else - uri - end - end - - def allow? - @git ? @git.allow_git_ops? : true - end - - def in_path(&blk) - checkout unless path.exist? - _ = URICredentialsFilter # load it before we chdir - SharedHelpers.chdir(path, &blk) - end - - def allowed_in_path - return in_path { yield } if allow? - raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application" - end - - # TODO: Replace this with Open3 when upgrading to bundler 2 - # Similar to #git_null, as Open3 is not cross-platform, - # a temporary way is to use Tempfile to capture the stderr. - # When replacing this using Open3, make sure git_null is - # also replaced by Open3, so stdout and stderr all got handled properly. - def capture_and_filter_stderr(uri) - return_value, captured_err = "" - backup_stderr = STDERR.dup - begin - Tempfile.open("captured_stderr") do |f| - STDERR.reopen(f) - return_value = yield - f.rewind - captured_err = f.read - end - ensure - STDERR.reopen backup_stderr - end - $stderr.puts URICredentialsFilter.credential_filtered_string(captured_err, uri) if uri && !captured_err.empty? - return_value - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/metadata.rb b/lib/ruby/stdlib/bundler/source/metadata.rb deleted file mode 100644 index d9c93bfb67e..00000000000 --- a/lib/ruby/stdlib/bundler/source/metadata.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Source - class Metadata < Source - def specs - @specs ||= Index.build do |idx| - idx << Gem::Specification.new("ruby\0", RubyVersion.system.to_gem_version_with_patchlevel) - idx << Gem::Specification.new("rubygems\0", Gem::VERSION) - - idx << Gem::Specification.new do |s| - s.name = "bundler" - s.version = VERSION - s.platform = Gem::Platform::RUBY - s.source = self - s.authors = ["bundler team"] - s.bindir = "exe" - s.executables = %w[bundle] - # can't point to the actual gemspec or else the require paths will be wrong - s.loaded_from = File.expand_path("..", __FILE__) - end - - if local_spec = Bundler.rubygems.find_name("bundler").find {|s| s.version.to_s == VERSION } - idx << local_spec - end - - idx.each {|s| s.source = self } - end - end - - def cached!; end - - def remote!; end - - def options - {} - end - - def install(spec, _opts = {}) - print_using_message "Using #{version_message(spec)}" - nil - end - - def to_s - "the local ruby installation" - end - - def ==(other) - self.class == other.class - end - alias_method :eql?, :== - - def hash - self.class.hash - end - - def version_message(spec) - "#{spec.name} #{spec.version}" - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/path.rb b/lib/ruby/stdlib/bundler/source/path.rb deleted file mode 100644 index ed734bf549a..00000000000 --- a/lib/ruby/stdlib/bundler/source/path.rb +++ /dev/null @@ -1,249 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Source - class Path < Source - autoload :Installer, "bundler/source/path/installer" - - attr_reader :path, :options, :root_path, :original_path - attr_writer :name - attr_accessor :version - - protected :original_path - - DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze - - def initialize(options) - @options = options.dup - @glob = options["glob"] || DEFAULT_GLOB - - @allow_cached = false - @allow_remote = false - - @root_path = options["root_path"] || Bundler.root - - if options["path"] - @path = Pathname.new(options["path"]) - @path = expand(@path) unless @path.relative? - end - - @name = options["name"] - @version = options["version"] - - # Stores the original path. If at any point we move to the - # cached directory, we still have the original path to copy from. - @original_path = @path - end - - def remote! - @local_specs = nil - @allow_remote = true - end - - def cached! - @local_specs = nil - @allow_cached = true - end - - def self.from_lock(options) - new(options.merge("path" => options.delete("remote"))) - end - - def to_lock - out = String.new("PATH\n") - out << " remote: #{lockfile_path}\n" - out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB - out << " specs:\n" - end - - def to_s - "source at `#{@path}`" - end - - def hash - [self.class, expanded_path, version].hash - end - - def eql?(other) - return unless other.class == self.class - expanded_original_path == other.expanded_original_path && - version == other.version - end - - alias_method :==, :eql? - - def name - File.basename(expanded_path.to_s) - end - - def install(spec, options = {}) - print_using_message "Using #{version_message(spec)} from #{self}" - generate_bin(spec, :disable_extensions => true) - nil # no post-install message - end - - def cache(spec, custom_path = nil) - app_cache_path = app_cache_path(custom_path) - return unless Bundler.feature_flag.cache_all? - return if expand(@original_path).to_s.index(root_path.to_s + "/") == 0 - - unless @original_path.exist? - raise GemNotFound, "Can't cache gem #{version_message(spec)} because #{self} is missing!" - end - - FileUtils.rm_rf(app_cache_path) - FileUtils.cp_r("#{@original_path}/.", app_cache_path) - FileUtils.touch(app_cache_path.join(".bundlecache")) - end - - def local_specs(*) - @local_specs ||= load_spec_files - end - - def specs - if has_app_cache? - @path = app_cache_path - @expanded_path = nil # Invalidate - end - local_specs - end - - def app_cache_dirname - name - end - - def root - Bundler.root - end - - def expanded_original_path - @expanded_original_path ||= expand(original_path) - end - - private - - def expanded_path - @expanded_path ||= expand(path) - end - - def expand(somepath) - somepath.expand_path(root_path) - rescue ArgumentError => e - Bundler.ui.debug(e) - raise PathError, "There was an error while trying to use the path " \ - "`#{somepath}`.\nThe error message was: #{e.message}." - end - - def lockfile_path - return relative_path(original_path) if original_path.absolute? - expand(original_path).relative_path_from(Bundler.root) - end - - def app_cache_path(custom_path = nil) - @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) - end - - def has_app_cache? - SharedHelpers.in_bundle? && app_cache_path.exist? - end - - def load_gemspec(file) - return unless spec = Bundler.load_gemspec(file) - Bundler.rubygems.set_installed_by_version(spec) - spec - end - - def validate_spec(spec) - Bundler.rubygems.validate(spec) - end - - def load_spec_files - index = Index.new - - if File.directory?(expanded_path) - # We sort depth-first since `<<` will override the earlier-found specs - Dir["#{expanded_path}/#{@glob}"].sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file| - next unless spec = load_gemspec(file) - spec.source = self - - # Validation causes extension_dir to be calculated, which depends - # on #source, so we validate here instead of load_gemspec - validate_spec(spec) - index << spec - end - - if index.empty? && @name && @version - index << Gem::Specification.new do |s| - s.name = @name - s.source = self - s.version = Gem::Version.new(@version) - s.platform = Gem::Platform::RUBY - s.summary = "Fake gemspec for #{@name}" - s.relative_loaded_from = "#{@name}.gemspec" - s.authors = ["no one"] - if expanded_path.join("bin").exist? - executables = expanded_path.join("bin").children - executables.reject! {|p| File.directory?(p) } - s.executables = executables.map {|c| c.basename.to_s } - end - end - end - else - message = String.new("The path `#{expanded_path}` ") - message << if File.exist?(expanded_path) - "is not a directory." - else - "does not exist." - end - raise PathError, message - end - - index - end - - def relative_path(path = self.path) - if path.to_s.start_with?(root_path.to_s) - return path.relative_path_from(root_path) - end - path - end - - def generate_bin(spec, options = {}) - gem_dir = Pathname.new(spec.full_gem_path) - - # Some gem authors put absolute paths in their gemspec - # and we have to save them from themselves - spec.files = spec.files.map do |p| - next p unless p =~ /\A#{Pathname::SEPARATOR_PAT}/ - next if File.directory?(p) - begin - Pathname.new(p).relative_path_from(gem_dir).to_s - rescue ArgumentError - p - end - end.compact - - installer = Path::Installer.new( - spec, - :env_shebang => false, - :disable_extensions => options[:disable_extensions], - :build_args => options[:build_args], - :bundler_extension_cache_path => extension_cache_path(spec) - ) - installer.post_install - rescue Gem::InvalidSpecificationException => e - Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \ - "This prevents bundler from installing bins or native extensions, but " \ - "that may not affect its functionality." - - if !spec.extensions.empty? && !spec.email.empty? - Bundler.ui.warn "If you need to use this package without installing it from a gem " \ - "repository, please contact #{spec.email} and ask them " \ - "to modify their .gemspec so it can work with `gem build`." - end - - Bundler.ui.warn "The validation message from RubyGems was:\n #{e.message}" - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/path/installer.rb b/lib/ruby/stdlib/bundler/source/path/installer.rb deleted file mode 100644 index a0357ffa391..00000000000 --- a/lib/ruby/stdlib/bundler/source/path/installer.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Source - class Path - class Installer < Bundler::RubyGemsGemInstaller - attr_reader :spec - - def initialize(spec, options = {}) - @options = options - @spec = spec - @gem_dir = Bundler.rubygems.path(spec.full_gem_path) - @wrappers = true - @env_shebang = true - @format_executable = options[:format_executable] || false - @build_args = options[:build_args] || Bundler.rubygems.build_args - @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin" - @disable_extensions = options[:disable_extensions] - - if Bundler.requires_sudo? - @tmp_dir = Bundler.tmp(spec.full_name).to_s - @bin_dir = "#{@tmp_dir}/bin" - else - @bin_dir = @gem_bin_dir - end - end - - def post_install - SharedHelpers.chdir(@gem_dir) do - run_hooks(:pre_install) - - unless @disable_extensions - build_extensions - run_hooks(:post_build) - end - - generate_bin unless spec.executables.nil? || spec.executables.empty? - - run_hooks(:post_install) - end - ensure - Bundler.rm_rf(@tmp_dir) if Bundler.requires_sudo? - end - - private - - def generate_bin - super - - if Bundler.requires_sudo? - SharedHelpers.filesystem_access(@gem_bin_dir) do |p| - Bundler.mkdir_p(p) - end - spec.executables.each do |exe| - Bundler.sudo "cp -R #{@bin_dir}/#{exe} #{@gem_bin_dir}" - end - end - end - - def run_hooks(type) - hooks_meth = "#{type}_hooks" - return unless Gem.respond_to?(hooks_meth) - Gem.send(hooks_meth).each do |hook| - result = hook.call(self) - next unless result == false - location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ - message = "#{type} hook#{location} failed for #{spec.full_name}" - raise InstallHookError, message - end - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/rubygems.rb b/lib/ruby/stdlib/bundler/source/rubygems.rb deleted file mode 100644 index 485b388a326..00000000000 --- a/lib/ruby/stdlib/bundler/source/rubygems.rb +++ /dev/null @@ -1,539 +0,0 @@ -# frozen_string_literal: true - -require "uri" -require "rubygems/user_interaction" - -module Bundler - class Source - class Rubygems < Source - autoload :Remote, "bundler/source/rubygems/remote" - - # Use the API when installing less than X gems - API_REQUEST_LIMIT = 500 - # Ask for X gems per API request - API_REQUEST_SIZE = 50 - - attr_reader :remotes, :caches - - def initialize(options = {}) - @options = options - @remotes = [] - @dependency_names = [] - @allow_remote = false - @allow_cached = false - @caches = [cache_path, *Bundler.rubygems.gem_cache] - - Array(options["remotes"] || []).reverse_each {|r| add_remote(r) } - end - - def remote! - @specs = nil - @allow_remote = true - end - - def cached! - @specs = nil - @allow_cached = true - end - - def hash - @remotes.hash - end - - def eql?(other) - other.is_a?(Rubygems) && other.credless_remotes == credless_remotes - end - - alias_method :==, :eql? - - def include?(o) - o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? - end - - def can_lock?(spec) - return super if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - spec.source.is_a?(Rubygems) - end - - def options - { "remotes" => @remotes.map(&:to_s) } - end - - def self.from_lock(options) - new(options) - end - - def to_lock - out = String.new("GEM\n") - remotes.reverse_each do |remote| - out << " remote: #{suppress_configured_credentials remote}\n" - end - out << " specs:\n" - end - - def to_s - if remotes.empty? - "locally installed gems" - else - remote_names = remotes.map(&:to_s).join(", ") - "rubygems repository #{remote_names} or installed locally" - end - end - alias_method :name, :to_s - - def specs - @specs ||= begin - # remote_specs usually generates a way larger Index than the other - # sources, and large_idx.use small_idx is way faster than - # small_idx.use large_idx. - idx = @allow_remote ? remote_specs.dup : Index.new - idx.use(cached_specs, :override_dupes) if @allow_cached || @allow_remote - idx.use(installed_specs, :override_dupes) - idx - end - end - - def install(spec, opts = {}) - force = opts[:force] - ensure_builtin_gems_cached = opts[:ensure_builtin_gems_cached] - - if ensure_builtin_gems_cached && builtin_gem?(spec) - if !cached_path(spec) - cached_built_in_gem(spec) unless spec.remote - force = true - else - spec.loaded_from = loaded_from(spec) - end - end - - if installed?(spec) && !force - print_using_message "Using #{version_message(spec)}" - return nil # no post-install message - end - - # Download the gem to get the spec, because some specs that are returned - # by rubygems.org are broken and wrong. - if spec.remote - # Check for this spec from other sources - uris = [spec.remote.anonymized_uri] - uris += remotes_for_spec(spec).map(&:anonymized_uri) - uris.uniq! - Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1 - - s = Bundler.rubygems.spec_from_gem(fetch_gem(spec), Bundler.settings["trust-policy"]) - spec.__swap__(s) - end - - unless Bundler.settings[:no_install] - message = "Installing #{version_message(spec)}" - message += " with native extensions" if spec.extensions.any? - Bundler.ui.confirm message - - path = cached_gem(spec) - if requires_sudo? - install_path = Bundler.tmp(spec.full_name) - bin_path = install_path.join("bin") - else - install_path = rubygems_dir - bin_path = Bundler.system_bindir - end - - Bundler.mkdir_p bin_path, :no_sudo => true unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5") - - installed_spec = nil - Bundler.rubygems.preserve_paths do - installed_spec = Bundler::RubyGemsGemInstaller.at( - path, - :install_dir => install_path.to_s, - :bin_dir => bin_path.to_s, - :ignore_dependencies => true, - :wrappers => true, - :env_shebang => true, - :build_args => opts[:build_args], - :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum, - :bundler_extension_cache_path => extension_cache_path(spec) - ).install - end - spec.full_gem_path = installed_spec.full_gem_path - - # SUDO HAX - if requires_sudo? - Bundler.rubygems.repository_subdirectories.each do |name| - src = File.join(install_path, name, "*") - dst = File.join(rubygems_dir, name) - if name == "extensions" && Dir.glob(src).any? - src = File.join(src, "*/*") - ext_src = Dir.glob(src).first - ext_src.gsub!(src[0..-6], "") - dst = File.dirname(File.join(dst, ext_src)) - end - SharedHelpers.filesystem_access(dst) do |p| - Bundler.mkdir_p(p) - end - Bundler.sudo "cp -R #{src} #{dst}" if Dir[src].any? - end - - spec.executables.each do |exe| - SharedHelpers.filesystem_access(Bundler.system_bindir) do |p| - Bundler.mkdir_p(p) - end - Bundler.sudo "cp -R #{install_path}/bin/#{exe} #{Bundler.system_bindir}/" - end - end - installed_spec.loaded_from = loaded_from(spec) - end - spec.loaded_from = loaded_from(spec) - - spec.post_install_message - ensure - Bundler.rm_rf(install_path) if requires_sudo? - end - - def cache(spec, custom_path = nil) - if builtin_gem?(spec) - cached_path = cached_built_in_gem(spec) - else - cached_path = cached_gem(spec) - end - raise GemNotFound, "Missing gem file '#{spec.full_name}.gem'." unless cached_path - return if File.dirname(cached_path) == Bundler.app_cache.to_s - Bundler.ui.info " * #{File.basename(cached_path)}" - FileUtils.cp(cached_path, Bundler.app_cache(custom_path)) - rescue Errno::EACCES => e - Bundler.ui.debug(e) - raise InstallError, e.message - end - - def cached_built_in_gem(spec) - cached_path = cached_path(spec) - if cached_path.nil? - remote_spec = remote_specs.search(spec).first - if remote_spec - cached_path = fetch_gem(remote_spec) - else - Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it." - end - end - cached_path - end - - def add_remote(source) - uri = normalize_uri(source) - @remotes.unshift(uri) unless @remotes.include?(uri) - end - - def equivalent_remotes?(other_remotes) - other_remotes.map(&method(:remove_auth)) == @remotes.map(&method(:remove_auth)) - end - - def replace_remotes(other_remotes, allow_equivalent = false) - return false if other_remotes == @remotes - - equivalent = allow_equivalent && equivalent_remotes?(other_remotes) - - @remotes = [] - other_remotes.reverse_each do |r| - add_remote r.to_s - end - - !equivalent - end - - def unmet_deps - if @allow_remote && api_fetchers.any? - remote_specs.unmet_dependency_names - else - [] - end - end - - def fetchers - @fetchers ||= remotes.map do |uri| - remote = Source::Rubygems::Remote.new(uri) - Bundler::Fetcher.new(remote) - end - end - - def double_check_for(unmet_dependency_names) - return unless @allow_remote - return unless api_fetchers.any? - - unmet_dependency_names = unmet_dependency_names.call - unless unmet_dependency_names.nil? - if api_fetchers.size <= 1 - # can't do this when there are multiple fetchers because then we might not fetch from _all_ - # of them - unmet_dependency_names -= remote_specs.spec_names # avoid re-fetching things we've already gotten - end - return if unmet_dependency_names.empty? - end - - Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}" - - fetch_names(api_fetchers, unmet_dependency_names, specs, false) - end - - def dependency_names_to_double_check - names = [] - remote_specs.each do |spec| - case spec - when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification - names.concat(spec.runtime_dependencies) - when RemoteSpecification # from the full index - return nil - else - raise "unhandled spec type (#{spec.inspect})" - end - end - names.map!(&:name) if names - names - end - - protected - - def credless_remotes - remotes.map(&method(:suppress_configured_credentials)) - end - - def remotes_for_spec(spec) - specs.search_all(spec.name).inject([]) do |uris, s| - uris << s.remote if s.remote - uris - end - end - - def loaded_from(spec) - "#{rubygems_dir}/specifications/#{spec.full_name}.gemspec" - end - - def cached_gem(spec) - cached_gem = cached_path(spec) - unless cached_gem - raise Bundler::GemNotFound, "Could not find #{spec.file_name} for installation" - end - cached_gem - end - - def cached_path(spec) - possibilities = @caches.map {|p| "#{p}/#{spec.file_name}" } - possibilities.find {|p| File.exist?(p) } - end - - def normalize_uri(uri) - uri = uri.to_s - uri = "#{uri}/" unless uri =~ %r{/$} - uri = URI(uri) - raise ArgumentError, "The source must be an absolute URI. For example:\n" \ - "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(URI::HTTP) && uri.host.nil?) - uri - end - - def suppress_configured_credentials(remote) - remote_nouser = remove_auth(remote) - if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser] - remote_nouser - else - remote - end - end - - def remove_auth(remote) - if remote.user || remote.password - remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s - else - remote.to_s - end - end - - def installed_specs - @installed_specs ||= Index.build do |idx| - Bundler.rubygems.all_specs.reverse_each do |spec| - next if spec.name == "bundler" - spec.source = self - if Bundler.rubygems.spec_missing_extensions?(spec, false) - Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions" - next - end - idx << spec - end - end - end - - def cached_specs - @cached_specs ||= begin - idx = installed_specs.dup - - Dir["#{cache_path}/*.gem"].each do |gemfile| - next if gemfile =~ /^bundler\-[\d\.]+?\.gem/ - s ||= Bundler.rubygems.spec_from_gem(gemfile) - s.source = self - if Bundler.rubygems.spec_missing_extensions?(s, false) - Bundler.ui.debug "Source #{self} is ignoring #{s} because it is missing extensions" - next - end - idx << s - end - - idx - end - end - - def api_fetchers - fetchers.select {|f| f.use_api && f.fetchers.first.api_fetcher? } - end - - def remote_specs - @remote_specs ||= Index.build do |idx| - index_fetchers = fetchers - api_fetchers - - # gather lists from non-api sites - fetch_names(index_fetchers, nil, idx, false) - - # because ensuring we have all the gems we need involves downloading - # the gemspecs of those gems, if the non-api sites contain more than - # about 500 gems, we treat all sites as non-api for speed. - allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT - Bundler.ui.debug "Need to query more than #{API_REQUEST_LIMIT} gems." \ - " Downloading full index instead..." unless allow_api - - fetch_names(api_fetchers, allow_api && dependency_names, idx, false) - end - end - - def fetch_names(fetchers, dependency_names, index, override_dupes) - fetchers.each do |f| - if dependency_names - Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug? - index.use f.specs_with_retry(dependency_names, self), override_dupes - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - else - Bundler.ui.info "Fetching source index from #{f.uri}" - index.use f.specs_with_retry(nil, self), override_dupes - end - end - end - - def fetch_gem(spec) - return false unless spec.remote - - spec.fetch_platform - - download_path = requires_sudo? ? Bundler.tmp(spec.full_name) : rubygems_dir - gem_path = "#{rubygems_dir}/cache/#{spec.full_name}.gem" - - SharedHelpers.filesystem_access("#{download_path}/cache") do |p| - FileUtils.mkdir_p(p) - end - download_gem(spec, download_path) - - if requires_sudo? - SharedHelpers.filesystem_access("#{rubygems_dir}/cache") do |p| - Bundler.mkdir_p(p) - end - Bundler.sudo "mv #{download_path}/cache/#{spec.full_name}.gem #{gem_path}" - end - - gem_path - ensure - Bundler.rm_rf(download_path) if requires_sudo? - end - - def builtin_gem?(spec) - # Ruby 2.1, where all included gems have this summary - return true if spec.summary =~ /is bundled with Ruby/ - - # Ruby 2.0, where gemspecs are stored in specifications/default/ - spec.loaded_from && spec.loaded_from.include?("specifications/default/") - end - - def installed?(spec) - installed_specs[spec].any? - end - - def requires_sudo? - Bundler.requires_sudo? - end - - def rubygems_dir - Bundler.rubygems.gem_dir - end - - def cache_path - Bundler.app_cache - end - - private - - # Checks if the requested spec exists in the global cache. If it does, - # we copy it to the download path, and if it does not, we download it. - # - # @param [Specification] spec - # the spec we want to download or retrieve from the cache. - # - # @param [String] download_path - # the local directory the .gem will end up in. - # - def download_gem(spec, download_path) - local_path = File.join(download_path, "cache/#{spec.full_name}.gem") - - if (cache_path = download_cache_path(spec)) && cache_path.file? - SharedHelpers.filesystem_access(local_path) do - FileUtils.cp(cache_path, local_path) - end - else - uri = spec.remote.uri - Bundler.ui.confirm("Fetching #{version_message(spec)}") - rubygems_local_path = Bundler.rubygems.download_gem(spec, uri, download_path) - if rubygems_local_path != local_path - FileUtils.mv(rubygems_local_path, local_path) - end - cache_globally(spec, local_path) - end - end - - # Checks if the requested spec exists in the global cache. If it does - # not, we create the relevant global cache subdirectory if it does not - # exist and copy the spec from the local cache to the global cache. - # - # @param [Specification] spec - # the spec we want to copy to the global cache. - # - # @param [String] local_cache_path - # the local directory from which we want to copy the .gem. - # - def cache_globally(spec, local_cache_path) - return unless cache_path = download_cache_path(spec) - return if cache_path.exist? - - SharedHelpers.filesystem_access(cache_path.dirname, &:mkpath) - SharedHelpers.filesystem_access(cache_path) do - FileUtils.cp(local_cache_path, cache_path) - end - end - - # Returns the global cache path of the calling Rubygems::Source object. - # - # Note that the Source determines the path's subdirectory. We use this - # subdirectory in the global cache path so that gems with the same name - # -- and possibly different versions -- from different sources are saved - # to their respective subdirectories and do not override one another. - # - # @param [Gem::Specification] specification - # - # @return [Pathname] The global cache path. - # - def download_cache_path(spec) - return unless Bundler.feature_flag.global_gem_cache? - return unless remote = spec.remote - return unless cache_slug = remote.cache_slug - - Bundler.user_cache.join("gems", cache_slug, spec.file_name) - end - - def extension_cache_slug(spec) - return unless remote = spec.remote - remote.cache_slug - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source/rubygems/remote.rb b/lib/ruby/stdlib/bundler/source/rubygems/remote.rb deleted file mode 100644 index b45f33770ae..00000000000 --- a/lib/ruby/stdlib/bundler/source/rubygems/remote.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class Source - class Rubygems - class Remote - attr_reader :uri, :anonymized_uri, :original_uri - - def initialize(uri) - orig_uri = uri - uri = Bundler.settings.mirror_for(uri) - @original_uri = orig_uri if orig_uri != uri - fallback_auth = Bundler.settings.credentials_for(uri) - - @uri = apply_auth(uri, fallback_auth).freeze - @anonymized_uri = remove_auth(@uri).freeze - end - - # @return [String] A slug suitable for use as a cache key for this - # remote. - # - def cache_slug - @cache_slug ||= begin - return nil unless SharedHelpers.md5_available? - - cache_uri = original_uri || uri - - # URI::File of Ruby 2.6 returns empty string when given "file://". - host = defined?(URI::File) && cache_uri.is_a?(URI::File) ? nil : cache_uri.host - - uri_parts = [host, cache_uri.user, cache_uri.port, cache_uri.path] - uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.compact.join(".")) - - uri_parts[-1] = uri_digest - uri_parts.compact.join(".") - end - end - - def to_s - "rubygems remote at #{anonymized_uri}" - end - - private - - def apply_auth(uri, auth) - if auth && uri.userinfo.nil? - uri = uri.dup - uri.userinfo = auth - end - - uri - rescue URI::InvalidComponentError - error_message = "Please CGI escape your usernames and passwords before " \ - "setting them for authentication." - raise HTTPError.new(error_message) - end - - def remove_auth(uri) - if uri.userinfo - uri = uri.dup - uri.user = uri.password = nil - end - - uri - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/source_list.rb b/lib/ruby/stdlib/bundler/source_list.rb deleted file mode 100644 index ac2adacb3d4..00000000000 --- a/lib/ruby/stdlib/bundler/source_list.rb +++ /dev/null @@ -1,186 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class SourceList - attr_reader :path_sources, - :git_sources, - :plugin_sources, - :global_rubygems_source, - :metadata_source - - def initialize - @path_sources = [] - @git_sources = [] - @plugin_sources = [] - @global_rubygems_source = nil - @rubygems_aggregate = rubygems_aggregate_class.new - @rubygems_sources = [] - @metadata_source = Source::Metadata.new - end - - def add_path_source(options = {}) - if options["gemspec"] - add_source_to_list Source::Gemspec.new(options), path_sources - else - add_source_to_list Source::Path.new(options), path_sources - end - end - - def add_git_source(options = {}) - add_source_to_list(Source::Git.new(options), git_sources).tap do |source| - warn_on_git_protocol(source) - end - end - - def add_rubygems_source(options = {}) - add_source_to_list Source::Rubygems.new(options), @rubygems_sources - end - - def add_plugin_source(source, options = {}) - add_source_to_list Plugin.source(source).new(options), @plugin_sources - end - - def global_rubygems_source=(uri) - if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri) - end - add_rubygems_remote(uri) - end - - def add_rubygems_remote(uri) - if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - return if Bundler.feature_flag.disable_multisource? - raise InvalidOption, "`lockfile_uses_separate_rubygems_sources` cannot be set without `disable_multisource` being set" - end - @rubygems_aggregate.add_remote(uri) - @rubygems_aggregate - end - - def default_source - global_rubygems_source || @rubygems_aggregate - end - - def rubygems_sources - @rubygems_sources + [default_source] - end - - def rubygems_remotes - rubygems_sources.map(&:remotes).flatten.uniq - end - - def all_sources - path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] - end - - def get(source) - source_list_for(source).find {|s| equal_source?(source, s) || equivalent_source?(source, s) } - end - - def lock_sources - if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - [[default_source], @rubygems_sources, git_sources, path_sources, plugin_sources].map do |sources| - sources.sort_by(&:to_s) - end.flatten(1) - else - lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s) - lock_sources << combine_rubygems_sources - end - end - - # Returns true if there are changes - def replace_sources!(replacement_sources) - return true if replacement_sources.empty? - - [path_sources, git_sources, plugin_sources].each do |source_list| - source_list.map! do |source| - replacement_sources.find {|s| s == source } || source - end - end - - replacement_rubygems = !Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? && - replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } - @rubygems_aggregate = replacement_rubygems if replacement_rubygems - - return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) - return true if replacement_rubygems && rubygems_remotes.to_set != replacement_rubygems.remotes.to_set - - false - end - - def cached! - all_sources.each(&:cached!) - end - - def remote! - all_sources.each(&:remote!) - end - - def rubygems_primary_remotes - @rubygems_aggregate.remotes - end - - private - - def rubygems_aggregate_class - Source::Rubygems - end - - def add_source_to_list(source, list) - list.unshift(source).uniq! - source - end - - def source_list_for(source) - case source - when Source::Git then git_sources - when Source::Path then path_sources - when Source::Rubygems then rubygems_sources - when Plugin::API::Source then plugin_sources - else raise ArgumentError, "Invalid source: #{source.inspect}" - end - end - - def combine_rubygems_sources - Source::Rubygems.new("remotes" => rubygems_remotes) - end - - def warn_on_git_protocol(source) - return if Bundler.settings["git.allow_insecure"] - - if source.uri =~ /^git\:/ - Bundler.ui.warn "The git source `#{source.uri}` uses the `git` protocol, " \ - "which transmits data without encryption. Disable this warning with " \ - "`bundle config git.allow_insecure true`, or switch to the `https` " \ - "protocol to keep your data secure." - end - end - - def equal_sources?(lock_sources, replacement_sources) - lock_sources.to_set == replacement_sources.to_set - end - - def equal_source?(source, other_source) - source == other_source - end - - def equivalent_source?(source, other_source) - return false unless Bundler.settings[:allow_deployment_source_credential_changes] && source.is_a?(Source::Rubygems) - - equivalent_rubygems_sources?([source], [other_source]) - end - - def equivalent_sources?(lock_sources, replacement_sources) - return false unless Bundler.settings[:allow_deployment_source_credential_changes] - - lock_rubygems_sources, lock_other_sources = lock_sources.partition {|s| s.is_a?(Source::Rubygems) } - replacement_rubygems_sources, replacement_other_sources = replacement_sources.partition {|s| s.is_a?(Source::Rubygems) } - - equivalent_rubygems_sources?(lock_rubygems_sources, replacement_rubygems_sources) && equal_sources?(lock_other_sources, replacement_other_sources) - end - - def equivalent_rubygems_sources?(lock_sources, replacement_sources) - actual_remotes = replacement_sources.map(&:remotes).flatten.uniq - lock_sources.all? {|s| s.equivalent_remotes?(actual_remotes) } - end - end -end diff --git a/lib/ruby/stdlib/bundler/spec_set.rb b/lib/ruby/stdlib/bundler/spec_set.rb deleted file mode 100644 index 5003b2cbeca..00000000000 --- a/lib/ruby/stdlib/bundler/spec_set.rb +++ /dev/null @@ -1,192 +0,0 @@ -# frozen_string_literal: true - -require "tsort" -require "forwardable" -require "set" - -module Bundler - class SpecSet - extend Forwardable - include TSort, Enumerable - - def_delegators :@specs, :<<, :length, :add, :remove, :size, :empty? - def_delegators :sorted, :each - - def initialize(specs) - @specs = specs - end - - def for(dependencies, skip = [], check = false, match_current_platform = false, raise_on_missing = true) - handled = Set.new - deps = dependencies.dup - specs = [] - skip += ["bundler"] - - loop do - break unless dep = deps.shift - next if !handled.add?(dep) || skip.include?(dep.name) - - if spec = spec_for_dependency(dep, match_current_platform) - specs << spec - - spec.dependencies.each do |d| - next if d.type == :development - d = DepProxy.new(d, dep.__platform) unless match_current_platform - deps << d - end - elsif check - return false - elsif raise_on_missing - others = lookup[dep.name] if match_current_platform - message = "Unable to find a spec satisfying #{dep} in the set. Perhaps the lockfile is corrupted?" - message += " Found #{others.join(", ")} that did not match the current platform." if others && !others.empty? - raise GemNotFound, message - end - end - - if spec = lookup["bundler"].first - specs << spec - end - - check ? true : SpecSet.new(specs) - end - - def valid_for?(deps) - self.for(deps, [], true) - end - - def [](key) - key = key.name if key.respond_to?(:name) - lookup[key].reverse - end - - def []=(key, value) - @specs << value - @lookup = nil - @sorted = nil - value - end - - def sort! - self - end - - def to_a - sorted.dup - end - - def to_hash - lookup.dup - end - - def materialize(deps, missing_specs = nil) - materialized = self.for(deps, [], false, true, !missing_specs).to_a - deps = materialized.map(&:name).uniq - materialized.map! do |s| - next s unless s.is_a?(LazySpecification) - s.source.dependency_names = deps if s.source.respond_to?(:dependency_names=) - spec = s.__materialize__ - unless spec - unless missing_specs - raise GemNotFound, "Could not find #{s.full_name} in any of the sources" - end - missing_specs << s - end - spec - end - SpecSet.new(missing_specs ? materialized.compact : materialized) - end - - # Materialize for all the specs in the spec set, regardless of what platform they're for - # This is in contrast to how for does platform filtering (and specifically different from how `materialize` calls `for` only for the current platform) - # @return [Array] - def materialized_for_all_platforms - names = @specs.map(&:name).uniq - @specs.map do |s| - next s unless s.is_a?(LazySpecification) - s.source.dependency_names = names if s.source.respond_to?(:dependency_names=) - spec = s.__materialize__ - raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec - spec - end - end - - def merge(set) - arr = sorted.dup - set.each do |set_spec| - full_name = set_spec.full_name - next if arr.any? {|spec| spec.full_name == full_name } - arr << set_spec - end - SpecSet.new(arr) - end - - def find_by_name_and_platform(name, platform) - @specs.detect {|spec| spec.name == name && spec.match_platform(platform) } - end - - def what_required(spec) - unless req = find {|s| s.dependencies.any? {|d| d.type == :runtime && d.name == spec.name } } - return [spec] - end - what_required(req) << spec - end - - private - - def sorted - rake = @specs.find {|s| s.name == "rake" } - begin - @sorted ||= ([rake] + tsort).compact.uniq - rescue TSort::Cyclic => error - cgems = extract_circular_gems(error) - raise CyclicDependencyError, "Your bundle requires gems that depend" \ - " on each other, creating an infinite loop. Please remove either" \ - " gem '#{cgems[1]}' or gem '#{cgems[0]}' and try again." - end - end - - def extract_circular_gems(error) - if Bundler.current_ruby.mri? && Bundler.current_ruby.on_19? - error.message.scan(/(\w+) \([^)]/).flatten - else - error.message.scan(/@name="(.*?)"/).flatten - end - end - - def lookup - @lookup ||= begin - lookup = Hash.new {|h, k| h[k] = [] } - Index.sort_specs(@specs).reverse_each do |s| - lookup[s.name] << s - end - lookup - end - end - - def tsort_each_node - # MUST sort by name for backwards compatibility - @specs.sort_by(&:name).each {|s| yield s } - end - - def spec_for_dependency(dep, match_current_platform) - specs_for_platforms = lookup[dep.name] - if match_current_platform - Bundler.rubygems.platforms.reverse_each do |pl| - match = GemHelpers.select_best_platform_match(specs_for_platforms, pl) - return match if match - end - nil - else - GemHelpers.select_best_platform_match(specs_for_platforms, dep.__platform) - end - end - - def tsort_each_child(s) - s.dependencies.sort_by(&:name).each do |d| - next if d.type == :development - lookup[d.name].each {|s2| yield s2 } - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/ssl_certs/certificate_manager.rb b/lib/ruby/stdlib/bundler/ssl_certs/certificate_manager.rb deleted file mode 100644 index 26fc38ec185..00000000000 --- a/lib/ruby/stdlib/bundler/ssl_certs/certificate_manager.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_fileutils" -require "net/https" -require "openssl" - -module Bundler - module SSLCerts - class CertificateManager - attr_reader :bundler_cert_path, :bundler_certs, :rubygems_certs - - def self.update_from!(rubygems_path) - new(rubygems_path).update! - end - - def initialize(rubygems_path = nil) - if rubygems_path - rubygems_cert_path = File.join(rubygems_path, "lib/rubygems/ssl_certs") - @rubygems_certs = certificates_in(rubygems_cert_path) - end - - @bundler_cert_path = File.expand_path("..", __FILE__) - @bundler_certs = certificates_in(bundler_cert_path) - end - - def up_to_date? - rubygems_certs.all? do |rc| - bundler_certs.find do |bc| - File.basename(bc) == File.basename(rc) && FileUtils.compare_file(bc, rc) - end - end - end - - def update! - return if up_to_date? - - FileUtils.rm bundler_certs - FileUtils.cp rubygems_certs, bundler_cert_path - end - - def connect_to(host) - http = Net::HTTP.new(host, 443) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - http.cert_store = store - http.head("/") - end - - private - - def certificates_in(path) - Dir[File.join(path, "**/*.pem")].sort - end - - def store - @store ||= begin - store = OpenSSL::X509::Store.new - bundler_certs.each do |cert| - store.add_file cert - end - store - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem b/lib/ruby/stdlib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem deleted file mode 100644 index f4ce4ca43dc..00000000000 --- a/lib/ruby/stdlib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B -AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz -yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE -38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP -AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad -DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME -HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- diff --git a/lib/ruby/stdlib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem b/lib/ruby/stdlib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem deleted file mode 100644 index 9e6810ab70c..00000000000 --- a/lib/ruby/stdlib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- diff --git a/lib/ruby/stdlib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem b/lib/ruby/stdlib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem deleted file mode 100644 index 20585f1c01e..00000000000 --- a/lib/ruby/stdlib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem +++ /dev/null @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs -IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 -MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h -bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v -dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt -H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 -uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX -mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX -a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN -E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 -WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD -VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 -Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU -cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx -IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN -AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH -YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC -Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX -c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a -mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= ------END CERTIFICATE----- diff --git a/lib/ruby/stdlib/bundler/stub_specification.rb b/lib/ruby/stdlib/bundler/stub_specification.rb deleted file mode 100644 index 0dd024024a0..00000000000 --- a/lib/ruby/stdlib/bundler/stub_specification.rb +++ /dev/null @@ -1,108 +0,0 @@ -# frozen_string_literal: true - -require "bundler/remote_specification" - -module Bundler - class StubSpecification < RemoteSpecification - def self.from_stub(stub) - return stub if stub.is_a?(Bundler::StubSpecification) - spec = new(stub.name, stub.version, stub.platform, nil) - spec.stub = stub - spec - end - - attr_accessor :stub, :ignored - - # Pre 2.2.0 did not include extension_dir - # https://github.com/rubygems/rubygems/commit/9485ca2d101b82a946d6f327f4bdcdea6d4946ea - if Bundler.rubygems.provides?(">= 2.2.0") - def source=(source) - super - # Stub has no concept of source, which means that extension_dir may be wrong - # This is the case for git-based gems. So, instead manually assign the extension dir - return unless source.respond_to?(:extension_dir_name) - path = File.join(stub.extensions_dir, source.extension_dir_name) - stub.extension_dir = File.expand_path(path) - end - end - - def to_yaml - _remote_specification.to_yaml - end - - # @!group Stub Delegates - - if Bundler.rubygems.provides?(">= 2.3") - # This is defined directly to avoid having to load every installed spec - def missing_extensions? - stub.missing_extensions? - end - end - - def activated - stub.activated - end - - def activated=(activated) - stub.instance_variable_set(:@activated, activated) - end - - def default_gem - stub.default_gem - end - - def full_gem_path - # deleted gems can have their stubs return nil, so in that case grab the - # expired path from the full spec - stub.full_gem_path || method_missing(:full_gem_path) - end - - if Bundler.rubygems.provides?(">= 2.2.0") - def full_require_paths - stub.full_require_paths - end - - # This is what we do in bundler/rubygems_ext - # full_require_paths is always implemented in >= 2.2.0 - def load_paths - full_require_paths - end - end - - def loaded_from - stub.loaded_from - end - - if Bundler.rubygems.stubs_provide_full_functionality? - def matches_for_glob(glob) - stub.matches_for_glob(glob) - end - end - - def raw_require_paths - stub.raw_require_paths - end - - private - - def _remote_specification - @_remote_specification ||= begin - rs = stub.to_spec - if rs.equal?(self) # happens when to_spec gets the spec from Gem.loaded_specs - rs = Gem::Specification.load(loaded_from) - Bundler.rubygems.stub_set_spec(stub, rs) - end - - unless rs - raise GemspecError, "The gemspec for #{full_name} at #{loaded_from}" \ - " was missing or broken. Try running `gem pristine #{name} -v #{version}`" \ - " to fix the cached spec." - end - - rs.source = source - - rs - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/templates/.document b/lib/ruby/stdlib/bundler/templates/.document deleted file mode 100644 index fb66f13c330..00000000000 --- a/lib/ruby/stdlib/bundler/templates/.document +++ /dev/null @@ -1 +0,0 @@ -# Ignore all files in this directory diff --git a/lib/ruby/stdlib/bundler/templates/Executable b/lib/ruby/stdlib/bundler/templates/Executable deleted file mode 100644 index 3e8d5b317ad..00000000000 --- a/lib/ruby/stdlib/bundler/templates/Executable +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> -# frozen_string_literal: true - -# -# This file was generated by Bundler. -# -# The application '<%= executable %>' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../<%= relative_gemfile_path %>", - Pathname.new(__FILE__).realpath) - -bundle_binstub = File.expand_path("../bundle", __FILE__) - -if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ - load(bundle_binstub) - else - abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. -Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") - end -end - -require "rubygems" -require "bundler/setup" - -load Gem.bin_path("<%= spec.name %>", "<%= executable %>") diff --git a/lib/ruby/stdlib/bundler/templates/Executable.bundler b/lib/ruby/stdlib/bundler/templates/Executable.bundler deleted file mode 100644 index eeda90b584b..00000000000 --- a/lib/ruby/stdlib/bundler/templates/Executable.bundler +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> -# frozen_string_literal: true - -# -# This file was generated by Bundler. -# -# The application '<%= executable %>' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "rubygems" - -m = Module.new do - module_function - - def invoked_as_script? - File.expand_path($0) == File.expand_path(__FILE__) - end - - def env_var_version - ENV["BUNDLER_VERSION"] - end - - def cli_arg_version - return unless invoked_as_script? # don't want to hijack other binstubs - return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` - bundler_version = nil - update_index = nil - ARGV.each_with_index do |a, i| - if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN - bundler_version = a - end - next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ - bundler_version = $1 || ">= 0.a" - update_index = i - end - bundler_version - end - - def gemfile - gemfile = ENV["BUNDLE_GEMFILE"] - return gemfile if gemfile && !gemfile.empty? - - File.expand_path("../<%= relative_gemfile_path %>", __FILE__) - end - - def lockfile - lockfile = - case File.basename(gemfile) - when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) - else "#{gemfile}.lock" - end - File.expand_path(lockfile) - end - - def lockfile_version - return unless File.file?(lockfile) - lockfile_contents = File.read(lockfile) - return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ - Regexp.last_match(1) - end - - def bundler_version - @bundler_version ||= begin - env_var_version || cli_arg_version || - lockfile_version || "#{Gem::Requirement.default}.a" - end - end - - def load_bundler! - ENV["BUNDLE_GEMFILE"] ||= gemfile - - # must dup string for RG < 1.8 compatibility - activate_bundler(bundler_version.dup) - end - - def activate_bundler(bundler_version) - if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0") - bundler_version = "< 2" - end - gem_error = activation_error_handling do - gem "bundler", bundler_version - end - return if gem_error.nil? - require_error = activation_error_handling do - require "bundler/version" - end - return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION)) - warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`" - exit 42 - end - - def activation_error_handling - yield - nil - rescue StandardError, LoadError => e - e - end -end - -m.load_bundler! - -if m.invoked_as_script? - load Gem.bin_path("<%= spec.name %>", "<%= executable %>") -end diff --git a/lib/ruby/stdlib/bundler/templates/Executable.standalone b/lib/ruby/stdlib/bundler/templates/Executable.standalone deleted file mode 100644 index 4bf0753f44d..00000000000 --- a/lib/ruby/stdlib/bundler/templates/Executable.standalone +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> -# -# This file was generated by Bundler. -# -# The application '<%= executable %>' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "pathname" -path = Pathname.new(__FILE__) -$:.unshift File.expand_path "../<%= standalone_path %>", path.realpath - -require "bundler/setup" -load File.expand_path "../<%= executable_path %>", path.realpath diff --git a/lib/ruby/stdlib/bundler/templates/Gemfile b/lib/ruby/stdlib/bundler/templates/Gemfile deleted file mode 100644 index 1afd2cce673..00000000000 --- a/lib/ruby/stdlib/bundler/templates/Gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -source "https://rubygems.org" - -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -# gem "rails" diff --git a/lib/ruby/stdlib/bundler/templates/gems.rb b/lib/ruby/stdlib/bundler/templates/gems.rb deleted file mode 100644 index 547cd6e8d9b..00000000000 --- a/lib/ruby/stdlib/bundler/templates/gems.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -# A sample gems.rb -source "https://rubygems.org" - -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -# gem "rails" diff --git a/lib/ruby/stdlib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/lib/ruby/stdlib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt deleted file mode 100644 index a3833d29d78..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at <%= config[:email] %>. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/lib/ruby/stdlib/bundler/templates/newgem/Gemfile.tt b/lib/ruby/stdlib/bundler/templates/newgem/Gemfile.tt deleted file mode 100644 index c114bd66659..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/Gemfile.tt +++ /dev/null @@ -1,6 +0,0 @@ -source "https://rubygems.org" - -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -# Specify your gem's dependencies in <%= config[:name] %>.gemspec -gemspec diff --git a/lib/ruby/stdlib/bundler/templates/newgem/LICENSE.txt.tt b/lib/ruby/stdlib/bundler/templates/newgem/LICENSE.txt.tt deleted file mode 100644 index 76ef4b0191c..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/LICENSE.txt.tt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) <%= Time.now.year %> <%= config[:author] %> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/lib/ruby/stdlib/bundler/templates/newgem/README.md.tt b/lib/ruby/stdlib/bundler/templates/newgem/README.md.tt deleted file mode 100644 index 868a0afe67f..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/README.md.tt +++ /dev/null @@ -1,47 +0,0 @@ -# <%= config[:constant_name] %> - -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. - -TODO: Delete this and the text above, and describe your gem - -## Installation - -Add this line to your application's Gemfile: - -```ruby -gem '<%= config[:name] %>' -``` - -And then execute: - - $ bundle - -Or install it yourself as: - - $ gem install <%= config[:name] %> - -## Usage - -TODO: Write usage instructions here - -## Development - -After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test].sub('mini', '').sub('rspec', 'spec') %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %> - -To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). - -## Contributing - -Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.<% end %> -<% if config[:mit] -%> - -## License - -The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). -<% end -%> -<% if config[:coc] -%> - -## Code of Conduct - -Everyone interacting in the <%= config[:constant_name] %> project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/master/CODE_OF_CONDUCT.md). -<% end -%> diff --git a/lib/ruby/stdlib/bundler/templates/newgem/Rakefile.tt b/lib/ruby/stdlib/bundler/templates/newgem/Rakefile.tt deleted file mode 100644 index 099da6f3ecd..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/Rakefile.tt +++ /dev/null @@ -1,29 +0,0 @@ -require "bundler/gem_tasks" -<% if config[:test] == "minitest" -%> -require "rake/testtask" - -Rake::TestTask.new(:test) do |t| - t.libs << "test" - t.libs << "lib" - t.test_files = FileList["test/**/*_test.rb"] -end - -<% elsif config[:test] == "rspec" -%> -require "rspec/core/rake_task" - -RSpec::Core::RakeTask.new(:spec) - -<% end -%> -<% if config[:ext] -%> -require "rake/extensiontask" - -task :build => :compile - -Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext| - ext.lib_dir = "lib/<%= config[:namespaced_path] %>" -end - -task :default => [:clobber, :compile, :<%= config[:test_task] %>] -<% else -%> -task :default => :<%= config[:test_task] %> -<% end -%> diff --git a/lib/ruby/stdlib/bundler/templates/newgem/bin/console.tt b/lib/ruby/stdlib/bundler/templates/newgem/bin/console.tt deleted file mode 100644 index a27f82430f9..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/bin/console.tt +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ruby - -require "bundler/setup" -require "<%= config[:namespaced_path] %>" - -# You can add fixtures and/or initialization code here to make experimenting -# with your gem easier. You can also use a different console, if you like. - -# (If you use this, don't forget to add pry to your Gemfile!) -# require "pry" -# Pry.start - -require "irb" -IRB.start(__FILE__) diff --git a/lib/ruby/stdlib/bundler/templates/newgem/bin/setup.tt b/lib/ruby/stdlib/bundler/templates/newgem/bin/setup.tt deleted file mode 100644 index dce67d860af..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/bin/setup.tt +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -IFS=$'\n\t' -set -vx - -bundle install - -# Do any other automated setup that you need to do here diff --git a/lib/ruby/stdlib/bundler/templates/newgem/exe/newgem.tt b/lib/ruby/stdlib/bundler/templates/newgem/exe/newgem.tt deleted file mode 100644 index a8339bb79f5..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/exe/newgem.tt +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby - -require "<%= config[:namespaced_path] %>" diff --git a/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/extconf.rb.tt b/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/extconf.rb.tt deleted file mode 100644 index 8cfc828f94f..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +++ /dev/null @@ -1,3 +0,0 @@ -require "mkmf" - -create_makefile(<%= config[:makefile_path].inspect %>) diff --git a/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/newgem.c.tt b/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/newgem.c.tt deleted file mode 100644 index 8177c4d2021..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/newgem.c.tt +++ /dev/null @@ -1,9 +0,0 @@ -#include "<%= config[:underscored_name] %>.h" - -VALUE rb_m<%= config[:constant_array].join %>; - -void -Init_<%= config[:underscored_name] %>(void) -{ - rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>); -} diff --git a/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/newgem.h.tt b/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/newgem.h.tt deleted file mode 100644 index c6e420b66ec..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/ext/newgem/newgem.h.tt +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef <%= config[:underscored_name].upcase %>_H -#define <%= config[:underscored_name].upcase %>_H 1 - -#include "ruby.h" - -#endif /* <%= config[:underscored_name].upcase %>_H */ diff --git a/lib/ruby/stdlib/bundler/templates/newgem/gitignore.tt b/lib/ruby/stdlib/bundler/templates/newgem/gitignore.tt deleted file mode 100644 index b1c9f9986cc..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/gitignore.tt +++ /dev/null @@ -1,20 +0,0 @@ -/.bundle/ -/.yardoc -/_yardoc/ -/coverage/ -/doc/ -/pkg/ -/spec/reports/ -/tmp/ -<%- if config[:ext] -%> -*.bundle -*.so -*.o -*.a -mkmf.log -<%- end -%> -<%- if config[:test] == "rspec" -%> - -# rspec failure tracking -.rspec_status -<%- end -%> diff --git a/lib/ruby/stdlib/bundler/templates/newgem/lib/newgem.rb.tt b/lib/ruby/stdlib/bundler/templates/newgem/lib/newgem.rb.tt deleted file mode 100644 index fae6337c3e6..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/lib/newgem.rb.tt +++ /dev/null @@ -1,13 +0,0 @@ -require "<%= config[:namespaced_path] %>/version" -<%- if config[:ext] -%> -require "<%= config[:namespaced_path] %>/<%= config[:underscored_name] %>" -<%- end -%> - -<%- config[:constant_array].each_with_index do |c, i| -%> -<%= " " * i %>module <%= c %> -<%- end -%> -<%= " " * config[:constant_array].size %>class Error < StandardError; end -<%= " " * config[:constant_array].size %># Your code goes here... -<%- (config[:constant_array].size-1).downto(0) do |i| -%> -<%= " " * i %>end -<%- end -%> diff --git a/lib/ruby/stdlib/bundler/templates/newgem/lib/newgem/version.rb.tt b/lib/ruby/stdlib/bundler/templates/newgem/lib/newgem/version.rb.tt deleted file mode 100644 index 389daf5048d..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/lib/newgem/version.rb.tt +++ /dev/null @@ -1,7 +0,0 @@ -<%- config[:constant_array].each_with_index do |c, i| -%> -<%= " " * i %>module <%= c %> -<%- end -%> -<%= " " * config[:constant_array].size %>VERSION = "0.1.0" -<%- (config[:constant_array].size-1).downto(0) do |i| -%> -<%= " " * i %>end -<%- end -%> diff --git a/lib/ruby/stdlib/bundler/templates/newgem/newgem.gemspec.tt b/lib/ruby/stdlib/bundler/templates/newgem/newgem.gemspec.tt deleted file mode 100644 index faf6f7bbc5e..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/newgem.gemspec.tt +++ /dev/null @@ -1,55 +0,0 @@ -<%- if RUBY_VERSION < "2.0.0" -%> -# coding: utf-8 -<%- end -%> - -lib = File.expand_path("../lib", __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require "<%= config[:namespaced_path] %>/version" - -Gem::Specification.new do |spec| - spec.name = <%= config[:name].inspect %> - spec.version = <%= config[:constant_name] %>::VERSION - spec.authors = [<%= config[:author].inspect %>] - spec.email = [<%= config[:email].inspect %>] - - spec.summary = %q{TODO: Write a short summary, because RubyGems requires one.} - spec.description = %q{TODO: Write a longer description or delete this line.} - spec.homepage = "TODO: Put your gem's website or public repo URL here." -<%- if config[:mit] -%> - spec.license = "MIT" -<%- end -%> - - # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' - # to allow pushing to a single host or delete this section to allow pushing to any host. - if spec.respond_to?(:metadata) - spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" - - spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." - spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." - else - raise "RubyGems 2.0 or newer is required to protect against " \ - "public gem pushes." - end - - # Specify which files should be added to the gem when it is released. - # The `git ls-files -z` loads the files in the RubyGem that have been added into git. - spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - end - spec.bindir = "exe" - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } - spec.require_paths = ["lib"] -<%- if config[:ext] -%> - spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] -<%- end -%> - - spec.add_development_dependency "bundler", "~> <%= config[:bundler_version] %>" - spec.add_development_dependency "rake", "~> 10.0" -<%- if config[:ext] -%> - spec.add_development_dependency "rake-compiler" -<%- end -%> -<%- if config[:test] -%> - spec.add_development_dependency "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>" -<%- end -%> -end diff --git a/lib/ruby/stdlib/bundler/templates/newgem/rspec.tt b/lib/ruby/stdlib/bundler/templates/newgem/rspec.tt deleted file mode 100644 index 34c5164d9b5..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/rspec.tt +++ /dev/null @@ -1,3 +0,0 @@ ---format documentation ---color ---require spec_helper diff --git a/lib/ruby/stdlib/bundler/templates/newgem/spec/newgem_spec.rb.tt b/lib/ruby/stdlib/bundler/templates/newgem/spec/newgem_spec.rb.tt deleted file mode 100644 index c63b4878306..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/spec/newgem_spec.rb.tt +++ /dev/null @@ -1,9 +0,0 @@ -RSpec.describe <%= config[:constant_name] %> do - it "has a version number" do - expect(<%= config[:constant_name] %>::VERSION).not_to be nil - end - - it "does something useful" do - expect(false).to eq(true) - end -end diff --git a/lib/ruby/stdlib/bundler/templates/newgem/spec/spec_helper.rb.tt b/lib/ruby/stdlib/bundler/templates/newgem/spec/spec_helper.rb.tt deleted file mode 100644 index 805cf57e011..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/spec/spec_helper.rb.tt +++ /dev/null @@ -1,14 +0,0 @@ -require "bundler/setup" -require "<%= config[:namespaced_path] %>" - -RSpec.configure do |config| - # Enable flags like --only-failures and --next-failure - config.example_status_persistence_file_path = ".rspec_status" - - # Disable RSpec exposing methods globally on `Module` and `main` - config.disable_monkey_patching! - - config.expect_with :rspec do |c| - c.syntax = :expect - end -end diff --git a/lib/ruby/stdlib/bundler/templates/newgem/test/newgem_test.rb.tt b/lib/ruby/stdlib/bundler/templates/newgem/test/newgem_test.rb.tt deleted file mode 100644 index f2af9f90e0b..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/test/newgem_test.rb.tt +++ /dev/null @@ -1,11 +0,0 @@ -require "test_helper" - -class <%= config[:constant_name] %>Test < Minitest::Test - def test_that_it_has_a_version_number - refute_nil ::<%= config[:constant_name] %>::VERSION - end - - def test_it_does_something_useful - assert false - end -end diff --git a/lib/ruby/stdlib/bundler/templates/newgem/test/test_helper.rb.tt b/lib/ruby/stdlib/bundler/templates/newgem/test/test_helper.rb.tt deleted file mode 100644 index 725e3e46473..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/test/test_helper.rb.tt +++ /dev/null @@ -1,4 +0,0 @@ -$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) -require "<%= config[:namespaced_path] %>" - -require "minitest/autorun" diff --git a/lib/ruby/stdlib/bundler/templates/newgem/travis.yml.tt b/lib/ruby/stdlib/bundler/templates/newgem/travis.yml.tt deleted file mode 100644 index 7a3381a8890..00000000000 --- a/lib/ruby/stdlib/bundler/templates/newgem/travis.yml.tt +++ /dev/null @@ -1,7 +0,0 @@ ---- -sudo: false -language: ruby -cache: bundler -rvm: - - <%= RUBY_VERSION %> -before_install: gem install bundler -v <%= Bundler::VERSION %> diff --git a/lib/ruby/stdlib/bundler/ui.rb b/lib/ruby/stdlib/bundler/ui.rb deleted file mode 100644 index 8138b30d389..00000000000 --- a/lib/ruby/stdlib/bundler/ui.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module UI - autoload :RGProxy, "bundler/ui/rg_proxy" - autoload :Shell, "bundler/ui/shell" - autoload :Silent, "bundler/ui/silent" - end -end diff --git a/lib/ruby/stdlib/bundler/ui/rg_proxy.rb b/lib/ruby/stdlib/bundler/ui/rg_proxy.rb deleted file mode 100644 index e2f98481db3..00000000000 --- a/lib/ruby/stdlib/bundler/ui/rg_proxy.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require "bundler/ui" -require "rubygems/user_interaction" - -module Bundler - module UI - class RGProxy < ::Gem::SilentUI - def initialize(ui) - @ui = ui - super() - end - - def say(message) - @ui && @ui.debug(message) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/ui/shell.rb b/lib/ruby/stdlib/bundler/ui/shell.rb deleted file mode 100644 index 16e3d157137..00000000000 --- a/lib/ruby/stdlib/bundler/ui/shell.rb +++ /dev/null @@ -1,146 +0,0 @@ -# frozen_string_literal: true - -require "bundler/vendored_thor" - -module Bundler - module UI - class Shell - LEVELS = %w[silent error warn confirm info debug].freeze - - attr_writer :shell - - def initialize(options = {}) - if options["no-color"] || !$stdout.tty? - Thor::Base.shell = Thor::Shell::Basic - end - @shell = Thor::Base.shell.new - @level = ENV["DEBUG"] ? "debug" : "info" - @warning_history = [] - end - - def add_color(string, *color) - @shell.set_color(string, *color) - end - - def info(msg, newline = nil) - tell_me(msg, nil, newline) if level("info") - end - - def confirm(msg, newline = nil) - tell_me(msg, :green, newline) if level("confirm") - end - - def warn(msg, newline = nil) - return unless level("warn") - return if @warning_history.include? msg - @warning_history << msg - - return tell_err(msg, :yellow, newline) if Bundler.feature_flag.error_on_stderr? - tell_me(msg, :yellow, newline) - end - - def error(msg, newline = nil) - return unless level("error") - return tell_err(msg, :red, newline) if Bundler.feature_flag.error_on_stderr? - tell_me(msg, :red, newline) - end - - def debug(msg, newline = nil) - tell_me(msg, nil, newline) if debug? - end - - def debug? - level("debug") - end - - def quiet? - level("quiet") - end - - def ask(msg) - @shell.ask(msg) - end - - def yes?(msg) - @shell.yes?(msg) - end - - def no? - @shell.no?(msg) - end - - def level=(level) - raise ArgumentError unless LEVELS.include?(level.to_s) - @level = level.to_s - end - - def level(name = nil) - return @level unless name - unless index = LEVELS.index(name) - raise "#{name.inspect} is not a valid level" - end - index <= LEVELS.index(@level) - end - - def trace(e, newline = nil, force = false) - return unless debug? || force - msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}" - tell_me(msg, nil, newline) - end - - def silence(&blk) - with_level("silent", &blk) - end - - def unprinted_warnings - [] - end - - private - - # valimism - def tell_me(msg, color = nil, newline = nil) - msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap] - if newline.nil? - @shell.say(msg, color) - else - @shell.say(msg, color, newline) - end - end - - def tell_err(message, color = nil, newline = nil) - return if @shell.send(:stderr).closed? - - newline ||= message.to_s !~ /( |\t)\Z/ - message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap] - - color = nil if color && !$stderr.tty? - - buffer = @shell.send(:prepare_message, message, *color) - buffer << "\n" if newline && !message.to_s.end_with?("\n") - - @shell.send(:stderr).print(buffer) - @shell.send(:stderr).flush - end - - def strip_leading_spaces(text) - spaces = text[/\A\s+/, 0] - spaces ? text.gsub(/#{spaces}/, "") : text - end - - def word_wrap(text, line_width = @shell.terminal_width) - strip_leading_spaces(text).split("\n").collect do |line| - line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line - end * "\n" - end - - def with_level(level) - original = @level - @level = level - yield - ensure - @level = original - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/ui/silent.rb b/lib/ruby/stdlib/bundler/ui/silent.rb deleted file mode 100644 index dca1b2ac86d..00000000000 --- a/lib/ruby/stdlib/bundler/ui/silent.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module UI - class Silent - attr_writer :shell - - def initialize - @warnings = [] - end - - def add_color(string, color) - string - end - - def info(message, newline = nil) - end - - def confirm(message, newline = nil) - end - - def warn(message, newline = nil) - @warnings |= [message] - end - - def error(message, newline = nil) - end - - def debug(message, newline = nil) - end - - def debug? - false - end - - def quiet? - false - end - - def ask(message) - end - - def yes?(msg) - raise "Cannot ask yes? with a silent shell" - end - - def no? - raise "Cannot ask no? with a silent shell" - end - - def level=(name) - end - - def level(name = nil) - end - - def trace(message, newline = nil, force = false) - end - - def silence - yield - end - - def unprinted_warnings - @warnings - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/uri_credentials_filter.rb b/lib/ruby/stdlib/bundler/uri_credentials_filter.rb deleted file mode 100644 index ee3692268cf..00000000000 --- a/lib/ruby/stdlib/bundler/uri_credentials_filter.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module URICredentialsFilter - module_function - - def credential_filtered_uri(uri_to_anonymize) - return uri_to_anonymize if uri_to_anonymize.nil? - uri = uri_to_anonymize.dup - uri = URI(uri.to_s) unless uri.is_a?(URI) - if uri.userinfo - # oauth authentication - if uri.password == "x-oauth-basic" || uri.password == "x" - # URI as string does not display with password if no user is set - oauth_designation = uri.password - uri.user = oauth_designation - end - uri.password = nil - end - return uri if uri_to_anonymize.is_a?(URI) - return uri.to_s if uri_to_anonymize.is_a?(String) - rescue URI::InvalidURIError # uri is not canonical uri scheme - uri - end - - def credential_filtered_string(str_to_filter, uri) - return str_to_filter if uri.nil? || str_to_filter.nil? - str_with_no_credentials = str_to_filter.dup - anonymous_uri_str = credential_filtered_uri(uri).to_s - uri_str = uri.to_s - if anonymous_uri_str != uri_str - str_with_no_credentials = str_with_no_credentials.gsub(uri_str, anonymous_uri_str) - end - str_with_no_credentials - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/ruby/stdlib/bundler/vendor/fileutils/lib/fileutils.rb deleted file mode 100644 index cc697408451..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/fileutils/lib/fileutils.rb +++ /dev/null @@ -1,1638 +0,0 @@ -# frozen_string_literal: true -# -# = fileutils.rb -# -# Copyright (c) 2000-2007 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the same terms of ruby. -# -# == module Bundler::FileUtils -# -# Namespace for several file utility methods for copying, moving, removing, etc. -# -# === Module Functions -# -# require 'bundler/vendor/fileutils/lib/fileutils' -# -# Bundler::FileUtils.cd(dir, options) -# Bundler::FileUtils.cd(dir, options) {|dir| block } -# Bundler::FileUtils.pwd() -# Bundler::FileUtils.mkdir(dir, options) -# Bundler::FileUtils.mkdir(list, options) -# Bundler::FileUtils.mkdir_p(dir, options) -# Bundler::FileUtils.mkdir_p(list, options) -# Bundler::FileUtils.rmdir(dir, options) -# Bundler::FileUtils.rmdir(list, options) -# Bundler::FileUtils.ln(target, link, options) -# Bundler::FileUtils.ln(targets, dir, options) -# Bundler::FileUtils.ln_s(target, link, options) -# Bundler::FileUtils.ln_s(targets, dir, options) -# Bundler::FileUtils.ln_sf(target, link, options) -# Bundler::FileUtils.cp(src, dest, options) -# Bundler::FileUtils.cp(list, dir, options) -# Bundler::FileUtils.cp_r(src, dest, options) -# Bundler::FileUtils.cp_r(list, dir, options) -# Bundler::FileUtils.mv(src, dest, options) -# Bundler::FileUtils.mv(list, dir, options) -# Bundler::FileUtils.rm(list, options) -# Bundler::FileUtils.rm_r(list, options) -# Bundler::FileUtils.rm_rf(list, options) -# Bundler::FileUtils.install(src, dest, options) -# Bundler::FileUtils.chmod(mode, list, options) -# Bundler::FileUtils.chmod_R(mode, list, options) -# Bundler::FileUtils.chown(user, group, list, options) -# Bundler::FileUtils.chown_R(user, group, list, options) -# Bundler::FileUtils.touch(list, options) -# -# The options parameter is a hash of options, taken from the list -# :force, :noop, :preserve, and :verbose. -# :noop means that no changes are made. The other three are obvious. -# Each method documents the options that it honours. -# -# All methods that have the concept of a "source" file or directory can take -# either one file or a list of files in that argument. See the method -# documentation for examples. -# -# There are some `low level' methods, which do not accept any option: -# -# Bundler::FileUtils.copy_entry(src, dest, preserve = false, dereference = false) -# Bundler::FileUtils.copy_file(src, dest, preserve = false, dereference = true) -# Bundler::FileUtils.copy_stream(srcstream, deststream) -# Bundler::FileUtils.remove_entry(path, force = false) -# Bundler::FileUtils.remove_entry_secure(path, force = false) -# Bundler::FileUtils.remove_file(path, force = false) -# Bundler::FileUtils.compare_file(path_a, path_b) -# Bundler::FileUtils.compare_stream(stream_a, stream_b) -# Bundler::FileUtils.uptodate?(file, cmp_list) -# -# == module Bundler::FileUtils::Verbose -# -# This module has all methods of Bundler::FileUtils module, but it outputs messages -# before acting. This equates to passing the :verbose flag to methods -# in Bundler::FileUtils. -# -# == module Bundler::FileUtils::NoWrite -# -# This module has all methods of Bundler::FileUtils module, but never changes -# files/directories. This equates to passing the :noop flag to methods -# in Bundler::FileUtils. -# -# == module Bundler::FileUtils::DryRun -# -# This module has all methods of Bundler::FileUtils module, but never changes -# files/directories. This equates to passing the :noop and -# :verbose flags to methods in Bundler::FileUtils. -# - -module Bundler::FileUtils - - def self.private_module_function(name) #:nodoc: - module_function name - private_class_method name - end - - # - # Returns the name of the current directory. - # - def pwd - Dir.pwd - end - module_function :pwd - - alias getwd pwd - module_function :getwd - - # - # Changes the current directory to the directory +dir+. - # - # If this method is called with block, resumes to the old - # working directory after the block execution finished. - # - # Bundler::FileUtils.cd('/', :verbose => true) # chdir and report it - # - # Bundler::FileUtils.cd('/') do # chdir - # # ... # do something - # end # return to original directory - # - def cd(dir, verbose: nil, &block) # :yield: dir - fu_output_message "cd #{dir}" if verbose - Dir.chdir(dir, &block) - fu_output_message 'cd -' if verbose and block - end - module_function :cd - - alias chdir cd - module_function :chdir - - # - # Returns true if +new+ is newer than all +old_list+. - # Non-existent files are older than any file. - # - # Bundler::FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \ - # system 'make hello.o' - # - def uptodate?(new, old_list) - return false unless File.exist?(new) - new_time = File.mtime(new) - old_list.each do |old| - if File.exist?(old) - return false unless new_time > File.mtime(old) - end - end - true - end - module_function :uptodate? - - def remove_trailing_slash(dir) #:nodoc: - dir == '/' ? dir : dir.chomp(?/) - end - private_module_function :remove_trailing_slash - - # - # Creates one or more directories. - # - # Bundler::FileUtils.mkdir 'test' - # Bundler::FileUtils.mkdir %w( tmp data ) - # Bundler::FileUtils.mkdir 'notexist', :noop => true # Does not really create. - # Bundler::FileUtils.mkdir 'tmp', :mode => 0700 - # - def mkdir(list, mode: nil, noop: nil, verbose: nil) - list = fu_list(list) - fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose - return if noop - - list.each do |dir| - fu_mkdir dir, mode - end - end - module_function :mkdir - - # - # Creates a directory and all its parent directories. - # For example, - # - # Bundler::FileUtils.mkdir_p '/usr/local/lib/ruby' - # - # causes to make following directories, if it does not exist. - # - # * /usr - # * /usr/local - # * /usr/local/lib - # * /usr/local/lib/ruby - # - # You can pass several directories at a time in a list. - # - def mkdir_p(list, mode: nil, noop: nil, verbose: nil) - list = fu_list(list) - fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose - return *list if noop - - list.map {|path| remove_trailing_slash(path)}.each do |path| - # optimize for the most common case - begin - fu_mkdir path, mode - next - rescue SystemCallError - next if File.directory?(path) - end - - stack = [] - until path == stack.last # dirname("/")=="/", dirname("C:/")=="C:/" - stack.push path - path = File.dirname(path) - end - stack.pop # root directory should exist - stack.reverse_each do |dir| - begin - fu_mkdir dir, mode - rescue SystemCallError - raise unless File.directory?(dir) - end - end - end - - return *list - end - module_function :mkdir_p - - alias mkpath mkdir_p - alias makedirs mkdir_p - module_function :mkpath - module_function :makedirs - - def fu_mkdir(path, mode) #:nodoc: - path = remove_trailing_slash(path) - if mode - Dir.mkdir path, mode - File.chmod mode, path - else - Dir.mkdir path - end - end - private_module_function :fu_mkdir - - # - # Removes one or more directories. - # - # Bundler::FileUtils.rmdir 'somedir' - # Bundler::FileUtils.rmdir %w(somedir anydir otherdir) - # # Does not really remove directory; outputs message. - # Bundler::FileUtils.rmdir 'somedir', :verbose => true, :noop => true - # - def rmdir(list, parents: nil, noop: nil, verbose: nil) - list = fu_list(list) - fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose - return if noop - list.each do |dir| - begin - Dir.rmdir(dir = remove_trailing_slash(dir)) - if parents - until (parent = File.dirname(dir)) == '.' or parent == dir - dir = parent - Dir.rmdir(dir) - end - end - rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT - end - end - end - module_function :rmdir - - # - # :call-seq: - # Bundler::FileUtils.ln(target, link, force: nil, noop: nil, verbose: nil) - # Bundler::FileUtils.ln(target, dir, force: nil, noop: nil, verbose: nil) - # Bundler::FileUtils.ln(targets, dir, force: nil, noop: nil, verbose: nil) - # - # In the first form, creates a hard link +link+ which points to +target+. - # If +link+ already exists, raises Errno::EEXIST. - # But if the :force option is set, overwrites +link+. - # - # Bundler::FileUtils.ln 'gcc', 'cc', verbose: true - # Bundler::FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs' - # - # In the second form, creates a link +dir/target+ pointing to +target+. - # In the third form, creates several hard links in the directory +dir+, - # pointing to each item in +targets+. - # If +dir+ is not a directory, raises Errno::ENOTDIR. - # - # Bundler::FileUtils.cd '/sbin' - # Bundler::FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked. - # - def ln(src, dest, force: nil, noop: nil, verbose: nil) - fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose - return if noop - fu_each_src_dest0(src, dest) do |s,d| - remove_file d, true if force - File.link s, d - end - end - module_function :ln - - alias link ln - module_function :link - - # - # :call-seq: - # Bundler::FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil) - # Bundler::FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil) - # Bundler::FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil) - # - # In the first form, creates a symbolic link +link+ which points to +target+. - # If +link+ already exists, raises Errno::EEXIST. - # But if the :force option is set, overwrites +link+. - # - # Bundler::FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby' - # Bundler::FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true - # - # In the second form, creates a link +dir/target+ pointing to +target+. - # In the third form, creates several symbolic links in the directory +dir+, - # pointing to each item in +targets+. - # If +dir+ is not a directory, raises Errno::ENOTDIR. - # - # Bundler::FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin' - # - def ln_s(src, dest, force: nil, noop: nil, verbose: nil) - fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose - return if noop - fu_each_src_dest0(src, dest) do |s,d| - remove_file d, true if force - File.symlink s, d - end - end - module_function :ln_s - - alias symlink ln_s - module_function :symlink - - # - # :call-seq: - # Bundler::FileUtils.ln_sf(*args) - # - # Same as - # - # Bundler::FileUtils.ln_s(*args, force: true) - # - def ln_sf(src, dest, noop: nil, verbose: nil) - ln_s src, dest, force: true, noop: noop, verbose: verbose - end - module_function :ln_sf - - # - # Copies a file content +src+ to +dest+. If +dest+ is a directory, - # copies +src+ to +dest/src+. - # - # If +src+ is a list of files, then +dest+ must be a directory. - # - # Bundler::FileUtils.cp 'eval.c', 'eval.c.org' - # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6' - # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', :verbose => true - # Bundler::FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink - # - def cp(src, dest, preserve: nil, noop: nil, verbose: nil) - fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose - return if noop - fu_each_src_dest(src, dest) do |s, d| - copy_file s, d, preserve - end - end - module_function :cp - - alias copy cp - module_function :copy - - # - # Copies +src+ to +dest+. If +src+ is a directory, this method copies - # all its contents recursively. If +dest+ is a directory, copies - # +src+ to +dest/src+. - # - # +src+ can be a list of files. - # - # # Installing Ruby library "mylib" under the site_ruby - # Bundler::FileUtils.rm_r site_ruby + '/mylib', :force - # Bundler::FileUtils.cp_r 'lib/', site_ruby + '/mylib' - # - # # Examples of copying several files to target directory. - # Bundler::FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail' - # Bundler::FileUtils.cp_r Dir.glob('*.rb'), '/home/foo/lib/ruby', :noop => true, :verbose => true - # - # # If you want to copy all contents of a directory instead of the - # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, - # # use following code. - # Bundler::FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes dest/src, - # # but this doesn't. - # - def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, - dereference_root: true, remove_destination: nil) - fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose - return if noop - fu_each_src_dest(src, dest) do |s, d| - copy_entry s, d, preserve, dereference_root, remove_destination - end - end - module_function :cp_r - - # - # Copies a file system entry +src+ to +dest+. - # If +src+ is a directory, this method copies its contents recursively. - # This method preserves file types, c.f. symlink, directory... - # (FIFO, device files and etc. are not supported yet) - # - # Both of +src+ and +dest+ must be a path name. - # +src+ must exist, +dest+ must not exist. - # - # If +preserve+ is true, this method preserves owner, group, and - # modified time. Permissions are copied regardless +preserve+. - # - # If +dereference_root+ is true, this method dereference tree root. - # - # If +remove_destination+ is true, this method removes each destination file before copy. - # - def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) - Entry_.new(src, nil, dereference_root).wrap_traverse(proc do |ent| - destent = Entry_.new(dest, ent.rel, false) - File.unlink destent.path if remove_destination && File.file?(destent.path) - ent.copy destent.path - end, proc do |ent| - destent = Entry_.new(dest, ent.rel, false) - ent.copy_metadata destent.path if preserve - end) - end - module_function :copy_entry - - # - # Copies file contents of +src+ to +dest+. - # Both of +src+ and +dest+ must be a path name. - # - def copy_file(src, dest, preserve = false, dereference = true) - ent = Entry_.new(src, nil, dereference) - ent.copy_file dest - ent.copy_metadata dest if preserve - end - module_function :copy_file - - # - # Copies stream +src+ to +dest+. - # +src+ must respond to #read(n) and - # +dest+ must respond to #write(str). - # - def copy_stream(src, dest) - IO.copy_stream(src, dest) - end - module_function :copy_stream - - # - # Moves file(s) +src+ to +dest+. If +file+ and +dest+ exist on the different - # disk partition, the file is copied then the original file is removed. - # - # Bundler::FileUtils.mv 'badname.rb', 'goodname.rb' - # Bundler::FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', :force => true # no error - # - # Bundler::FileUtils.mv %w(junk.txt dust.txt), '/home/foo/.trash/' - # Bundler::FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true - # - def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) - fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose - return if noop - fu_each_src_dest(src, dest) do |s, d| - destent = Entry_.new(d, nil, true) - begin - if destent.exist? - if destent.directory? - raise Errno::EEXIST, d - else - destent.remove_file if rename_cannot_overwrite_file? - end - end - begin - File.rename s, d - rescue Errno::EXDEV - copy_entry s, d, true - if secure - remove_entry_secure s, force - else - remove_entry s, force - end - end - rescue SystemCallError - raise unless force - end - end - end - module_function :mv - - alias move mv - module_function :move - - def rename_cannot_overwrite_file? #:nodoc: - /emx/ =~ RUBY_PLATFORM - end - private_module_function :rename_cannot_overwrite_file? - - # - # Remove file(s) specified in +list+. This method cannot remove directories. - # All StandardErrors are ignored when the :force option is set. - # - # Bundler::FileUtils.rm %w( junk.txt dust.txt ) - # Bundler::FileUtils.rm Dir.glob('*.so') - # Bundler::FileUtils.rm 'NotExistFile', :force => true # never raises exception - # - def rm(list, force: nil, noop: nil, verbose: nil) - list = fu_list(list) - fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose - return if noop - - list.each do |path| - remove_file path, force - end - end - module_function :rm - - alias remove rm - module_function :remove - - # - # Equivalent to - # - # Bundler::FileUtils.rm(list, :force => true) - # - def rm_f(list, noop: nil, verbose: nil) - rm list, force: true, noop: noop, verbose: verbose - end - module_function :rm_f - - alias safe_unlink rm_f - module_function :safe_unlink - - # - # remove files +list+[0] +list+[1]... If +list+[n] is a directory, - # removes its all contents recursively. This method ignores - # StandardError when :force option is set. - # - # Bundler::FileUtils.rm_r Dir.glob('/tmp/*') - # Bundler::FileUtils.rm_r 'some_dir', :force => true - # - # WARNING: This method causes local vulnerability - # if one of parent directories or removing directory tree are world - # writable (including /tmp, whose permission is 1777), and the current - # process has strong privilege such as Unix super user (root), and the - # system has symbolic link. For secure removing, read the documentation - # of #remove_entry_secure carefully, and set :secure option to true. - # Default is :secure=>false. - # - # NOTE: This method calls #remove_entry_secure if :secure option is set. - # See also #remove_entry_secure. - # - def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) - list = fu_list(list) - fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose - return if noop - list.each do |path| - if secure - remove_entry_secure path, force - else - remove_entry path, force - end - end - end - module_function :rm_r - - # - # Equivalent to - # - # Bundler::FileUtils.rm_r(list, :force => true) - # - # WARNING: This method causes local vulnerability. - # Read the documentation of #rm_r first. - # - def rm_rf(list, noop: nil, verbose: nil, secure: nil) - rm_r list, force: true, noop: noop, verbose: verbose, secure: secure - end - module_function :rm_rf - - alias rmtree rm_rf - module_function :rmtree - - # - # This method removes a file system entry +path+. +path+ shall be a - # regular file, a directory, or something. If +path+ is a directory, - # remove it recursively. This method is required to avoid TOCTTOU - # (time-of-check-to-time-of-use) local security vulnerability of #rm_r. - # #rm_r causes security hole when: - # - # * Parent directory is world writable (including /tmp). - # * Removing directory tree includes world writable directory. - # * The system has symbolic link. - # - # To avoid this security hole, this method applies special preprocess. - # If +path+ is a directory, this method chown(2) and chmod(2) all - # removing directories. This requires the current process is the - # owner of the removing whole directory tree, or is the super user (root). - # - # WARNING: You must ensure that *ALL* parent directories cannot be - # moved by other untrusted users. For example, parent directories - # should not be owned by untrusted users, and should not be world - # writable except when the sticky bit set. - # - # WARNING: Only the owner of the removing directory tree, or Unix super - # user (root) should invoke this method. Otherwise this method does not - # work. - # - # For details of this security vulnerability, see Perl's case: - # - # * http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 - # * http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452 - # - # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100]. - # - def remove_entry_secure(path, force = false) - unless fu_have_symlink? - remove_entry path, force - return - end - fullpath = File.expand_path(path) - st = File.lstat(fullpath) - unless st.directory? - File.unlink fullpath - return - end - # is a directory. - parent_st = File.stat(File.dirname(fullpath)) - unless parent_st.world_writable? - remove_entry path, force - return - end - unless parent_st.sticky? - raise ArgumentError, "parent directory is world writable, Bundler::FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})" - end - # freeze tree root - euid = Process.euid - File.open(fullpath + '/.') {|f| - unless fu_stat_identical_entry?(st, f.stat) - # symlink (TOC-to-TOU attack?) - File.unlink fullpath - return - end - f.chown euid, -1 - f.chmod 0700 - unless fu_stat_identical_entry?(st, File.lstat(fullpath)) - # TOC-to-TOU attack? - File.unlink fullpath - return - end - } - # ---- tree root is frozen ---- - root = Entry_.new(path) - root.preorder_traverse do |ent| - if ent.directory? - ent.chown euid, -1 - ent.chmod 0700 - end - end - root.postorder_traverse do |ent| - begin - ent.remove - rescue - raise unless force - end - end - rescue - raise unless force - end - module_function :remove_entry_secure - - def fu_have_symlink? #:nodoc: - File.symlink nil, nil - rescue NotImplementedError - return false - rescue TypeError - return true - end - private_module_function :fu_have_symlink? - - def fu_stat_identical_entry?(a, b) #:nodoc: - a.dev == b.dev and a.ino == b.ino - end - private_module_function :fu_stat_identical_entry? - - # - # This method removes a file system entry +path+. - # +path+ might be a regular file, a directory, or something. - # If +path+ is a directory, remove it recursively. - # - # See also #remove_entry_secure. - # - def remove_entry(path, force = false) - Entry_.new(path).postorder_traverse do |ent| - begin - ent.remove - rescue - raise unless force - end - end - rescue - raise unless force - end - module_function :remove_entry - - # - # Removes a file +path+. - # This method ignores StandardError if +force+ is true. - # - def remove_file(path, force = false) - Entry_.new(path).remove_file - rescue - raise unless force - end - module_function :remove_file - - # - # Removes a directory +dir+ and its contents recursively. - # This method ignores StandardError if +force+ is true. - # - def remove_dir(path, force = false) - remove_entry path, force # FIXME?? check if it is a directory - end - module_function :remove_dir - - # - # Returns true if the contents of a file +a+ and a file +b+ are identical. - # - # Bundler::FileUtils.compare_file('somefile', 'somefile') #=> true - # Bundler::FileUtils.compare_file('/dev/null', '/dev/urandom') #=> false - # - def compare_file(a, b) - return false unless File.size(a) == File.size(b) - File.open(a, 'rb') {|fa| - File.open(b, 'rb') {|fb| - return compare_stream(fa, fb) - } - } - end - module_function :compare_file - - alias identical? compare_file - alias cmp compare_file - module_function :identical? - module_function :cmp - - # - # Returns true if the contents of a stream +a+ and +b+ are identical. - # - def compare_stream(a, b) - bsize = fu_stream_blksize(a, b) - sa = String.new(capacity: bsize) - sb = String.new(capacity: bsize) - begin - a.read(bsize, sa) - b.read(bsize, sb) - return true if sa.empty? && sb.empty? - end while sa == sb - false - end - module_function :compare_stream - - # - # If +src+ is not same as +dest+, copies it and changes the permission - # mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+. - # This method removes destination before copy. - # - # Bundler::FileUtils.install 'ruby', '/usr/local/bin/ruby', :mode => 0755, :verbose => true - # Bundler::FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', :verbose => true - # - def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, - noop: nil, verbose: nil) - if verbose - msg = +"install -c" - msg << ' -p' if preserve - msg << ' -m ' << mode_to_s(mode) if mode - msg << " -o #{owner}" if owner - msg << " -g #{group}" if group - msg << ' ' << [src,dest].flatten.join(' ') - fu_output_message msg - end - return if noop - uid = fu_get_uid(owner) - gid = fu_get_gid(group) - fu_each_src_dest(src, dest) do |s, d| - st = File.stat(s) - unless File.exist?(d) and compare_file(s, d) - remove_file d, true - copy_file s, d - File.utime st.atime, st.mtime, d if preserve - File.chmod fu_mode(mode, st), d if mode - File.chown uid, gid, d if uid or gid - end - end - end - module_function :install - - def user_mask(target) #:nodoc: - target.each_char.inject(0) do |mask, chr| - case chr - when "u" - mask | 04700 - when "g" - mask | 02070 - when "o" - mask | 01007 - when "a" - mask | 07777 - else - raise ArgumentError, "invalid `who' symbol in file mode: #{chr}" - end - end - end - private_module_function :user_mask - - def apply_mask(mode, user_mask, op, mode_mask) #:nodoc: - case op - when '=' - (mode & ~user_mask) | (user_mask & mode_mask) - when '+' - mode | (user_mask & mode_mask) - when '-' - mode & ~(user_mask & mode_mask) - end - end - private_module_function :apply_mask - - def symbolic_modes_to_i(mode_sym, path) #:nodoc: - mode = if File::Stat === path - path.mode - else - File.stat(path).mode - end - mode_sym.split(/,/).inject(mode & 07777) do |current_mode, clause| - target, *actions = clause.split(/([=+-])/) - raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty? - target = 'a' if target.empty? - user_mask = user_mask(target) - actions.each_slice(2) do |op, perm| - need_apply = op == '=' - mode_mask = (perm || '').each_char.inject(0) do |mask, chr| - case chr - when "r" - mask | 0444 - when "w" - mask | 0222 - when "x" - mask | 0111 - when "X" - if FileTest.directory? path - mask | 0111 - else - mask - end - when "s" - mask | 06000 - when "t" - mask | 01000 - when "u", "g", "o" - if mask.nonzero? - current_mode = apply_mask(current_mode, user_mask, op, mask) - end - need_apply = false - copy_mask = user_mask(chr) - (current_mode & copy_mask) / (copy_mask & 0111) * (user_mask & 0111) - else - raise ArgumentError, "invalid `perm' symbol in file mode: #{chr}" - end - end - - if mode_mask.nonzero? || need_apply - current_mode = apply_mask(current_mode, user_mask, op, mode_mask) - end - end - current_mode - end - end - private_module_function :symbolic_modes_to_i - - def fu_mode(mode, path) #:nodoc: - mode.is_a?(String) ? symbolic_modes_to_i(mode, path) : mode - end - private_module_function :fu_mode - - def mode_to_s(mode) #:nodoc: - mode.is_a?(String) ? mode : "%o" % mode - end - private_module_function :mode_to_s - - # - # Changes permission bits on the named files (in +list+) to the bit pattern - # represented by +mode+. - # - # +mode+ is the symbolic and absolute mode can be used. - # - # Absolute mode is - # Bundler::FileUtils.chmod 0755, 'somecommand' - # Bundler::FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb) - # Bundler::FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true - # - # Symbolic mode is - # Bundler::FileUtils.chmod "u=wrx,go=rx", 'somecommand' - # Bundler::FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb) - # Bundler::FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', :verbose => true - # - # "a" :: is user, group, other mask. - # "u" :: is user's mask. - # "g" :: is group's mask. - # "o" :: is other's mask. - # "w" :: is write permission. - # "r" :: is read permission. - # "x" :: is execute permission. - # "X" :: - # is execute permission for directories only, must be used in conjunction with "+" - # "s" :: is uid, gid. - # "t" :: is sticky bit. - # "+" :: is added to a class given the specified mode. - # "-" :: Is removed from a given class given mode. - # "=" :: Is the exact nature of the class will be given a specified mode. - - def chmod(mode, list, noop: nil, verbose: nil) - list = fu_list(list) - fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose - return if noop - list.each do |path| - Entry_.new(path).chmod(fu_mode(mode, path)) - end - end - module_function :chmod - - # - # Changes permission bits on the named files (in +list+) - # to the bit pattern represented by +mode+. - # - # Bundler::FileUtils.chmod_R 0700, "/tmp/app.#{$$}" - # Bundler::FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}" - # - def chmod_R(mode, list, noop: nil, verbose: nil, force: nil) - list = fu_list(list) - fu_output_message sprintf('chmod -R%s %s %s', - (force ? 'f' : ''), - mode_to_s(mode), list.join(' ')) if verbose - return if noop - list.each do |root| - Entry_.new(root).traverse do |ent| - begin - ent.chmod(fu_mode(mode, ent.path)) - rescue - raise unless force - end - end - end - end - module_function :chmod_R - - # - # Changes owner and group on the named files (in +list+) - # to the user +user+ and the group +group+. +user+ and +group+ - # may be an ID (Integer/String) or a name (String). - # If +user+ or +group+ is nil, this method does not change - # the attribute. - # - # Bundler::FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby' - # Bundler::FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true - # - def chown(user, group, list, noop: nil, verbose: nil) - list = fu_list(list) - fu_output_message sprintf('chown %s %s', - (group ? "#{user}:#{group}" : user || ':'), - list.join(' ')) if verbose - return if noop - uid = fu_get_uid(user) - gid = fu_get_gid(group) - list.each do |path| - Entry_.new(path).chown uid, gid - end - end - module_function :chown - - # - # Changes owner and group on the named files (in +list+) - # to the user +user+ and the group +group+ recursively. - # +user+ and +group+ may be an ID (Integer/String) or - # a name (String). If +user+ or +group+ is nil, this - # method does not change the attribute. - # - # Bundler::FileUtils.chown_R 'www', 'www', '/var/www/htdocs' - # Bundler::FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true - # - def chown_R(user, group, list, noop: nil, verbose: nil, force: nil) - list = fu_list(list) - fu_output_message sprintf('chown -R%s %s %s', - (force ? 'f' : ''), - (group ? "#{user}:#{group}" : user || ':'), - list.join(' ')) if verbose - return if noop - uid = fu_get_uid(user) - gid = fu_get_gid(group) - list.each do |root| - Entry_.new(root).traverse do |ent| - begin - ent.chown uid, gid - rescue - raise unless force - end - end - end - end - module_function :chown_R - - begin - require 'etc' - rescue LoadError # rescue LoadError for miniruby - end - - def fu_get_uid(user) #:nodoc: - return nil unless user - case user - when Integer - user - when /\A\d+\z/ - user.to_i - else - Etc.getpwnam(user) ? Etc.getpwnam(user).uid : nil - end - end - private_module_function :fu_get_uid - - def fu_get_gid(group) #:nodoc: - return nil unless group - case group - when Integer - group - when /\A\d+\z/ - group.to_i - else - Etc.getgrnam(group) ? Etc.getgrnam(group).gid : nil - end - end - private_module_function :fu_get_gid - - # - # Updates modification time (mtime) and access time (atime) of file(s) in - # +list+. Files are created if they don't exist. - # - # Bundler::FileUtils.touch 'timestamp' - # Bundler::FileUtils.touch Dir.glob('*.c'); system 'make' - # - def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) - list = fu_list(list) - t = mtime - if verbose - fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}" - end - return if noop - list.each do |path| - created = nocreate - begin - File.utime(t, t, path) - rescue Errno::ENOENT - raise if created - File.open(path, 'a') { - ; - } - created = true - retry if t - end - end - end - module_function :touch - - private - - module StreamUtils_ - private - - def fu_windows? - /mswin|mingw|bccwin|emx/ =~ RUBY_PLATFORM - end - - def fu_copy_stream0(src, dest, blksize = nil) #:nodoc: - IO.copy_stream(src, dest) - end - - def fu_stream_blksize(*streams) - streams.each do |s| - next unless s.respond_to?(:stat) - size = fu_blksize(s.stat) - return size if size - end - fu_default_blksize() - end - - def fu_blksize(st) - s = st.blksize - return nil unless s - return nil if s == 0 - s - end - - def fu_default_blksize - 1024 - end - end - - include StreamUtils_ - extend StreamUtils_ - - class Entry_ #:nodoc: internal use only - include StreamUtils_ - - def initialize(a, b = nil, deref = false) - @prefix = @rel = @path = nil - if b - @prefix = a - @rel = b - else - @path = a - end - @deref = deref - @stat = nil - @lstat = nil - end - - def inspect - "\#<#{self.class} #{path()}>" - end - - def path - if @path - File.path(@path) - else - join(@prefix, @rel) - end - end - - def prefix - @prefix || @path - end - - def rel - @rel - end - - def dereference? - @deref - end - - def exist? - begin - lstat - true - rescue Errno::ENOENT - false - end - end - - def file? - s = lstat! - s and s.file? - end - - def directory? - s = lstat! - s and s.directory? - end - - def symlink? - s = lstat! - s and s.symlink? - end - - def chardev? - s = lstat! - s and s.chardev? - end - - def blockdev? - s = lstat! - s and s.blockdev? - end - - def socket? - s = lstat! - s and s.socket? - end - - def pipe? - s = lstat! - s and s.pipe? - end - - S_IF_DOOR = 0xD000 - - def door? - s = lstat! - s and (s.mode & 0xF000 == S_IF_DOOR) - end - - def entries - opts = {} - opts[:encoding] = ::Encoding::UTF_8 if fu_windows? - Dir.entries(path(), opts)\ - .reject {|n| n == '.' or n == '..' }\ - .map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) } - end - - def stat - return @stat if @stat - if lstat() and lstat().symlink? - @stat = File.stat(path()) - else - @stat = lstat() - end - @stat - end - - def stat! - return @stat if @stat - if lstat! and lstat!.symlink? - @stat = File.stat(path()) - else - @stat = lstat! - end - @stat - rescue SystemCallError - nil - end - - def lstat - if dereference? - @lstat ||= File.stat(path()) - else - @lstat ||= File.lstat(path()) - end - end - - def lstat! - lstat() - rescue SystemCallError - nil - end - - def chmod(mode) - if symlink? - File.lchmod mode, path() if have_lchmod? - else - File.chmod mode, path() - end - end - - def chown(uid, gid) - if symlink? - File.lchown uid, gid, path() if have_lchown? - else - File.chown uid, gid, path() - end - end - - def copy(dest) - lstat - case - when file? - copy_file dest - when directory? - if !File.exist?(dest) and descendant_directory?(dest, path) - raise ArgumentError, "cannot copy directory %s to itself %s" % [path, dest] - end - begin - Dir.mkdir dest - rescue - raise unless File.directory?(dest) - end - when symlink? - File.symlink File.readlink(path()), dest - when chardev? - raise "cannot handle device file" unless File.respond_to?(:mknod) - mknod dest, ?c, 0666, lstat().rdev - when blockdev? - raise "cannot handle device file" unless File.respond_to?(:mknod) - mknod dest, ?b, 0666, lstat().rdev - when socket? - raise "cannot handle socket" unless File.respond_to?(:mknod) - mknod dest, nil, lstat().mode, 0 - when pipe? - raise "cannot handle FIFO" unless File.respond_to?(:mkfifo) - mkfifo dest, 0666 - when door? - raise "cannot handle door: #{path()}" - else - raise "unknown file type: #{path()}" - end - end - - def copy_file(dest) - File.open(path()) do |s| - File.open(dest, 'wb', s.stat.mode) do |f| - IO.copy_stream(s, f) - end - end - end - - def copy_metadata(path) - st = lstat() - if !st.symlink? - File.utime st.atime, st.mtime, path - end - mode = st.mode - begin - if st.symlink? - begin - File.lchown st.uid, st.gid, path - rescue NotImplementedError - end - else - File.chown st.uid, st.gid, path - end - rescue Errno::EPERM, Errno::EACCES - # clear setuid/setgid - mode &= 01777 - end - if st.symlink? - begin - File.lchmod mode, path - rescue NotImplementedError - end - else - File.chmod mode, path - end - end - - def remove - if directory? - remove_dir1 - else - remove_file - end - end - - def remove_dir1 - platform_support { - Dir.rmdir path().chomp(?/) - } - end - - def remove_file - platform_support { - File.unlink path - } - end - - def platform_support - return yield unless fu_windows? - first_time_p = true - begin - yield - rescue Errno::ENOENT - raise - rescue => err - if first_time_p - first_time_p = false - begin - File.chmod 0700, path() # Windows does not have symlink - retry - rescue SystemCallError - end - end - raise err - end - end - - def preorder_traverse - stack = [self] - while ent = stack.pop - yield ent - stack.concat ent.entries.reverse if ent.directory? - end - end - - alias traverse preorder_traverse - - def postorder_traverse - if directory? - entries().each do |ent| - ent.postorder_traverse do |e| - yield e - end - end - end - ensure - yield self - end - - def wrap_traverse(pre, post) - pre.call self - if directory? - entries.each do |ent| - ent.wrap_traverse pre, post - end - end - post.call self - end - - private - - $fileutils_rb_have_lchmod = nil - - def have_lchmod? - # This is not MT-safe, but it does not matter. - if $fileutils_rb_have_lchmod == nil - $fileutils_rb_have_lchmod = check_have_lchmod? - end - $fileutils_rb_have_lchmod - end - - def check_have_lchmod? - return false unless File.respond_to?(:lchmod) - File.lchmod 0 - return true - rescue NotImplementedError - return false - end - - $fileutils_rb_have_lchown = nil - - def have_lchown? - # This is not MT-safe, but it does not matter. - if $fileutils_rb_have_lchown == nil - $fileutils_rb_have_lchown = check_have_lchown? - end - $fileutils_rb_have_lchown - end - - def check_have_lchown? - return false unless File.respond_to?(:lchown) - File.lchown nil, nil - return true - rescue NotImplementedError - return false - end - - def join(dir, base) - return File.path(dir) if not base or base == '.' - return File.path(base) if not dir or dir == '.' - File.join(dir, base) - end - - if File::ALT_SEPARATOR - DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)" - else - DIRECTORY_TERM = "(?=/|\\z)" - end - SYSCASE = File::FNM_SYSCASE.nonzero? ? "-i" : "" - - def descendant_directory?(descendant, ascendant) - /\A(?#{SYSCASE}:#{Regexp.quote(ascendant)})#{DIRECTORY_TERM}/ =~ File.dirname(descendant) - end - end # class Entry_ - - def fu_list(arg) #:nodoc: - [arg].flatten.map {|path| File.path(path) } - end - private_module_function :fu_list - - def fu_each_src_dest(src, dest) #:nodoc: - fu_each_src_dest0(src, dest) do |s, d| - raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d) - yield s, d - end - end - private_module_function :fu_each_src_dest - - def fu_each_src_dest0(src, dest) #:nodoc: - if tmp = Array.try_convert(src) - tmp.each do |s| - s = File.path(s) - yield s, File.join(dest, File.basename(s)) - end - else - src = File.path(src) - if File.directory?(dest) - yield src, File.join(dest, File.basename(src)) - else - yield src, File.path(dest) - end - end - end - private_module_function :fu_each_src_dest0 - - def fu_same?(a, b) #:nodoc: - File.identical?(a, b) - end - private_module_function :fu_same? - - @fileutils_output = $stderr - @fileutils_label = '' - - def fu_output_message(msg) #:nodoc: - @fileutils_output ||= $stderr - @fileutils_label ||= '' - @fileutils_output.puts @fileutils_label + msg - end - private_module_function :fu_output_message - - # This hash table holds command options. - OPT_TABLE = {} #:nodoc: internal use only - (private_instance_methods & methods(false)).inject(OPT_TABLE) {|tbl, name| - (tbl[name.to_s] = instance_method(name).parameters).map! {|t, n| n if t == :key}.compact! - tbl - } - - # - # Returns an Array of method names which have any options. - # - # p Bundler::FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...] - # - def self.commands - OPT_TABLE.keys - end - - # - # Returns an Array of option names. - # - # p Bundler::FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"] - # - def self.options - OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s } - end - - # - # Returns true if the method +mid+ have an option +opt+. - # - # p Bundler::FileUtils.have_option?(:cp, :noop) #=> true - # p Bundler::FileUtils.have_option?(:rm, :force) #=> true - # p Bundler::FileUtils.have_option?(:rm, :preserve) #=> false - # - def self.have_option?(mid, opt) - li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}" - li.include?(opt) - end - - # - # Returns an Array of option names of the method +mid+. - # - # p Bundler::FileUtils.options_of(:rm) #=> ["noop", "verbose", "force"] - # - def self.options_of(mid) - OPT_TABLE[mid.to_s].map {|sym| sym.to_s } - end - - # - # Returns an Array of method names which have the option +opt+. - # - # p Bundler::FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"] - # - def self.collect_method(opt) - OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) } - end - - LOW_METHODS = singleton_methods(false) - collect_method(:noop).map(&:intern) - module LowMethods - private - def _do_nothing(*)end - ::Bundler::FileUtils::LOW_METHODS.map {|name| alias_method name, :_do_nothing} - end - - METHODS = singleton_methods() - [:private_module_function, - :commands, :options, :have_option?, :options_of, :collect_method] - - # - # This module has all methods of Bundler::FileUtils module, but it outputs messages - # before acting. This equates to passing the :verbose flag to - # methods in Bundler::FileUtils. - # - module Verbose - include Bundler::FileUtils - @fileutils_output = $stderr - @fileutils_label = '' - names = ::Bundler::FileUtils.collect_method(:verbose) - names.each do |name| - module_eval(<<-EOS, __FILE__, __LINE__ + 1) - def #{name}(*args, **options) - super(*args, **options, verbose: true) - end - EOS - end - private(*names) - extend self - class << self - public(*::Bundler::FileUtils::METHODS) - end - end - - # - # This module has all methods of Bundler::FileUtils module, but never changes - # files/directories. This equates to passing the :noop flag - # to methods in Bundler::FileUtils. - # - module NoWrite - include Bundler::FileUtils - include LowMethods - @fileutils_output = $stderr - @fileutils_label = '' - names = ::Bundler::FileUtils.collect_method(:noop) - names.each do |name| - module_eval(<<-EOS, __FILE__, __LINE__ + 1) - def #{name}(*args, **options) - super(*args, **options, noop: true) - end - EOS - end - private(*names) - extend self - class << self - public(*::Bundler::FileUtils::METHODS) - end - end - - # - # This module has all methods of Bundler::FileUtils module, but never changes - # files/directories, with printing message before acting. - # This equates to passing the :noop and :verbose flag - # to methods in Bundler::FileUtils. - # - module DryRun - include Bundler::FileUtils - include LowMethods - @fileutils_output = $stderr - @fileutils_label = '' - names = ::Bundler::FileUtils.collect_method(:noop) - names.each do |name| - module_eval(<<-EOS, __FILE__, __LINE__ + 1) - def #{name}(*args, **options) - super(*args, **options, noop: true, verbose: true) - end - EOS - end - private(*names) - extend self - class << self - public(*::Bundler::FileUtils::METHODS) - end - end - -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo.rb deleted file mode 100644 index 9e2867144fb..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/compatibility' -require 'bundler/vendor/molinillo/lib/molinillo/gem_metadata' -require 'bundler/vendor/molinillo/lib/molinillo/errors' -require 'bundler/vendor/molinillo/lib/molinillo/resolver' -require 'bundler/vendor/molinillo/lib/molinillo/modules/ui' -require 'bundler/vendor/molinillo/lib/molinillo/modules/specification_provider' - -# Bundler::Molinillo is a generic dependency resolution algorithm. -module Bundler::Molinillo -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb deleted file mode 100644 index 3eba8e4083f..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # Hacks needed for old Ruby versions. - module Compatibility - module_function - - if [].respond_to?(:flat_map) - # Flat map - # @param [Enumerable] enum an enumerable object - # @block the block to flat-map with - # @return The enum, flat-mapped - def flat_map(enum, &blk) - enum.flat_map(&blk) - end - else - # Flat map - # @param [Enumerable] enum an enumerable object - # @block the block to flat-map with - # @return The enum, flat-mapped - def flat_map(enum, &blk) - enum.map(&blk).flatten(1) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb deleted file mode 100644 index bcacf35243b..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # @!visibility private - module Delegates - # Delegates all {Bundler::Molinillo::ResolutionState} methods to a `#state` property. - module ResolutionState - # (see Bundler::Molinillo::ResolutionState#name) - def name - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.name - end - - # (see Bundler::Molinillo::ResolutionState#requirements) - def requirements - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.requirements - end - - # (see Bundler::Molinillo::ResolutionState#activated) - def activated - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.activated - end - - # (see Bundler::Molinillo::ResolutionState#requirement) - def requirement - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.requirement - end - - # (see Bundler::Molinillo::ResolutionState#possibilities) - def possibilities - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.possibilities - end - - # (see Bundler::Molinillo::ResolutionState#depth) - def depth - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.depth - end - - # (see Bundler::Molinillo::ResolutionState#conflicts) - def conflicts - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.conflicts - end - - # (see Bundler::Molinillo::ResolutionState#unused_unwind_options) - def unused_unwind_options - current_state = state || Bundler::Molinillo::ResolutionState.empty - current_state.unused_unwind_options - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb deleted file mode 100644 index ec9c770a288..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - module Delegates - # Delegates all {Bundler::Molinillo::SpecificationProvider} methods to a - # `#specification_provider` property. - module SpecificationProvider - # (see Bundler::Molinillo::SpecificationProvider#search_for) - def search_for(dependency) - with_no_such_dependency_error_handling do - specification_provider.search_for(dependency) - end - end - - # (see Bundler::Molinillo::SpecificationProvider#dependencies_for) - def dependencies_for(specification) - with_no_such_dependency_error_handling do - specification_provider.dependencies_for(specification) - end - end - - # (see Bundler::Molinillo::SpecificationProvider#requirement_satisfied_by?) - def requirement_satisfied_by?(requirement, activated, spec) - with_no_such_dependency_error_handling do - specification_provider.requirement_satisfied_by?(requirement, activated, spec) - end - end - - # (see Bundler::Molinillo::SpecificationProvider#name_for) - def name_for(dependency) - with_no_such_dependency_error_handling do - specification_provider.name_for(dependency) - end - end - - # (see Bundler::Molinillo::SpecificationProvider#name_for_explicit_dependency_source) - def name_for_explicit_dependency_source - with_no_such_dependency_error_handling do - specification_provider.name_for_explicit_dependency_source - end - end - - # (see Bundler::Molinillo::SpecificationProvider#name_for_locking_dependency_source) - def name_for_locking_dependency_source - with_no_such_dependency_error_handling do - specification_provider.name_for_locking_dependency_source - end - end - - # (see Bundler::Molinillo::SpecificationProvider#sort_dependencies) - def sort_dependencies(dependencies, activated, conflicts) - with_no_such_dependency_error_handling do - specification_provider.sort_dependencies(dependencies, activated, conflicts) - end - end - - # (see Bundler::Molinillo::SpecificationProvider#allow_missing?) - def allow_missing?(dependency) - with_no_such_dependency_error_handling do - specification_provider.allow_missing?(dependency) - end - end - - private - - # Ensures any raised {NoSuchDependencyError} has its - # {NoSuchDependencyError#required_by} set. - # @yield - def with_no_such_dependency_error_handling - yield - rescue NoSuchDependencyError => error - if state - vertex = activated.vertex_named(name_for(error.dependency)) - error.required_by += vertex.incoming_edges.map { |e| e.origin.name } - error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty? - end - raise - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb deleted file mode 100644 index 677a8bd9165..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +++ /dev/null @@ -1,223 +0,0 @@ -# frozen_string_literal: true - -require 'set' -require 'tsort' - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/log' -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex' - -module Bundler::Molinillo - # A directed acyclic graph that is tuned to hold named dependencies - class DependencyGraph - include Enumerable - - # Enumerates through the vertices of the graph. - # @return [Array] The graph's vertices. - def each - return vertices.values.each unless block_given? - vertices.values.each { |v| yield v } - end - - include TSort - - # @!visibility private - alias tsort_each_node each - - # @!visibility private - def tsort_each_child(vertex, &block) - vertex.successors.each(&block) - end - - # Topologically sorts the given vertices. - # @param [Enumerable] vertices the vertices to be sorted, which must - # all belong to the same graph. - # @return [Array] The sorted vertices. - def self.tsort(vertices) - TSort.tsort( - lambda { |b| vertices.each(&b) }, - lambda { |v, &b| (v.successors & vertices).each(&b) } - ) - end - - # A directed edge of a {DependencyGraph} - # @attr [Vertex] origin The origin of the directed edge - # @attr [Vertex] destination The destination of the directed edge - # @attr [Object] requirement The requirement the directed edge represents - Edge = Struct.new(:origin, :destination, :requirement) - - # @return [{String => Vertex}] the vertices of the dependency graph, keyed - # by {Vertex#name} - attr_reader :vertices - - # @return [Log] the op log for this graph - attr_reader :log - - # Initializes an empty dependency graph - def initialize - @vertices = {} - @log = Log.new - end - - # Tags the current state of the dependency as the given tag - # @param [Object] tag an opaque tag for the current state of the graph - # @return [Void] - def tag(tag) - log.tag(self, tag) - end - - # Rewinds the graph to the state tagged as `tag` - # @param [Object] tag the tag to rewind to - # @return [Void] - def rewind_to(tag) - log.rewind_to(self, tag) - end - - # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices} - # are properly copied. - # @param [DependencyGraph] other the graph to copy. - def initialize_copy(other) - super - @vertices = {} - @log = other.log.dup - traverse = lambda do |new_v, old_v| - return if new_v.outgoing_edges.size == old_v.outgoing_edges.size - old_v.outgoing_edges.each do |edge| - destination = add_vertex(edge.destination.name, edge.destination.payload) - add_edge_no_circular(new_v, destination, edge.requirement) - traverse.call(destination, edge.destination) - end - end - other.vertices.each do |name, vertex| - new_vertex = add_vertex(name, vertex.payload, vertex.root?) - new_vertex.explicit_requirements.replace(vertex.explicit_requirements) - traverse.call(new_vertex, vertex) - end - end - - # @return [String] a string suitable for debugging - def inspect - "#{self.class}:#{vertices.values.inspect}" - end - - # @param [Hash] options options for dot output. - # @return [String] Returns a dot format representation of the graph - def to_dot(options = {}) - edge_label = options.delete(:edge_label) - raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty? - - dot_vertices = [] - dot_edges = [] - vertices.each do |n, v| - dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]" - v.outgoing_edges.each do |e| - label = edge_label ? edge_label.call(e) : e.requirement - dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]" - end - end - - dot_vertices.uniq! - dot_vertices.sort! - dot_edges.uniq! - dot_edges.sort! - - dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}') - dot.join("\n") - end - - # @return [Boolean] whether the two dependency graphs are equal, determined - # by a recursive traversal of each {#root_vertices} and its - # {Vertex#successors} - def ==(other) - return false unless other - return true if equal?(other) - vertices.each do |name, vertex| - other_vertex = other.vertex_named(name) - return false unless other_vertex - return false unless vertex.payload == other_vertex.payload - return false unless other_vertex.successors.to_set == vertex.successors.to_set - end - end - - # @param [String] name - # @param [Object] payload - # @param [Array] parent_names - # @param [Object] requirement the requirement that is requiring the child - # @return [void] - def add_child_vertex(name, payload, parent_names, requirement) - root = !parent_names.delete(nil) { true } - vertex = add_vertex(name, payload, root) - vertex.explicit_requirements << requirement if root - parent_names.each do |parent_name| - parent_vertex = vertex_named(parent_name) - add_edge(parent_vertex, vertex, requirement) - end - vertex - end - - # Adds a vertex with the given name, or updates the existing one. - # @param [String] name - # @param [Object] payload - # @return [Vertex] the vertex that was added to `self` - def add_vertex(name, payload, root = false) - log.add_vertex(self, name, payload, root) - end - - # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively - # removing any non-root vertices that were orphaned in the process - # @param [String] name - # @return [Array] the vertices which have been detached - def detach_vertex_named(name) - log.detach_vertex_named(self, name) - end - - # @param [String] name - # @return [Vertex,nil] the vertex with the given name - def vertex_named(name) - vertices[name] - end - - # @param [String] name - # @return [Vertex,nil] the root vertex with the given name - def root_vertex_named(name) - vertex = vertex_named(name) - vertex if vertex && vertex.root? - end - - # Adds a new {Edge} to the dependency graph - # @param [Vertex] origin - # @param [Vertex] destination - # @param [Object] requirement the requirement that this edge represents - # @return [Edge] the added edge - def add_edge(origin, destination, requirement) - if destination.path_to?(origin) - raise CircularDependencyError.new([origin, destination]) - end - add_edge_no_circular(origin, destination, requirement) - end - - # Deletes an {Edge} from the dependency graph - # @param [Edge] edge - # @return [Void] - def delete_edge(edge) - log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement) - end - - # Sets the payload of the vertex with the given name - # @param [String] name the name of the vertex - # @param [Object] payload the payload - # @return [Void] - def set_payload(name, payload) - log.set_payload(self, name, payload) - end - - private - - # Adds a new {Edge} to the dependency graph without checking for - # circularity. - # @param (see #add_edge) - # @return (see #add_edge) - def add_edge_no_circular(origin, destination, requirement) - log.add_edge_no_circular(self, origin.name, destination.name, requirement) - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb deleted file mode 100644 index c04c7eec9c7..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - class DependencyGraph - # An action that modifies a {DependencyGraph} that is reversible. - # @abstract - class Action - # rubocop:disable Lint/UnusedMethodArgument - - # @return [Symbol] The name of the action. - def self.action_name - raise 'Abstract' - end - - # Performs the action on the given graph. - # @param [DependencyGraph] graph the graph to perform the action on. - # @return [Void] - def up(graph) - raise 'Abstract' - end - - # Reverses the action on the given graph. - # @param [DependencyGraph] graph the graph to reverse the action on. - # @return [Void] - def down(graph) - raise 'Abstract' - end - - # @return [Action,Nil] The previous action - attr_accessor :previous - - # @return [Action,Nil] The next action - attr_accessor :next - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb deleted file mode 100644 index 9849aea2fee..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' -module Bundler::Molinillo - class DependencyGraph - # @!visibility private - # (see DependencyGraph#add_edge_no_circular) - class AddEdgeNoCircular < Action - # @!group Action - - # (see Action.action_name) - def self.action_name - :add_vertex - end - - # (see Action#up) - def up(graph) - edge = make_edge(graph) - edge.origin.outgoing_edges << edge - edge.destination.incoming_edges << edge - edge - end - - # (see Action#down) - def down(graph) - edge = make_edge(graph) - delete_first(edge.origin.outgoing_edges, edge) - delete_first(edge.destination.incoming_edges, edge) - end - - # @!group AddEdgeNoCircular - - # @return [String] the name of the origin of the edge - attr_reader :origin - - # @return [String] the name of the destination of the edge - attr_reader :destination - - # @return [Object] the requirement that the edge represents - attr_reader :requirement - - # @param [DependencyGraph] graph the graph to find vertices from - # @return [Edge] The edge this action adds - def make_edge(graph) - Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement) - end - - # Initialize an action to add an edge to a dependency graph - # @param [String] origin the name of the origin of the edge - # @param [String] destination the name of the destination of the edge - # @param [Object] requirement the requirement that the edge represents - def initialize(origin, destination, requirement) - @origin = origin - @destination = destination - @requirement = requirement - end - - private - - def delete_first(array, item) - return unless index = array.index(item) - array.delete_at(index) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb deleted file mode 100644 index 0a1e08255bc..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' -module Bundler::Molinillo - class DependencyGraph - # @!visibility private - # (see DependencyGraph#add_vertex) - class AddVertex < Action # :nodoc: - # @!group Action - - # (see Action.action_name) - def self.action_name - :add_vertex - end - - # (see Action#up) - def up(graph) - if existing = graph.vertices[name] - @existing_payload = existing.payload - @existing_root = existing.root - end - vertex = existing || Vertex.new(name, payload) - graph.vertices[vertex.name] = vertex - vertex.payload ||= payload - vertex.root ||= root - vertex - end - - # (see Action#down) - def down(graph) - if defined?(@existing_payload) - vertex = graph.vertices[name] - vertex.payload = @existing_payload - vertex.root = @existing_root - else - graph.vertices.delete(name) - end - end - - # @!group AddVertex - - # @return [String] the name of the vertex - attr_reader :name - - # @return [Object] the payload for the vertex - attr_reader :payload - - # @return [Boolean] whether the vertex is root or not - attr_reader :root - - # Initialize an action to add a vertex to a dependency graph - # @param [String] name the name of the vertex - # @param [Object] payload the payload for the vertex - # @param [Boolean] root whether the vertex is root or not - def initialize(name, payload, root) - @name = name - @payload = payload - @root = root - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb deleted file mode 100644 index 1d9f4b327d1..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' -module Bundler::Molinillo - class DependencyGraph - # @!visibility private - # (see DependencyGraph#delete_edge) - class DeleteEdge < Action - # @!group Action - - # (see Action.action_name) - def self.action_name - :delete_edge - end - - # (see Action#up) - def up(graph) - edge = make_edge(graph) - edge.origin.outgoing_edges.delete(edge) - edge.destination.incoming_edges.delete(edge) - end - - # (see Action#down) - def down(graph) - edge = make_edge(graph) - edge.origin.outgoing_edges << edge - edge.destination.incoming_edges << edge - edge - end - - # @!group DeleteEdge - - # @return [String] the name of the origin of the edge - attr_reader :origin_name - - # @return [String] the name of the destination of the edge - attr_reader :destination_name - - # @return [Object] the requirement that the edge represents - attr_reader :requirement - - # @param [DependencyGraph] graph the graph to find vertices from - # @return [Edge] The edge this action adds - def make_edge(graph) - Edge.new( - graph.vertex_named(origin_name), - graph.vertex_named(destination_name), - requirement - ) - end - - # Initialize an action to add an edge to a dependency graph - # @param [String] origin_name the name of the origin of the edge - # @param [String] destination_name the name of the destination of the edge - # @param [Object] requirement the requirement that the edge represents - def initialize(origin_name, destination_name, requirement) - @origin_name = origin_name - @destination_name = destination_name - @requirement = requirement - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb deleted file mode 100644 index 385dcbdd064..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' -module Bundler::Molinillo - class DependencyGraph - # @!visibility private - # @see DependencyGraph#detach_vertex_named - class DetachVertexNamed < Action - # @!group Action - - # (see Action#name) - def self.action_name - :add_vertex - end - - # (see Action#up) - def up(graph) - return [] unless @vertex = graph.vertices.delete(name) - - removed_vertices = [@vertex] - @vertex.outgoing_edges.each do |e| - v = e.destination - v.incoming_edges.delete(e) - if !v.root? && v.incoming_edges.empty? - removed_vertices.concat graph.detach_vertex_named(v.name) - end - end - - @vertex.incoming_edges.each do |e| - v = e.origin - v.outgoing_edges.delete(e) - end - - removed_vertices - end - - # (see Action#down) - def down(graph) - return unless @vertex - graph.vertices[@vertex.name] = @vertex - @vertex.outgoing_edges.each do |e| - e.destination.incoming_edges << e - end - @vertex.incoming_edges.each do |e| - e.origin.outgoing_edges << e - end - end - - # @!group DetachVertexNamed - - # @return [String] the name of the vertex to detach - attr_reader :name - - # Initialize an action to detach a vertex from a dependency graph - # @param [String] name the name of the vertex to detach - def initialize(name) - @name = name - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb deleted file mode 100644 index 8582dd19c16..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +++ /dev/null @@ -1,126 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular' -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex' -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge' -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named' -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload' -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag' - -module Bundler::Molinillo - class DependencyGraph - # A log for dependency graph actions - class Log - # Initializes an empty log - def initialize - @current_action = @first_action = nil - end - - # @!macro [new] action - # {include:DependencyGraph#$0} - # @param [Graph] graph the graph to perform the action on - # @param (see DependencyGraph#$0) - # @return (see DependencyGraph#$0) - - # @macro action - def tag(graph, tag) - push_action(graph, Tag.new(tag)) - end - - # @macro action - def add_vertex(graph, name, payload, root) - push_action(graph, AddVertex.new(name, payload, root)) - end - - # @macro action - def detach_vertex_named(graph, name) - push_action(graph, DetachVertexNamed.new(name)) - end - - # @macro action - def add_edge_no_circular(graph, origin, destination, requirement) - push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement)) - end - - # {include:DependencyGraph#delete_edge} - # @param [Graph] graph the graph to perform the action on - # @param [String] origin_name - # @param [String] destination_name - # @param [Object] requirement - # @return (see DependencyGraph#delete_edge) - def delete_edge(graph, origin_name, destination_name, requirement) - push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement)) - end - - # @macro action - def set_payload(graph, name, payload) - push_action(graph, SetPayload.new(name, payload)) - end - - # Pops the most recent action from the log and undoes the action - # @param [DependencyGraph] graph - # @return [Action] the action that was popped off the log - def pop!(graph) - return unless action = @current_action - unless @current_action = action.previous - @first_action = nil - end - action.down(graph) - action - end - - extend Enumerable - - # @!visibility private - # Enumerates each action in the log - # @yield [Action] - def each - return enum_for unless block_given? - action = @first_action - loop do - break unless action - yield action - action = action.next - end - self - end - - # @!visibility private - # Enumerates each action in the log in reverse order - # @yield [Action] - def reverse_each - return enum_for(:reverse_each) unless block_given? - action = @current_action - loop do - break unless action - yield action - action = action.previous - end - self - end - - # @macro action - def rewind_to(graph, tag) - loop do - action = pop!(graph) - raise "No tag #{tag.inspect} found" unless action - break if action.class.action_name == :tag && action.tag == tag - end - end - - private - - # Adds the given action to the log, running the action - # @param [DependencyGraph] graph - # @param [Action] action - # @return The value returned by `action.up` - def push_action(graph, action) - action.previous = @current_action - @current_action.next = action if @current_action - @current_action = action - @first_action ||= action - action.up(graph) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb deleted file mode 100644 index 37286d104a3..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' -module Bundler::Molinillo - class DependencyGraph - # @!visibility private - # @see DependencyGraph#set_payload - class SetPayload < Action # :nodoc: - # @!group Action - - # (see Action.action_name) - def self.action_name - :set_payload - end - - # (see Action#up) - def up(graph) - vertex = graph.vertex_named(name) - @old_payload = vertex.payload - vertex.payload = payload - end - - # (see Action#down) - def down(graph) - graph.vertex_named(name).payload = @old_payload - end - - # @!group SetPayload - - # @return [String] the name of the vertex - attr_reader :name - - # @return [Object] the payload for the vertex - attr_reader :payload - - # Initialize an action to add set the payload for a vertex in a dependency - # graph - # @param [String] name the name of the vertex - # @param [Object] payload the payload for the vertex - def initialize(name, payload) - @name = name - @payload = payload - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb deleted file mode 100644 index d6ad16e07a2..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' -module Bundler::Molinillo - class DependencyGraph - # @!visibility private - # @see DependencyGraph#tag - class Tag < Action - # @!group Action - - # (see Action.action_name) - def self.action_name - :tag - end - - # (see Action#up) - def up(_graph) - end - - # (see Action#down) - def down(_graph) - end - - # @!group Tag - - # @return [Object] An opaque tag - attr_reader :tag - - # Initialize an action to tag a state of a dependency graph - # @param [Object] tag an opaque tag - def initialize(tag) - @tag = tag - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb deleted file mode 100644 index 7ecdc4b65a1..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +++ /dev/null @@ -1,136 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - class DependencyGraph - # A vertex in a {DependencyGraph} that encapsulates a {#name} and a - # {#payload} - class Vertex - # @return [String] the name of the vertex - attr_accessor :name - - # @return [Object] the payload the vertex holds - attr_accessor :payload - - # @return [Array] the explicit requirements that required - # this vertex - attr_reader :explicit_requirements - - # @return [Boolean] whether the vertex is considered a root vertex - attr_accessor :root - alias root? root - - # Initializes a vertex with the given name and payload. - # @param [String] name see {#name} - # @param [Object] payload see {#payload} - def initialize(name, payload) - @name = name.frozen? ? name : name.dup.freeze - @payload = payload - @explicit_requirements = [] - @outgoing_edges = [] - @incoming_edges = [] - end - - # @return [Array] all of the requirements that required - # this vertex - def requirements - (incoming_edges.map(&:requirement) + explicit_requirements).uniq - end - - # @return [Array] the edges of {#graph} that have `self` as their - # {Edge#origin} - attr_accessor :outgoing_edges - - # @return [Array] the edges of {#graph} that have `self` as their - # {Edge#destination} - attr_accessor :incoming_edges - - # @return [Array] the vertices of {#graph} that have an edge with - # `self` as their {Edge#destination} - def predecessors - incoming_edges.map(&:origin) - end - - # @return [Array] the vertices of {#graph} where `self` is a - # {#descendent?} - def recursive_predecessors - vertices = predecessors - vertices += Compatibility.flat_map(vertices, &:recursive_predecessors) - vertices.uniq! - vertices - end - - # @return [Array] the vertices of {#graph} that have an edge with - # `self` as their {Edge#origin} - def successors - outgoing_edges.map(&:destination) - end - - # @return [Array] the vertices of {#graph} where `self` is an - # {#ancestor?} - def recursive_successors - vertices = successors - vertices += Compatibility.flat_map(vertices, &:recursive_successors) - vertices.uniq! - vertices - end - - # @return [String] a string suitable for debugging - def inspect - "#{self.class}:#{name}(#{payload.inspect})" - end - - # @return [Boolean] whether the two vertices are equal, determined - # by a recursive traversal of each {Vertex#successors} - def ==(other) - return true if equal?(other) - shallow_eql?(other) && - successors.to_set == other.successors.to_set - end - - # @param [Vertex] other the other vertex to compare to - # @return [Boolean] whether the two vertices are equal, determined - # solely by {#name} and {#payload} equality - def shallow_eql?(other) - return true if equal?(other) - other && - name == other.name && - payload == other.payload - end - - alias eql? == - - # @return [Fixnum] a hash for the vertex based upon its {#name} - def hash - name.hash - end - - # Is there a path from `self` to `other` following edges in the - # dependency graph? - # @return true iff there is a path following edges within this {#graph} - def path_to?(other) - _path_to?(other) - end - - alias descendent? path_to? - - # @param [Vertex] other the vertex to check if there's a path to - # @param [Set] visited the vertices of {#graph} that have been visited - # @return [Boolean] whether there is a path to `other` from `self` - def _path_to?(other, visited = Set.new) - return false unless visited.add?(self) - return true if equal?(other) - successors.any? { |v| v._path_to?(other, visited) } - end - protected :_path_to? - - # Is there a path from `other` to `self` following edges in the - # dependency graph? - # @return true iff there is a path following edges within this {#graph} - def ancestor?(other) - other.path_to?(self) - end - - alias is_reachable_from? ancestor? - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/errors.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/errors.rb deleted file mode 100644 index ce0931f103b..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/errors.rb +++ /dev/null @@ -1,143 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # An error that occurred during the resolution process - class ResolverError < StandardError; end - - # An error caused by searching for a dependency that is completely unknown, - # i.e. has no versions available whatsoever. - class NoSuchDependencyError < ResolverError - # @return [Object] the dependency that could not be found - attr_accessor :dependency - - # @return [Array] the specifications that depended upon {#dependency} - attr_accessor :required_by - - # Initializes a new error with the given missing dependency. - # @param [Object] dependency @see {#dependency} - # @param [Array] required_by @see {#required_by} - def initialize(dependency, required_by = []) - @dependency = dependency - @required_by = required_by.uniq - super() - end - - # The error message for the missing dependency, including the specifications - # that had this dependency. - def message - sources = required_by.map { |r| "`#{r}`" }.join(' and ') - message = "Unable to find a specification for `#{dependency}`" - message += " depended upon by #{sources}" unless sources.empty? - message - end - end - - # An error caused by attempting to fulfil a dependency that was circular - # - # @note This exception will be thrown iff a {Vertex} is added to a - # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an - # existing {DependencyGraph::Vertex} - class CircularDependencyError < ResolverError - # [Set] the dependencies responsible for causing the error - attr_reader :dependencies - - # Initializes a new error with the given circular vertices. - # @param [Array] vertices the vertices in the dependency - # that caused the error - def initialize(vertices) - super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}" - @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set - end - end - - # An error caused by conflicts in version - class VersionConflict < ResolverError - # @return [{String => Resolution::Conflict}] the conflicts that caused - # resolution to fail - attr_reader :conflicts - - # @return [SpecificationProvider] the specification provider used during - # resolution - attr_reader :specification_provider - - # Initializes a new error with the given version conflicts. - # @param [{String => Resolution::Conflict}] conflicts see {#conflicts} - # @param [SpecificationProvider] specification_provider see {#specification_provider} - def initialize(conflicts, specification_provider) - pairs = [] - Compatibility.flat_map(conflicts.values.flatten, &:requirements).each do |conflicting| - conflicting.each do |source, conflict_requirements| - conflict_requirements.each do |c| - pairs << [c, source] - end - end - end - - super "Unable to satisfy the following requirements:\n\n" \ - "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}" - - @conflicts = conflicts - @specification_provider = specification_provider - end - - require 'bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider' - include Delegates::SpecificationProvider - - # @return [String] An error message that includes requirement trees, - # which is much more detailed & customizable than the default message - # @param [Hash] opts the options to create a message with. - # @option opts [String] :solver_name The user-facing name of the solver - # @option opts [String] :possibility_type The generic name of a possibility - # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees - # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements - # @option opts [Proc] :additional_message_for_conflict A proc that appends additional - # messages for each conflict - # @option opts [Proc] :version_for_spec A proc that returns the version number for a - # possibility - def message_with_trees(opts = {}) - solver_name = opts.delete(:solver_name) { self.class.name.split('::').first } - possibility_type = opts.delete(:possibility_type) { 'possibility named' } - reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } } - printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } } - additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} } - version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) } - incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do - proc do |name, _conflict| - %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":) - end - end - - conflicts.sort.reduce(''.dup) do |o, (name, conflict)| - o << "\n" << incompatible_version_message_for_conflict.call(name, conflict) << "\n" - if conflict.locked_requirement - o << %( In snapshot (#{name_for_locking_dependency_source}):\n) - o << %( #{printable_requirement.call(conflict.locked_requirement)}\n) - o << %(\n) - end - o << %( In #{name_for_explicit_dependency_source}:\n) - trees = reduce_trees.call(conflict.requirement_trees) - - o << trees.map do |tree| - t = ''.dup - depth = 2 - tree.each do |req| - t << ' ' * depth << req.to_s - unless tree.last == req - if spec = conflict.activated_by_name[name_for(req)] - t << %( was resolved to #{version_for_spec.call(spec)}, which) - end - t << %( depends on) - end - t << %(\n) - depth += 1 - end - t - end.join("\n") - - additional_message_for_conflict.call(o, name, conflict) - - o - end.strip - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb deleted file mode 100644 index 73f8fbf2ac9..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # The version of Bundler::Molinillo. - VERSION = '0.6.6'.freeze -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb deleted file mode 100644 index fa094c19818..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +++ /dev/null @@ -1,101 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # Provides information about specifcations and dependencies to the resolver, - # allowing the {Resolver} class to remain generic while still providing power - # and flexibility. - # - # This module contains the methods that users of Bundler::Molinillo must to implement, - # using knowledge of their own model classes. - module SpecificationProvider - # Search for the specifications that match the given dependency. - # The specifications in the returned array will be considered in reverse - # order, so the latest version ought to be last. - # @note This method should be 'pure', i.e. the return value should depend - # only on the `dependency` parameter. - # - # @param [Object] dependency - # @return [Array] the specifications that satisfy the given - # `dependency`. - def search_for(dependency) - [] - end - - # Returns the dependencies of `specification`. - # @note This method should be 'pure', i.e. the return value should depend - # only on the `specification` parameter. - # - # @param [Object] specification - # @return [Array] the dependencies that are required by the given - # `specification`. - def dependencies_for(specification) - [] - end - - # Determines whether the given `requirement` is satisfied by the given - # `spec`, in the context of the current `activated` dependency graph. - # - # @param [Object] requirement - # @param [DependencyGraph] activated the current dependency graph in the - # resolution process. - # @param [Object] spec - # @return [Boolean] whether `requirement` is satisfied by `spec` in the - # context of the current `activated` dependency graph. - def requirement_satisfied_by?(requirement, activated, spec) - true - end - - # Returns the name for the given `dependency`. - # @note This method should be 'pure', i.e. the return value should depend - # only on the `dependency` parameter. - # - # @param [Object] dependency - # @return [String] the name for the given `dependency`. - def name_for(dependency) - dependency.to_s - end - - # @return [String] the name of the source of explicit dependencies, i.e. - # those passed to {Resolver#resolve} directly. - def name_for_explicit_dependency_source - 'user-specified dependency' - end - - # @return [String] the name of the source of 'locked' dependencies, i.e. - # those passed to {Resolver#resolve} directly as the `base` - def name_for_locking_dependency_source - 'Lockfile' - end - - # Sort dependencies so that the ones that are easiest to resolve are first. - # Easiest to resolve is (usually) defined by: - # 1) Is this dependency already activated? - # 2) How relaxed are the requirements? - # 3) Are there any conflicts for this dependency? - # 4) How many possibilities are there to satisfy this dependency? - # - # @param [Array] dependencies - # @param [DependencyGraph] activated the current dependency graph in the - # resolution process. - # @param [{String => Array}] conflicts - # @return [Array] a sorted copy of `dependencies`. - def sort_dependencies(dependencies, activated, conflicts) - dependencies.sort_by do |dependency| - name = name_for(dependency) - [ - activated.vertex_named(name).payload ? 0 : 1, - conflicts[name] ? 0 : 1, - ] - end - end - - # Returns whether this dependency, which has no possible matching - # specifications, can safely be ignored. - # - # @param [Object] dependency - # @return [Boolean] whether this dependency can safely be skipped. - def allow_missing?(dependency) - false - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb deleted file mode 100644 index a166bc69918..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # Conveys information about the resolution process to a user. - module UI - # The {IO} object that should be used to print output. `STDOUT`, by default. - # - # @return [IO] - def output - STDOUT - end - - # Called roughly every {#progress_rate}, this method should convey progress - # to the user. - # - # @return [void] - def indicate_progress - output.print '.' unless debug? - end - - # How often progress should be conveyed to the user via - # {#indicate_progress}, in seconds. A third of a second, by default. - # - # @return [Float] - def progress_rate - 0.33 - end - - # Called before resolution begins. - # - # @return [void] - def before_resolution - output.print 'Resolving dependencies...' - end - - # Called after resolution ends (either successfully or with an error). - # By default, prints a newline. - # - # @return [void] - def after_resolution - output.puts - end - - # Conveys debug information to the user. - # - # @param [Integer] depth the current depth of the resolution process. - # @return [void] - def debug(depth = 0) - if debug? - debug_info = yield - debug_info = debug_info.inspect unless debug_info.is_a?(String) - debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" } - output.puts debug_info - end - end - - # Whether or not debug messages should be printed. - # By default, whether or not the `MOLINILLO_DEBUG` environment variable is - # set. - # - # @return [Boolean] - def debug? - return @debug_mode if defined?(@debug_mode) - @debug_mode = ENV['MOLINILLO_DEBUG'] - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/resolution.rb deleted file mode 100644 index 0eb665d17af..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +++ /dev/null @@ -1,837 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - class Resolver - # A specific resolution from a given {Resolver} - class Resolution - # A conflict that the resolution process encountered - # @attr [Object] requirement the requirement that immediately led to the conflict - # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict - # @attr [Object, nil] existing the existing spec that was in conflict with - # the {#possibility} - # @attr [Object] possibility_set the set of specs that was unable to be - # activated due to a conflict. - # @attr [Object] locked_requirement the relevant locking requirement. - # @attr [Array>] requirement_trees the different requirement - # trees that led to every requirement for the conflicting name. - # @attr [{String=>Object}] activated_by_name the already-activated specs. - # @attr [Object] underlying_error an error that has occurred during resolution, and - # will be raised at the end of it if no resolution is found. - Conflict = Struct.new( - :requirement, - :requirements, - :existing, - :possibility_set, - :locked_requirement, - :requirement_trees, - :activated_by_name, - :underlying_error - ) - - class Conflict - # @return [Object] a spec that was unable to be activated due to a conflict - def possibility - possibility_set && possibility_set.latest_version - end - end - - # A collection of possibility states that share the same dependencies - # @attr [Array] dependencies the dependencies for this set of possibilities - # @attr [Array] possibilities the possibilities - PossibilitySet = Struct.new(:dependencies, :possibilities) - - class PossibilitySet - # String representation of the possibility set, for debugging - def to_s - "[#{possibilities.join(', ')}]" - end - - # @return [Object] most up-to-date dependency in the possibility set - def latest_version - possibilities.last - end - end - - # Details of the state to unwind to when a conflict occurs, and the cause of the unwind - # @attr [Integer] state_index the index of the state to unwind to - # @attr [Object] state_requirement the requirement of the state we're unwinding to - # @attr [Array] requirement_tree for the requirement we're relaxing - # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict - # @attr [Array] requirement_trees for the conflict - # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind - UnwindDetails = Struct.new( - :state_index, - :state_requirement, - :requirement_tree, - :conflicting_requirements, - :requirement_trees, - :requirements_unwound_to_instead - ) - - class UnwindDetails - include Comparable - - # We compare UnwindDetails when choosing which state to unwind to. If - # two options have the same state_index we prefer the one most - # removed from a requirement that caused the conflict. Both options - # would unwind to the same state, but a `grandparent` option will - # filter out fewer of its possibilities after doing so - where a state - # is both a `parent` and a `grandparent` to requirements that have - # caused a conflict this is the correct behaviour. - # @param [UnwindDetail] other UnwindDetail to be compared - # @return [Integer] integer specifying ordering - def <=>(other) - if state_index > other.state_index - 1 - elsif state_index == other.state_index - reversed_requirement_tree_index <=> other.reversed_requirement_tree_index - else - -1 - end - end - - # @return [Integer] index of state requirement in reversed requirement tree - # (the conflicting requirement itself will be at position 0) - def reversed_requirement_tree_index - @reversed_requirement_tree_index ||= - if state_requirement - requirement_tree.reverse.index(state_requirement) - else - 999_999 - end - end - - # @return [Boolean] where the requirement of the state we're unwinding - # to directly caused the conflict. Note: in this case, it is - # impossible for the state we're unwinding to to be a parent of - # any of the other conflicting requirements (or we would have - # circularity) - def unwinding_to_primary_requirement? - requirement_tree.last == state_requirement - end - - # @return [Array] array of sub-dependencies to avoid when choosing a - # new possibility for the state we've unwound to. Only relevant for - # non-primary unwinds - def sub_dependencies_to_avoid - @requirements_to_avoid ||= - requirement_trees.map do |tree| - index = tree.index(state_requirement) - tree[index + 1] if index - end.compact - end - - # @return [Array] array of all the requirements that led to the need for - # this unwind - def all_requirements - @all_requirements ||= requirement_trees.flatten(1) - end - end - - # @return [SpecificationProvider] the provider that knows about - # dependencies, requirements, specifications, versions, etc. - attr_reader :specification_provider - - # @return [UI] the UI that knows how to communicate feedback about the - # resolution process back to the user - attr_reader :resolver_ui - - # @return [DependencyGraph] the base dependency graph to which - # dependencies should be 'locked' - attr_reader :base - - # @return [Array] the dependencies that were explicitly required - attr_reader :original_requested - - # Initializes a new resolution. - # @param [SpecificationProvider] specification_provider - # see {#specification_provider} - # @param [UI] resolver_ui see {#resolver_ui} - # @param [Array] requested see {#original_requested} - # @param [DependencyGraph] base see {#base} - def initialize(specification_provider, resolver_ui, requested, base) - @specification_provider = specification_provider - @resolver_ui = resolver_ui - @original_requested = requested - @base = base - @states = [] - @iteration_counter = 0 - @parents_of = Hash.new { |h, k| h[k] = [] } - end - - # Resolves the {#original_requested} dependencies into a full dependency - # graph - # @raise [ResolverError] if successful resolution is impossible - # @return [DependencyGraph] the dependency graph of successfully resolved - # dependencies - def resolve - start_resolution - - while state - break if !state.requirement && state.requirements.empty? - indicate_progress - if state.respond_to?(:pop_possibility_state) # DependencyState - debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" } - state.pop_possibility_state.tap do |s| - if s - states.push(s) - activated.tag(s) - end - end - end - process_topmost_state - end - - resolve_activated_specs - ensure - end_resolution - end - - # @return [Integer] the number of resolver iterations in between calls to - # {#resolver_ui}'s {UI#indicate_progress} method - attr_accessor :iteration_rate - private :iteration_rate - - # @return [Time] the time at which resolution began - attr_accessor :started_at - private :started_at - - # @return [Array] the stack of states for the resolution - attr_accessor :states - private :states - - private - - # Sets up the resolution process - # @return [void] - def start_resolution - @started_at = Time.now - - handle_missing_or_push_dependency_state(initial_state) - - debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" } - resolver_ui.before_resolution - end - - def resolve_activated_specs - activated.vertices.each do |_, vertex| - next unless vertex.payload - - latest_version = vertex.payload.possibilities.reverse_each.find do |possibility| - vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) } - end - - activated.set_payload(vertex.name, latest_version) - end - activated.freeze - end - - # Ends the resolution process - # @return [void] - def end_resolution - resolver_ui.after_resolution - debug do - "Finished resolution (#{@iteration_counter} steps) " \ - "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})" - end - debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state - debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state - end - - require 'bundler/vendor/molinillo/lib/molinillo/state' - require 'bundler/vendor/molinillo/lib/molinillo/modules/specification_provider' - - require 'bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state' - require 'bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider' - - include Bundler::Molinillo::Delegates::ResolutionState - include Bundler::Molinillo::Delegates::SpecificationProvider - - # Processes the topmost available {RequirementState} on the stack - # @return [void] - def process_topmost_state - if possibility - attempt_to_activate - else - create_conflict - unwind_for_conflict - end - rescue CircularDependencyError => underlying_error - create_conflict(underlying_error) - unwind_for_conflict - end - - # @return [Object] the current possibility that the resolution is trying - # to activate - def possibility - possibilities.last - end - - # @return [RequirementState] the current state the resolution is - # operating upon - def state - states.last - end - - # Creates the initial state for the resolution, based upon the - # {#requested} dependencies - # @return [DependencyState] the initial state for the resolution - def initial_state - graph = DependencyGraph.new.tap do |dg| - original_requested.each do |requested| - vertex = dg.add_vertex(name_for(requested), nil, true) - vertex.explicit_requirements << requested - end - dg.tag(:initial_state) - end - - requirements = sort_dependencies(original_requested, graph, {}) - initial_requirement = requirements.shift - DependencyState.new( - initial_requirement && name_for(initial_requirement), - requirements, - graph, - initial_requirement, - possibilities_for_requirement(initial_requirement, graph), - 0, - {}, - [] - ) - end - - # Unwinds the states stack because a conflict has been encountered - # @return [void] - def unwind_for_conflict - details_for_unwind = build_details_for_unwind - unwind_options = unused_unwind_options - debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" } - conflicts.tap do |c| - sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1) - raise_error_unless_state(c) - activated.rewind_to(sliced_states.first || :initial_state) if sliced_states - state.conflicts = c - state.unused_unwind_options = unwind_options - filter_possibilities_after_unwind(details_for_unwind) - index = states.size - 1 - @parents_of.each { |_, a| a.reject! { |i| i >= index } } - state.unused_unwind_options.reject! { |uw| uw.state_index >= index } - end - end - - # Raises a VersionConflict error, or any underlying error, if there is no - # current state - # @return [void] - def raise_error_unless_state(conflicts) - return if state - - error = conflicts.values.map(&:underlying_error).compact.first - raise error || VersionConflict.new(conflicts, specification_provider) - end - - # @return [UnwindDetails] Details of the nearest index to which we could unwind - def build_details_for_unwind - # Get the possible unwinds for the current conflict - current_conflict = conflicts[name] - binding_requirements = binding_requirements_for_conflict(current_conflict) - unwind_details = unwind_options_for_requirements(binding_requirements) - - last_detail_for_current_unwind = unwind_details.sort.last - current_detail = last_detail_for_current_unwind - - # Look for past conflicts that could be unwound to affect the - # requirement tree for the current conflict - relevant_unused_unwinds = unused_unwind_options.select do |alternative| - intersecting_requirements = - last_detail_for_current_unwind.all_requirements & - alternative.requirements_unwound_to_instead - next if intersecting_requirements.empty? - # Find the highest index unwind whilst looping through - current_detail = alternative if alternative > current_detail - alternative - end - - # Add the current unwind options to the `unused_unwind_options` array. - # The "used" option will be filtered out during `unwind_for_conflict`. - state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 } - - # Update the requirements_unwound_to_instead on any relevant unused unwinds - relevant_unused_unwinds.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } - unwind_details.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } - - current_detail - end - - # @param [Array] array of requirements that combine to create a conflict - # @return [Array] array of UnwindDetails that have a chance - # of resolving the passed requirements - def unwind_options_for_requirements(binding_requirements) - unwind_details = [] - - trees = [] - binding_requirements.reverse_each do |r| - partial_tree = [r] - trees << partial_tree - unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, []) - - # If this requirement has alternative possibilities, check if any would - # satisfy the other requirements that created this conflict - requirement_state = find_state_for(r) - if conflict_fixing_possibilities?(requirement_state, binding_requirements) - unwind_details << UnwindDetails.new( - states.index(requirement_state), - r, - partial_tree, - binding_requirements, - trees, - [] - ) - end - - # Next, look at the parent of this requirement, and check if the requirement - # could have been avoided if an alternative PossibilitySet had been chosen - parent_r = parent_of(r) - next if parent_r.nil? - partial_tree.unshift(parent_r) - requirement_state = find_state_for(parent_r) - if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) } - unwind_details << UnwindDetails.new( - states.index(requirement_state), - parent_r, - partial_tree, - binding_requirements, - trees, - [] - ) - end - - # Finally, look at the grandparent and up of this requirement, looking - # for any possibilities that wouldn't create their parent requirement - grandparent_r = parent_of(parent_r) - until grandparent_r.nil? - partial_tree.unshift(grandparent_r) - requirement_state = find_state_for(grandparent_r) - if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) } - unwind_details << UnwindDetails.new( - states.index(requirement_state), - grandparent_r, - partial_tree, - binding_requirements, - trees, - [] - ) - end - parent_r = grandparent_r - grandparent_r = parent_of(parent_r) - end - end - - unwind_details - end - - # @param [DependencyState] state - # @param [Array] array of requirements - # @return [Boolean] whether or not the given state has any possibilities - # that could satisfy the given requirements - def conflict_fixing_possibilities?(state, binding_requirements) - return false unless state - - state.possibilities.any? do |possibility_set| - possibility_set.possibilities.any? do |poss| - possibility_satisfies_requirements?(poss, binding_requirements) - end - end - end - - # Filter's a state's possibilities to remove any that would not fix the - # conflict we've just rewound from - # @param [UnwindDetails] details of the conflict just unwound from - # @return [void] - def filter_possibilities_after_unwind(unwind_details) - return unless state && !state.possibilities.empty? - - if unwind_details.unwinding_to_primary_requirement? - filter_possibilities_for_primary_unwind(unwind_details) - else - filter_possibilities_for_parent_unwind(unwind_details) - end - end - - # Filter's a state's possibilities to remove any that would not satisfy - # the requirements in the conflict we've just rewound from - # @param [UnwindDetails] details of the conflict just unwound from - # @return [void] - def filter_possibilities_for_primary_unwind(unwind_details) - unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } - unwinds_to_state << unwind_details - unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements) - - state.possibilities.reject! do |possibility_set| - possibility_set.possibilities.none? do |poss| - unwind_requirement_sets.any? do |requirements| - possibility_satisfies_requirements?(poss, requirements) - end - end - end - end - - # @param [Object] possibility a single possibility - # @param [Array] requirements an array of requirements - # @return [Boolean] whether the possibility satisfies all of the - # given requirements - def possibility_satisfies_requirements?(possibility, requirements) - name = name_for(possibility) - - activated.tag(:swap) - activated.set_payload(name, possibility) if activated.vertex_named(name) - satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) } - activated.rewind_to(:swap) - - satisfied - end - - # Filter's a state's possibilities to remove any that would (eventually) - # create a requirement in the conflict we've just rewound from - # @param [UnwindDetails] details of the conflict just unwound from - # @return [void] - def filter_possibilities_for_parent_unwind(unwind_details) - unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } - unwinds_to_state << unwind_details - - primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq - parent_unwinds = unwinds_to_state.uniq - primary_unwinds - - allowed_possibility_sets = Compatibility.flat_map(primary_unwinds) do |unwind| - states[unwind.state_index].possibilities.select do |possibility_set| - possibility_set.possibilities.any? do |poss| - possibility_satisfies_requirements?(poss, unwind.conflicting_requirements) - end - end - end - - requirements_to_avoid = Compatibility.flat_map(parent_unwinds, &:sub_dependencies_to_avoid) - - state.possibilities.reject! do |possibility_set| - !allowed_possibility_sets.include?(possibility_set) && - (requirements_to_avoid - possibility_set.dependencies).empty? - end - end - - # @param [Conflict] conflict - # @return [Array] minimal array of requirements that would cause the passed - # conflict to occur. - def binding_requirements_for_conflict(conflict) - return [conflict.requirement] if conflict.possibility.nil? - - possible_binding_requirements = conflict.requirements.values.flatten(1).uniq - - # When there’s a `CircularDependency` error the conflicting requirement - # (the one causing the circular) won’t be `conflict.requirement` - # (which won’t be for the right state, because we won’t have created it, - # because it’s circular). - # We need to make sure we have that requirement in the conflict’s list, - # otherwise we won’t be able to unwind properly, so we just return all - # the requirements for the conflict. - return possible_binding_requirements if conflict.underlying_error - - possibilities = search_for(conflict.requirement) - - # If all the requirements together don't filter out all possibilities, - # then the only two requirements we need to consider are the initial one - # (where the dependency's version was first chosen) and the last - if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities) - return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact - end - - # Loop through the possible binding requirements, removing each one - # that doesn't bind. Use a `reverse_each` as we want the earliest set of - # binding requirements, and don't use `reject!` as we wish to refine the - # array *on each iteration*. - binding_requirements = possible_binding_requirements.dup - possible_binding_requirements.reverse_each do |req| - next if req == conflict.requirement - unless binding_requirement_in_set?(req, binding_requirements, possibilities) - binding_requirements -= [req] - end - end - - binding_requirements - end - - # @param [Object] requirement we wish to check - # @param [Array] array of requirements - # @param [Array] array of possibilities the requirements will be used to filter - # @return [Boolean] whether or not the given requirement is required to filter - # out all elements of the array of possibilities. - def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities) - possibilities.any? do |poss| - possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement]) - end - end - - # @return [Object] the requirement that led to `requirement` being added - # to the list of requirements. - def parent_of(requirement) - return unless requirement - return unless index = @parents_of[requirement].last - return unless parent_state = @states[index] - parent_state.requirement - end - - # @return [Object] the requirement that led to a version of a possibility - # with the given name being activated. - def requirement_for_existing_name(name) - return nil unless vertex = activated.vertex_named(name) - return nil unless vertex.payload - states.find { |s| s.name == name }.requirement - end - - # @return [ResolutionState] the state whose `requirement` is the given - # `requirement`. - def find_state_for(requirement) - return nil unless requirement - states.find { |i| requirement == i.requirement } - end - - # @return [Conflict] a {Conflict} that reflects the failure to activate - # the {#possibility} in conjunction with the current {#state} - def create_conflict(underlying_error = nil) - vertex = activated.vertex_named(name) - locked_requirement = locked_requirement_named(name) - - requirements = {} - unless vertex.explicit_requirements.empty? - requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements - end - requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement - vertex.incoming_edges.each do |edge| - (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement) - end - - activated_by_name = {} - activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload } - conflicts[name] = Conflict.new( - requirement, - requirements, - vertex.payload && vertex.payload.latest_version, - possibility, - locked_requirement, - requirement_trees, - activated_by_name, - underlying_error - ) - end - - # @return [Array>] The different requirement - # trees that led to every requirement for the current spec. - def requirement_trees - vertex = activated.vertex_named(name) - vertex.requirements.map { |r| requirement_tree_for(r) } - end - - # @return [Array] the list of requirements that led to - # `requirement` being required. - def requirement_tree_for(requirement) - tree = [] - while requirement - tree.unshift(requirement) - requirement = parent_of(requirement) - end - tree - end - - # Indicates progress roughly once every second - # @return [void] - def indicate_progress - @iteration_counter += 1 - @progress_rate ||= resolver_ui.progress_rate - if iteration_rate.nil? - if Time.now - started_at >= @progress_rate - self.iteration_rate = @iteration_counter - end - end - - if iteration_rate && (@iteration_counter % iteration_rate) == 0 - resolver_ui.indicate_progress - end - end - - # Calls the {#resolver_ui}'s {UI#debug} method - # @param [Integer] depth the depth of the {#states} stack - # @param [Proc] block a block that yields a {#to_s} - # @return [void] - def debug(depth = 0, &block) - resolver_ui.debug(depth, &block) - end - - # Attempts to activate the current {#possibility} - # @return [void] - def attempt_to_activate - debug(depth) { 'Attempting to activate ' + possibility.to_s } - existing_vertex = activated.vertex_named(name) - if existing_vertex.payload - debug(depth) { "Found existing spec (#{existing_vertex.payload})" } - attempt_to_filter_existing_spec(existing_vertex) - else - latest = possibility.latest_version - # use reject!(!satisfied) for 1.8.7 compatibility - possibility.possibilities.reject! do |possibility| - !requirement_satisfied_by?(requirement, activated, possibility) - end - if possibility.latest_version.nil? - # ensure there's a possibility for better error messages - possibility.possibilities << latest if latest - create_conflict - unwind_for_conflict - else - activate_new_spec - end - end - end - - # Attempts to update the existing vertex's `PossibilitySet` with a filtered version - # @return [void] - def attempt_to_filter_existing_spec(vertex) - filtered_set = filtered_possibility_set(vertex) - if !filtered_set.possibilities.empty? - activated.set_payload(name, filtered_set) - new_requirements = requirements.dup - push_state_for_requirements(new_requirements, false) - else - create_conflict - debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" } - unwind_for_conflict - end - end - - # Generates a filtered version of the existing vertex's `PossibilitySet` using the - # current state's `requirement` - # @param [Object] existing vertex - # @return [PossibilitySet] filtered possibility set - def filtered_possibility_set(vertex) - PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities) - end - - # @param [String] requirement_name the spec name to search for - # @return [Object] the locked spec named `requirement_name`, if one - # is found on {#base} - def locked_requirement_named(requirement_name) - vertex = base.vertex_named(requirement_name) - vertex && vertex.payload - end - - # Add the current {#possibility} to the dependency graph of the current - # {#state} - # @return [void] - def activate_new_spec - conflicts.delete(name) - debug(depth) { "Activated #{name} at #{possibility}" } - activated.set_payload(name, possibility) - require_nested_dependencies_for(possibility) - end - - # Requires the dependencies that the recently activated spec has - # @param [Object] activated_possibility the PossibilitySet that has just been - # activated - # @return [void] - def require_nested_dependencies_for(possibility_set) - nested_dependencies = dependencies_for(possibility_set.latest_version) - debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" } - nested_dependencies.each do |d| - activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d) - parent_index = states.size - 1 - parents = @parents_of[d] - parents << parent_index if parents.empty? - end - - push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?) - end - - # Pushes a new {DependencyState} that encapsulates both existing and new - # requirements - # @param [Array] new_requirements - # @return [void] - def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) - new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort - new_requirement = nil - loop do - new_requirement = new_requirements.shift - break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement } - end - new_name = new_requirement ? name_for(new_requirement) : ''.freeze - possibilities = possibilities_for_requirement(new_requirement) - handle_missing_or_push_dependency_state DependencyState.new( - new_name, new_requirements, new_activated, - new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup - ) - end - - # Checks a proposed requirement with any existing locked requirement - # before generating an array of possibilities for it. - # @param [Object] the proposed requirement - # @return [Array] possibilities - def possibilities_for_requirement(requirement, activated = self.activated) - return [] unless requirement - if locked_requirement_named(name_for(requirement)) - return locked_requirement_possibility_set(requirement, activated) - end - - group_possibilities(search_for(requirement)) - end - - # @param [Object] the proposed requirement - # @return [Array] possibility set containing only the locked requirement, if any - def locked_requirement_possibility_set(requirement, activated = self.activated) - all_possibilities = search_for(requirement) - locked_requirement = locked_requirement_named(name_for(requirement)) - - # Longwinded way to build a possibilities array with either the locked - # requirement or nothing in it. Required, since the API for - # locked_requirement isn't guaranteed. - locked_possibilities = all_possibilities.select do |possibility| - requirement_satisfied_by?(locked_requirement, activated, possibility) - end - - group_possibilities(locked_possibilities) - end - - # Build an array of PossibilitySets, with each element representing a group of - # dependency versions that all have the same sub-dependency version constraints - # and are contiguous. - # @param [Array] an array of possibilities - # @return [Array] an array of possibility sets - def group_possibilities(possibilities) - possibility_sets = [] - current_possibility_set = nil - - possibilities.reverse_each do |possibility| - dependencies = dependencies_for(possibility) - if current_possibility_set && current_possibility_set.dependencies == dependencies - current_possibility_set.possibilities.unshift(possibility) - else - possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility])) - current_possibility_set = possibility_sets.first - end - end - - possibility_sets - end - - # Pushes a new {DependencyState}. - # If the {#specification_provider} says to - # {SpecificationProvider#allow_missing?} that particular requirement, and - # there are no possibilities for that requirement, then `state` is not - # pushed, and the vertex in {#activated} is removed, and we continue - # resolving the remaining requirements. - # @param [DependencyState] state - # @return [void] - def handle_missing_or_push_dependency_state(state) - if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement) - state.activated.detach_vertex_named(state.name) - push_state_for_requirements(state.requirements.dup, false, state.activated) - else - states.push(state).tap { activated.tag(state) } - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/resolver.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/resolver.rb deleted file mode 100644 index 7d368587780..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph' - -module Bundler::Molinillo - # This class encapsulates a dependency resolver. - # The resolver is responsible for determining which set of dependencies to - # activate, with feedback from the {#specification_provider} - # - # - class Resolver - require 'bundler/vendor/molinillo/lib/molinillo/resolution' - - # @return [SpecificationProvider] the specification provider used - # in the resolution process - attr_reader :specification_provider - - # @return [UI] the UI module used to communicate back to the user - # during the resolution process - attr_reader :resolver_ui - - # Initializes a new resolver. - # @param [SpecificationProvider] specification_provider - # see {#specification_provider} - # @param [UI] resolver_ui - # see {#resolver_ui} - def initialize(specification_provider, resolver_ui) - @specification_provider = specification_provider - @resolver_ui = resolver_ui - end - - # Resolves the requested dependencies into a {DependencyGraph}, - # locking to the base dependency graph (if specified) - # @param [Array] requested an array of 'requested' dependencies that the - # {#specification_provider} can understand - # @param [DependencyGraph,nil] base the base dependency graph to which - # dependencies should be 'locked' - def resolve(requested, base = DependencyGraph.new) - Resolution.new(specification_provider, - resolver_ui, - requested, - base). - resolve - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/state.rb b/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/state.rb deleted file mode 100644 index 68fa1f54e3e..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/molinillo/lib/molinillo/state.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # A state that a {Resolution} can be in - # @attr [String] name the name of the current requirement - # @attr [Array] requirements currently unsatisfied requirements - # @attr [DependencyGraph] activated the graph of activated dependencies - # @attr [Object] requirement the current requirement - # @attr [Object] possibilities the possibilities to satisfy the current requirement - # @attr [Integer] depth the depth of the resolution - # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name - # @attr [Array] unused_unwind_options unwinds for previous conflicts that weren't explored - ResolutionState = Struct.new( - :name, - :requirements, - :activated, - :requirement, - :possibilities, - :depth, - :conflicts, - :unused_unwind_options - ) - - class ResolutionState - # Returns an empty resolution state - # @return [ResolutionState] an empty state - def self.empty - new(nil, [], DependencyGraph.new, nil, nil, 0, {}, []) - end - end - - # A state that encapsulates a set of {#requirements} with an {Array} of - # possibilities - class DependencyState < ResolutionState - # Removes a possibility from `self` - # @return [PossibilityState] a state with a single possibility, - # the possibility that was removed from `self` - def pop_possibility_state - PossibilityState.new( - name, - requirements.dup, - activated, - requirement, - [possibilities.pop], - depth + 1, - conflicts.dup, - unused_unwind_options.dup - ).tap do |state| - state.activated.tag(state) - end - end - end - - # A state that encapsulates a single possibility to fulfill the given - # {#requirement} - class PossibilityState < ResolutionState - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb b/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb deleted file mode 100644 index e5e09080c27..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'net/protocol' - -## -# Aaron Patterson's monkeypatch (accepted into 1.9.1) to fix Net::HTTP's speed -# problems. -# -# http://gist.github.com/251244 - -class Net::BufferedIO #:nodoc: - alias :old_rbuf_fill :rbuf_fill - - def rbuf_fill - if @io.respond_to? :read_nonblock then - begin - @rbuf << @io.read_nonblock(65536) - rescue Errno::EWOULDBLOCK, Errno::EAGAIN => e - retry if IO.select [@io], nil, nil, @read_timeout - raise Timeout::Error, e.message - end - else # SSL sockets do not have read_nonblock - timeout @read_timeout do - @rbuf << @io.sysread(65536) - end - end - end -end if RUBY_VERSION < '1.9' - diff --git a/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb b/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb deleted file mode 100644 index 7cbca5bc068..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +++ /dev/null @@ -1,1233 +0,0 @@ -require 'net/http' -begin - require 'net/https' -rescue LoadError - # net/https or openssl -end if RUBY_VERSION < '1.9' # but only for 1.8 -require 'bundler/vendor/net-http-persistent/lib/net/http/faster' -require 'uri' -require 'cgi' # for escaping - -begin - require 'net/http/pipeline' -rescue LoadError -end - -autoload :OpenSSL, 'openssl' - -## -# Persistent connections for Net::HTTP -# -# Bundler::Persistent::Net::HTTP::Persistent maintains persistent connections across all the -# servers you wish to talk to. For each host:port you communicate with a -# single persistent connection is created. -# -# Multiple Bundler::Persistent::Net::HTTP::Persistent objects will share the same set of -# connections. -# -# For each thread you start a new connection will be created. A -# Bundler::Persistent::Net::HTTP::Persistent connection will not be shared across threads. -# -# You can shut down the HTTP connections when done by calling #shutdown. You -# should name your Bundler::Persistent::Net::HTTP::Persistent object if you intend to call this -# method. -# -# Example: -# -# require 'bundler/vendor/net-http-persistent/lib/net/http/persistent' -# -# uri = URI 'http://example.com/awesome/web/service' -# -# http = Bundler::Persistent::Net::HTTP::Persistent.new 'my_app_name' -# -# # perform a GET -# response = http.request uri -# -# # or -# -# get = Net::HTTP::Get.new uri.request_uri -# response = http.request get -# -# # create a POST -# post_uri = uri + 'create' -# post = Net::HTTP::Post.new post_uri.path -# post.set_form_data 'some' => 'cool data' -# -# # perform the POST, the URI is always required -# response http.request post_uri, post -# -# Note that for GET, HEAD and other requests that do not have a body you want -# to use URI#request_uri not URI#path. The request_uri contains the query -# params which are sent in the body for other requests. -# -# == SSL -# -# SSL connections are automatically created depending upon the scheme of the -# URI. SSL connections are automatically verified against the default -# certificate store for your computer. You can override this by changing -# verify_mode or by specifying an alternate cert_store. -# -# Here are the SSL settings, see the individual methods for documentation: -# -# #certificate :: This client's certificate -# #ca_file :: The certificate-authority -# #cert_store :: An SSL certificate store -# #private_key :: The client's SSL private key -# #reuse_ssl_sessions :: Reuse a previously opened SSL session for a new -# connection -# #ssl_version :: Which specific SSL version to use -# #verify_callback :: For server certificate verification -# #verify_mode :: How connections should be verified -# -# == Proxies -# -# A proxy can be set through #proxy= or at initialization time by providing a -# second argument to ::new. The proxy may be the URI of the proxy server or -# :ENV which will consult environment variables. -# -# See #proxy= and #proxy_from_env for details. -# -# == Headers -# -# Headers may be specified for use in every request. #headers are appended to -# any headers on the request. #override_headers replace existing headers on -# the request. -# -# The difference between the two can be seen in setting the User-Agent. Using -# http.headers['User-Agent'] = 'MyUserAgent' will send "Ruby, -# MyUserAgent" while http.override_headers['User-Agent'] = -# 'MyUserAgent' will send "MyUserAgent". -# -# == Tuning -# -# === Segregation -# -# By providing an application name to ::new you can separate your connections -# from the connections of other applications. -# -# === Idle Timeout -# -# If a connection hasn't been used for this number of seconds it will automatically be -# reset upon the next use to avoid attempting to send to a closed connection. -# The default value is 5 seconds. nil means no timeout. Set through #idle_timeout. -# -# Reducing this value may help avoid the "too many connection resets" error -# when sending non-idempotent requests while increasing this value will cause -# fewer round-trips. -# -# === Read Timeout -# -# The amount of time allowed between reading two chunks from the socket. Set -# through #read_timeout -# -# === Max Requests -# -# The number of requests that should be made before opening a new connection. -# Typically many keep-alive capable servers tune this to 100 or less, so the -# 101st request will fail with ECONNRESET. If unset (default), this value has no -# effect, if set, connections will be reset on the request after max_requests. -# -# === Open Timeout -# -# The amount of time to wait for a connection to be opened. Set through -# #open_timeout. -# -# === Socket Options -# -# Socket options may be set on newly-created connections. See #socket_options -# for details. -# -# === Non-Idempotent Requests -# -# By default non-idempotent requests will not be retried per RFC 2616. By -# setting retry_change_requests to true requests will automatically be retried -# once. -# -# Only do this when you know that retrying a POST or other non-idempotent -# request is safe for your application and will not create duplicate -# resources. -# -# The recommended way to handle non-idempotent requests is the following: -# -# require 'bundler/vendor/net-http-persistent/lib/net/http/persistent' -# -# uri = URI 'http://example.com/awesome/web/service' -# post_uri = uri + 'create' -# -# http = Bundler::Persistent::Net::HTTP::Persistent.new 'my_app_name' -# -# post = Net::HTTP::Post.new post_uri.path -# # ... fill in POST request -# -# begin -# response = http.request post_uri, post -# rescue Bundler::Persistent::Net::HTTP::Persistent::Error -# -# # POST failed, make a new request to verify the server did not process -# # the request -# exists_uri = uri + '...' -# response = http.get exists_uri -# -# # Retry if it failed -# retry if response.code == '404' -# end -# -# The method of determining if the resource was created or not is unique to -# the particular service you are using. Of course, you will want to add -# protection from infinite looping. -# -# === Connection Termination -# -# If you are done using the Bundler::Persistent::Net::HTTP::Persistent instance you may shut down -# all the connections in the current thread with #shutdown. This is not -# recommended for normal use, it should only be used when it will be several -# minutes before you make another HTTP request. -# -# If you are using multiple threads, call #shutdown in each thread when the -# thread is done making requests. If you don't call shutdown, that's OK. -# Ruby will automatically garbage collect and shutdown your HTTP connections -# when the thread terminates. - -class Bundler::Persistent::Net::HTTP::Persistent - - ## - # The beginning of Time - - EPOCH = Time.at 0 # :nodoc: - - ## - # Is OpenSSL available? This test works with autoload - - HAVE_OPENSSL = defined? OpenSSL::SSL # :nodoc: - - ## - # The version of Bundler::Persistent::Net::HTTP::Persistent you are using - - VERSION = '2.9.4' - - ## - # Exceptions rescued for automatic retry on ruby 2.0.0. This overlaps with - # the exception list for ruby 1.x. - - RETRIED_EXCEPTIONS = [ # :nodoc: - (Net::ReadTimeout if Net.const_defined? :ReadTimeout), - IOError, - EOFError, - Errno::ECONNRESET, - Errno::ECONNABORTED, - Errno::EPIPE, - (OpenSSL::SSL::SSLError if HAVE_OPENSSL), - Timeout::Error, - ].compact - - ## - # Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various - # SystemCallErrors are re-raised with a human-readable message under this - # class. - - class Error < StandardError; end - - ## - # Use this method to detect the idle timeout of the host at +uri+. The - # value returned can be used to configure #idle_timeout. +max+ controls the - # maximum idle timeout to detect. - # - # After - # - # Idle timeout detection is performed by creating a connection then - # performing a HEAD request in a loop until the connection terminates - # waiting one additional second per loop. - # - # NOTE: This may not work on ruby > 1.9. - - def self.detect_idle_timeout uri, max = 10 - uri = URI uri unless URI::Generic === uri - uri += '/' - - req = Net::HTTP::Head.new uri.request_uri - - http = new 'net-http-persistent detect_idle_timeout' - - connection = http.connection_for uri - - sleep_time = 0 - - loop do - response = connection.request req - - $stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG - - unless Net::HTTPOK === response then - raise Error, "bad response code #{response.code} detecting idle timeout" - end - - break if sleep_time >= max - - sleep_time += 1 - - $stderr.puts "sleeping #{sleep_time}" if $DEBUG - sleep sleep_time - end - rescue - # ignore StandardErrors, we've probably found the idle timeout. - ensure - http.shutdown - - return sleep_time unless $! - end - - ## - # This client's OpenSSL::X509::Certificate - - attr_reader :certificate - - # For Net::HTTP parity - alias cert certificate - - ## - # An SSL certificate authority. Setting this will set verify_mode to - # VERIFY_PEER. - - attr_reader :ca_file - - ## - # An SSL certificate store. Setting this will override the default - # certificate store. See verify_mode for more information. - - attr_reader :cert_store - - ## - # Sends debug_output to this IO via Net::HTTP#set_debug_output. - # - # Never use this method in production code, it causes a serious security - # hole. - - attr_accessor :debug_output - - ## - # Current connection generation - - attr_reader :generation # :nodoc: - - ## - # Where this instance's connections live in the thread local variables - - attr_reader :generation_key # :nodoc: - - ## - # Headers that are added to every request using Net::HTTP#add_field - - attr_reader :headers - - ## - # Maps host:port to an HTTP version. This allows us to enable version - # specific features. - - attr_reader :http_versions - - ## - # Maximum time an unused connection can remain idle before being - # automatically closed. - - attr_accessor :idle_timeout - - ## - # Maximum number of requests on a connection before it is considered expired - # and automatically closed. - - attr_accessor :max_requests - - ## - # The value sent in the Keep-Alive header. Defaults to 30. Not needed for - # HTTP/1.1 servers. - # - # This may not work correctly for HTTP/1.0 servers - # - # This method may be removed in a future version as RFC 2616 does not - # require this header. - - attr_accessor :keep_alive - - ## - # A name for this connection. Allows you to keep your connections apart - # from everybody else's. - - attr_reader :name - - ## - # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout - - attr_accessor :open_timeout - - ## - # Headers that are added to every request using Net::HTTP#[]= - - attr_reader :override_headers - - ## - # This client's SSL private key - - attr_reader :private_key - - # For Net::HTTP parity - alias key private_key - - ## - # The URL through which requests will be proxied - - attr_reader :proxy_uri - - ## - # List of host suffixes which will not be proxied - - attr_reader :no_proxy - - ## - # Seconds to wait until reading one block. See Net::HTTP#read_timeout - - attr_accessor :read_timeout - - ## - # Where this instance's request counts live in the thread local variables - - attr_reader :request_key # :nodoc: - - ## - # By default SSL sessions are reused to avoid extra SSL handshakes. Set - # this to false if you have problems communicating with an HTTPS server - # like: - # - # SSL_connect [...] read finished A: unexpected message (OpenSSL::SSL::SSLError) - - attr_accessor :reuse_ssl_sessions - - ## - # An array of options for Socket#setsockopt. - # - # By default the TCP_NODELAY option is set on sockets. - # - # To set additional options append them to this array: - # - # http.socket_options << [Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1] - - attr_reader :socket_options - - ## - # Current SSL connection generation - - attr_reader :ssl_generation # :nodoc: - - ## - # Where this instance's SSL connections live in the thread local variables - - attr_reader :ssl_generation_key # :nodoc: - - ## - # SSL version to use. - # - # By default, the version will be negotiated automatically between client - # and server. Ruby 1.9 and newer only. - - attr_reader :ssl_version if RUBY_VERSION > '1.9' - - ## - # Where this instance's last-use times live in the thread local variables - - attr_reader :timeout_key # :nodoc: - - ## - # SSL verification callback. Used when ca_file is set. - - attr_reader :verify_callback - - ## - # HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER which verifies - # the server certificate. - # - # If no ca_file or cert_store is set the default system certificate store is - # used. - # - # You can use +verify_mode+ to override any default values. - - attr_reader :verify_mode - - ## - # Enable retries of non-idempotent requests that change data (e.g. POST - # requests) when the server has disconnected. - # - # This will in the worst case lead to multiple requests with the same data, - # but it may be useful for some applications. Take care when enabling - # this option to ensure it is safe to POST or perform other non-idempotent - # requests to the server. - - attr_accessor :retry_change_requests - - ## - # Creates a new Bundler::Persistent::Net::HTTP::Persistent. - # - # Set +name+ to keep your connections apart from everybody else's. Not - # required currently, but highly recommended. Your library name should be - # good enough. This parameter will be required in a future version. - # - # +proxy+ may be set to a URI::HTTP or :ENV to pick up proxy options from - # the environment. See proxy_from_env for details. - # - # In order to use a URI for the proxy you may need to do some extra work - # beyond URI parsing if the proxy requires a password: - # - # proxy = URI 'http://proxy.example' - # proxy.user = 'AzureDiamond' - # proxy.password = 'hunter2' - - def initialize name = nil, proxy = nil - @name = name - - @debug_output = nil - @proxy_uri = nil - @no_proxy = [] - @headers = {} - @override_headers = {} - @http_versions = {} - @keep_alive = 30 - @open_timeout = nil - @read_timeout = nil - @idle_timeout = 5 - @max_requests = nil - @socket_options = [] - - @socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if - Socket.const_defined? :TCP_NODELAY - - key = ['net_http_persistent', name].compact - @generation_key = [key, 'generations' ].join('_').intern - @ssl_generation_key = [key, 'ssl_generations'].join('_').intern - @request_key = [key, 'requests' ].join('_').intern - @timeout_key = [key, 'timeouts' ].join('_').intern - - @certificate = nil - @ca_file = nil - @private_key = nil - @ssl_version = nil - @verify_callback = nil - @verify_mode = nil - @cert_store = nil - - @generation = 0 # incremented when proxy URI changes - @ssl_generation = 0 # incremented when SSL session variables change - - if HAVE_OPENSSL then - @verify_mode = OpenSSL::SSL::VERIFY_PEER - @reuse_ssl_sessions = OpenSSL::SSL.const_defined? :Session - end - - @retry_change_requests = false - - @ruby_1 = RUBY_VERSION < '2' - @retried_on_ruby_2 = !@ruby_1 - - self.proxy = proxy if proxy - end - - ## - # Sets this client's OpenSSL::X509::Certificate - - def certificate= certificate - @certificate = certificate - - reconnect_ssl - end - - # For Net::HTTP parity - alias cert= certificate= - - ## - # Sets the SSL certificate authority file. - - def ca_file= file - @ca_file = file - - reconnect_ssl - end - - ## - # Overrides the default SSL certificate store used for verifying - # connections. - - def cert_store= store - @cert_store = store - - reconnect_ssl - end - - ## - # Finishes all connections on the given +thread+ that were created before - # the given +generation+ in the threads +generation_key+ list. - # - # See #shutdown for a bunch of scary warning about misusing this method. - - def cleanup(generation, thread = Thread.current, - generation_key = @generation_key) # :nodoc: - timeouts = thread[@timeout_key] - - (0...generation).each do |old_generation| - next unless thread[generation_key] - - conns = thread[generation_key].delete old_generation - - conns.each_value do |conn| - finish conn, thread - - timeouts.delete conn.object_id if timeouts - end if conns - end - end - - ## - # Creates a new connection for +uri+ - - def connection_for uri - Thread.current[@generation_key] ||= Hash.new { |h,k| h[k] = {} } - Thread.current[@ssl_generation_key] ||= Hash.new { |h,k| h[k] = {} } - Thread.current[@request_key] ||= Hash.new 0 - Thread.current[@timeout_key] ||= Hash.new EPOCH - - use_ssl = uri.scheme.downcase == 'https' - - if use_ssl then - raise Bundler::Persistent::Net::HTTP::Persistent::Error, 'OpenSSL is not available' unless - HAVE_OPENSSL - - ssl_generation = @ssl_generation - - ssl_cleanup ssl_generation - - connections = Thread.current[@ssl_generation_key][ssl_generation] - else - generation = @generation - - cleanup generation - - connections = Thread.current[@generation_key][generation] - end - - net_http_args = [uri.host, uri.port] - connection_id = net_http_args.join ':' - - if @proxy_uri and not proxy_bypass? uri.host, uri.port then - connection_id << @proxy_connection_id - net_http_args.concat @proxy_args - else - net_http_args.concat [nil, nil, nil, nil] - end - - connection = connections[connection_id] - - unless connection = connections[connection_id] then - connections[connection_id] = http_class.new(*net_http_args) - connection = connections[connection_id] - ssl connection if use_ssl - else - reset connection if expired? connection - end - - start connection unless connection.started? - - connection.read_timeout = @read_timeout if @read_timeout - connection.keep_alive_timeout = @idle_timeout if @idle_timeout && connection.respond_to?(:keep_alive_timeout=) - - connection - rescue Errno::ECONNREFUSED - address = connection.proxy_address || connection.address - port = connection.proxy_port || connection.port - - raise Error, "connection refused: #{address}:#{port}" - rescue Errno::EHOSTDOWN - address = connection.proxy_address || connection.address - port = connection.proxy_port || connection.port - - raise Error, "host down: #{address}:#{port}" - end - - ## - # Returns an error message containing the number of requests performed on - # this connection - - def error_message connection - requests = Thread.current[@request_key][connection.object_id] - 1 # fixup - last_use = Thread.current[@timeout_key][connection.object_id] - - age = Time.now - last_use - - "after #{requests} requests on #{connection.object_id}, " \ - "last used #{age} seconds ago" - end - - ## - # URI::escape wrapper - - def escape str - CGI.escape str if str - end - - ## - # URI::unescape wrapper - - def unescape str - CGI.unescape str if str - end - - - ## - # Returns true if the connection should be reset due to an idle timeout, or - # maximum request count, false otherwise. - - def expired? connection - requests = Thread.current[@request_key][connection.object_id] - return true if @max_requests && requests >= @max_requests - return false unless @idle_timeout - return true if @idle_timeout.zero? - - last_used = Thread.current[@timeout_key][connection.object_id] - - Time.now - last_used > @idle_timeout - end - - ## - # Starts the Net::HTTP +connection+ - - def start connection - connection.set_debug_output @debug_output if @debug_output - connection.open_timeout = @open_timeout if @open_timeout - - connection.start - - socket = connection.instance_variable_get :@socket - - if socket then # for fakeweb - @socket_options.each do |option| - socket.io.setsockopt(*option) - end - end - end - - ## - # Finishes the Net::HTTP +connection+ - - def finish connection, thread = Thread.current - if requests = thread[@request_key] then - requests.delete connection.object_id - end - - connection.finish - rescue IOError - end - - def http_class # :nodoc: - if RUBY_VERSION > '2.0' then - Net::HTTP - elsif [:Artifice, :FakeWeb, :WebMock].any? { |klass| - Object.const_defined?(klass) - } or not @reuse_ssl_sessions then - Net::HTTP - else - Bundler::Persistent::Net::HTTP::Persistent::SSLReuse - end - end - - ## - # Returns the HTTP protocol version for +uri+ - - def http_version uri - @http_versions["#{uri.host}:#{uri.port}"] - end - - ## - # Is +req+ idempotent according to RFC 2616? - - def idempotent? req - case req - when Net::HTTP::Delete, Net::HTTP::Get, Net::HTTP::Head, - Net::HTTP::Options, Net::HTTP::Put, Net::HTTP::Trace then - true - end - end - - ## - # Is the request +req+ idempotent or is retry_change_requests allowed. - # - # If +retried_on_ruby_2+ is true, true will be returned if we are on ruby, - # retry_change_requests is allowed and the request is not idempotent. - - def can_retry? req, retried_on_ruby_2 = false - return @retry_change_requests && !idempotent?(req) if retried_on_ruby_2 - - @retry_change_requests || idempotent?(req) - end - - if RUBY_VERSION > '1.9' then - ## - # Workaround for missing Net::HTTPHeader#connection_close? on Ruby 1.8 - - def connection_close? header - header.connection_close? - end - - ## - # Workaround for missing Net::HTTPHeader#connection_keep_alive? on Ruby 1.8 - - def connection_keep_alive? header - header.connection_keep_alive? - end - else - ## - # Workaround for missing Net::HTTPRequest#connection_close? on Ruby 1.8 - - def connection_close? header - header['connection'] =~ /close/ or header['proxy-connection'] =~ /close/ - end - - ## - # Workaround for missing Net::HTTPRequest#connection_keep_alive? on Ruby - # 1.8 - - def connection_keep_alive? header - header['connection'] =~ /keep-alive/ or - header['proxy-connection'] =~ /keep-alive/ - end - end - - ## - # Deprecated in favor of #expired? - - def max_age # :nodoc: - return Time.now + 1 unless @idle_timeout - - Time.now - @idle_timeout - end - - ## - # Adds "http://" to the String +uri+ if it is missing. - - def normalize_uri uri - (uri =~ /^https?:/) ? uri : "http://#{uri}" - end - - ## - # Pipelines +requests+ to the HTTP server at +uri+ yielding responses if a - # block is given. Returns all responses received. - # - # See - # Net::HTTP::Pipeline[http://docs.seattlerb.org/net-http-pipeline/Net/HTTP/Pipeline.html] - # for further details. - # - # Only if net-http-pipeline was required before - # net-http-persistent #pipeline will be present. - - def pipeline uri, requests, &block # :yields: responses - connection = connection_for uri - - connection.pipeline requests, &block - end - - ## - # Sets this client's SSL private key - - def private_key= key - @private_key = key - - reconnect_ssl - end - - # For Net::HTTP parity - alias key= private_key= - - ## - # Sets the proxy server. The +proxy+ may be the URI of the proxy server, - # the symbol +:ENV+ which will read the proxy from the environment or nil to - # disable use of a proxy. See #proxy_from_env for details on setting the - # proxy from the environment. - # - # If the proxy URI is set after requests have been made, the next request - # will shut-down and re-open all connections. - # - # The +no_proxy+ query parameter can be used to specify hosts which shouldn't - # be reached via proxy; if set it should be a comma separated list of - # hostname suffixes, optionally with +:port+ appended, for example - # example.com,some.host:8080. - - def proxy= proxy - @proxy_uri = case proxy - when :ENV then proxy_from_env - when URI::HTTP then proxy - when nil then # ignore - else raise ArgumentError, 'proxy must be :ENV or a URI::HTTP' - end - - @no_proxy.clear - - if @proxy_uri then - @proxy_args = [ - @proxy_uri.host, - @proxy_uri.port, - unescape(@proxy_uri.user), - unescape(@proxy_uri.password), - ] - - @proxy_connection_id = [nil, *@proxy_args].join ':' - - if @proxy_uri.query then - @no_proxy = CGI.parse(@proxy_uri.query)['no_proxy'].join(',').downcase.split(',').map { |x| x.strip }.reject { |x| x.empty? } - end - end - - reconnect - reconnect_ssl - end - - ## - # Creates a URI for an HTTP proxy server from ENV variables. - # - # If +HTTP_PROXY+ is set a proxy will be returned. - # - # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the URI is given the - # indicated user and password unless HTTP_PROXY contains either of these in - # the URI. - # - # The +NO_PROXY+ ENV variable can be used to specify hosts which shouldn't - # be reached via proxy; if set it should be a comma separated list of - # hostname suffixes, optionally with +:port+ appended, for example - # example.com,some.host:8080. When set to * no proxy will - # be returned. - # - # For Windows users, lowercase ENV variables are preferred over uppercase ENV - # variables. - - def proxy_from_env - env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY'] - - return nil if env_proxy.nil? or env_proxy.empty? - - uri = URI normalize_uri env_proxy - - env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY'] - - # '*' is special case for always bypass - return nil if env_no_proxy == '*' - - if env_no_proxy then - uri.query = "no_proxy=#{escape(env_no_proxy)}" - end - - unless uri.user or uri.password then - uri.user = escape ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER'] - uri.password = escape ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS'] - end - - uri - end - - ## - # Returns true when proxy should by bypassed for host. - - def proxy_bypass? host, port - host = host.downcase - host_port = [host, port].join ':' - - @no_proxy.each do |name| - return true if host[-name.length, name.length] == name or - host_port[-name.length, name.length] == name - end - - false - end - - ## - # Forces reconnection of HTTP connections. - - def reconnect - @generation += 1 - end - - ## - # Forces reconnection of SSL connections. - - def reconnect_ssl - @ssl_generation += 1 - end - - ## - # Finishes then restarts the Net::HTTP +connection+ - - def reset connection - Thread.current[@request_key].delete connection.object_id - Thread.current[@timeout_key].delete connection.object_id - - finish connection - - start connection - rescue Errno::ECONNREFUSED - e = Error.new "connection refused: #{connection.address}:#{connection.port}" - e.set_backtrace $@ - raise e - rescue Errno::EHOSTDOWN - e = Error.new "host down: #{connection.address}:#{connection.port}" - e.set_backtrace $@ - raise e - end - - ## - # Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed - # against +uri+. - # - # If a block is passed #request behaves like Net::HTTP#request (the body of - # the response will not have been read). - # - # +req+ must be a Net::HTTPRequest subclass (see Net::HTTP for a list). - # - # If there is an error and the request is idempotent according to RFC 2616 - # it will be retried automatically. - - def request uri, req = nil, &block - retried = false - bad_response = false - - req = request_setup req || uri - - connection = connection_for uri - connection_id = connection.object_id - - begin - Thread.current[@request_key][connection_id] += 1 - response = connection.request req, &block - - if connection_close?(req) or - (response.http_version <= '1.0' and - not connection_keep_alive?(response)) or - connection_close?(response) then - connection.finish - end - rescue Net::HTTPBadResponse => e - message = error_message connection - - finish connection - - raise Error, "too many bad responses #{message}" if - bad_response or not can_retry? req - - bad_response = true - retry - rescue *RETRIED_EXCEPTIONS => e # retried on ruby 2 - request_failed e, req, connection if - retried or not can_retry? req, @retried_on_ruby_2 - - reset connection - - retried = true - retry - rescue Errno::EINVAL, Errno::ETIMEDOUT => e # not retried on ruby 2 - request_failed e, req, connection if retried or not can_retry? req - - reset connection - - retried = true - retry - rescue Exception => e - finish connection - - raise - ensure - Thread.current[@timeout_key][connection_id] = Time.now - end - - @http_versions["#{uri.host}:#{uri.port}"] ||= response.http_version - - response - end - - ## - # Raises an Error for +exception+ which resulted from attempting the request - # +req+ on the +connection+. - # - # Finishes the +connection+. - - def request_failed exception, req, connection # :nodoc: - due_to = "(due to #{exception.message} - #{exception.class})" - message = "too many connection resets #{due_to} #{error_message connection}" - - finish connection - - - raise Error, message, exception.backtrace - end - - ## - # Creates a GET request if +req_or_uri+ is a URI and adds headers to the - # request. - # - # Returns the request. - - def request_setup req_or_uri # :nodoc: - req = if URI === req_or_uri then - Net::HTTP::Get.new req_or_uri.request_uri - else - req_or_uri - end - - @headers.each do |pair| - req.add_field(*pair) - end - - @override_headers.each do |name, value| - req[name] = value - end - - unless req['Connection'] then - req.add_field 'Connection', 'keep-alive' - req.add_field 'Keep-Alive', @keep_alive - end - - req - end - - ## - # Shuts down all connections for +thread+. - # - # Uses the current thread by default. - # - # If you've used Bundler::Persistent::Net::HTTP::Persistent across multiple threads you should - # call this in each thread when you're done making HTTP requests. - # - # *NOTE*: Calling shutdown for another thread can be dangerous! - # - # If the thread is still using the connection it may cause an error! It is - # best to call #shutdown in the thread at the appropriate time instead! - - def shutdown thread = Thread.current - generation = reconnect - cleanup generation, thread, @generation_key - - ssl_generation = reconnect_ssl - cleanup ssl_generation, thread, @ssl_generation_key - - thread[@request_key] = nil - thread[@timeout_key] = nil - end - - ## - # Shuts down all connections in all threads - # - # *NOTE*: THIS METHOD IS VERY DANGEROUS! - # - # Do not call this method if other threads are still using their - # connections! Call #shutdown at the appropriate time instead! - # - # Use this method only as a last resort! - - def shutdown_in_all_threads - Thread.list.each do |thread| - shutdown thread - end - - nil - end - - ## - # Enables SSL on +connection+ - - def ssl connection - connection.use_ssl = true - - connection.ssl_version = @ssl_version if @ssl_version - - connection.verify_mode = @verify_mode - - if OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE and - not Object.const_defined?(:I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG) then - warn <<-WARNING - !!!SECURITY WARNING!!! - -The SSL HTTP connection to: - - #{connection.address}:#{connection.port} - - !!!MAY NOT BE VERIFIED!!! - -On your platform your OpenSSL implementation is broken. - -There is no difference between the values of VERIFY_NONE and VERIFY_PEER. - -This means that attempting to verify the security of SSL connections may not -work. This exposes you to man-in-the-middle exploits, snooping on the -contents of your connection and other dangers to the security of your data. - -To disable this warning define the following constant at top-level in your -application: - - I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG = nil - - WARNING - end - - if @ca_file then - connection.ca_file = @ca_file - connection.verify_mode = OpenSSL::SSL::VERIFY_PEER - connection.verify_callback = @verify_callback if @verify_callback - end - - if @certificate and @private_key then - connection.cert = @certificate - connection.key = @private_key - end - - connection.cert_store = if @cert_store then - @cert_store - else - store = OpenSSL::X509::Store.new - store.set_default_paths - store - end - end - - ## - # Finishes all connections that existed before the given SSL parameter - # +generation+. - - def ssl_cleanup generation # :nodoc: - cleanup generation, Thread.current, @ssl_generation_key - end - - ## - # SSL version to use - - def ssl_version= ssl_version - @ssl_version = ssl_version - - reconnect_ssl - end if RUBY_VERSION > '1.9' - - ## - # Sets the HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER. - # - # Setting this to VERIFY_NONE is a VERY BAD IDEA and should NEVER be used. - # Securely transfer the correct certificate and update the default - # certificate store or set the ca file instead. - - def verify_mode= verify_mode - @verify_mode = verify_mode - - reconnect_ssl - end - - ## - # SSL verification callback. - - def verify_callback= callback - @verify_callback = callback - - reconnect_ssl - end - -end - -require 'bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse' - diff --git a/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb b/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb deleted file mode 100644 index 1b6b789f6d7..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb +++ /dev/null @@ -1,129 +0,0 @@ -## -# This Net::HTTP subclass adds SSL session reuse and Server Name Indication -# (SNI) RFC 3546. -# -# DO NOT DEPEND UPON THIS CLASS -# -# This class is an implementation detail and is subject to change or removal -# at any time. - -class Bundler::Persistent::Net::HTTP::Persistent::SSLReuse < Net::HTTP - - @is_proxy_class = false - @proxy_addr = nil - @proxy_port = nil - @proxy_user = nil - @proxy_pass = nil - - def initialize address, port = nil # :nodoc: - super - - @ssl_session = nil - end - - ## - # From ruby trunk r33086 including http://redmine.ruby-lang.org/issues/5341 - - def connect # :nodoc: - D "opening connection to #{conn_address()}..." - s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) } - D "opened" - if use_ssl? - ssl_parameters = Hash.new - iv_list = instance_variables - SSL_ATTRIBUTES.each do |name| - ivname = "@#{name}".intern - if iv_list.include?(ivname) and - value = instance_variable_get(ivname) - ssl_parameters[name] = value - end - end - unless @ssl_context then - @ssl_context = OpenSSL::SSL::SSLContext.new - @ssl_context.set_params(ssl_parameters) - end - s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) - s.sync_close = true - end - @socket = Net::BufferedIO.new(s) - @socket.read_timeout = @read_timeout - @socket.continue_timeout = @continue_timeout if - @socket.respond_to? :continue_timeout - @socket.debug_output = @debug_output - if use_ssl? - begin - if proxy? - @socket.writeline sprintf('CONNECT %s:%s HTTP/%s', - @address, @port, HTTPVersion) - @socket.writeline "Host: #{@address}:#{@port}" - if proxy_user - credential = ["#{proxy_user}:#{proxy_pass}"].pack('m') - credential.delete!("\r\n") - @socket.writeline "Proxy-Authorization: Basic #{credential}" - end - @socket.writeline '' - Net::HTTPResponse.read_new(@socket).value - end - s.session = @ssl_session if @ssl_session - # Server Name Indication (SNI) RFC 3546 - s.hostname = @address if s.respond_to? :hostname= - timeout(@open_timeout) { s.connect } - if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE - s.post_connection_check(@address) - end - @ssl_session = s.session - rescue => exception - D "Conn close because of connect error #{exception}" - @socket.close if @socket and not @socket.closed? - raise exception - end - end - on_connect - end if RUBY_VERSION > '1.9' - - ## - # From ruby_1_8_7 branch r29865 including a modified - # http://redmine.ruby-lang.org/issues/5341 - - def connect # :nodoc: - D "opening connection to #{conn_address()}..." - s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) } - D "opened" - if use_ssl? - unless @ssl_context.verify_mode - warn "warning: peer certificate won't be verified in this SSL session" - @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE - end - s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) - s.sync_close = true - end - @socket = Net::BufferedIO.new(s) - @socket.read_timeout = @read_timeout - @socket.debug_output = @debug_output - if use_ssl? - if proxy? - @socket.writeline sprintf('CONNECT %s:%s HTTP/%s', - @address, @port, HTTPVersion) - @socket.writeline "Host: #{@address}:#{@port}" - if proxy_user - credential = ["#{proxy_user}:#{proxy_pass}"].pack('m') - credential.delete!("\r\n") - @socket.writeline "Proxy-Authorization: Basic #{credential}" - end - @socket.writeline '' - Net::HTTPResponse.read_new(@socket).value - end - s.session = @ssl_session if @ssl_session - s.connect - if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE - s.post_connection_check(@address) - end - @ssl_session = s.session - end - on_connect - end if RUBY_VERSION < '1.9' - - private :connect - -end - diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor.rb deleted file mode 100644 index 999e8b7e614..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor.rb +++ /dev/null @@ -1,509 +0,0 @@ -require "set" -require "bundler/vendor/thor/lib/thor/base" - -class Bundler::Thor - class << self - # Allows for custom "Command" package naming. - # - # === Parameters - # name - # options - # - def package_name(name, _ = {}) - @package_name = name.nil? || name == "" ? nil : name - end - - # Sets the default command when thor is executed without an explicit command to be called. - # - # ==== Parameters - # meth:: name of the default command - # - def default_command(meth = nil) - if meth - @default_command = meth == :none ? "help" : meth.to_s - else - @default_command ||= from_superclass(:default_command, "help") - end - end - alias_method :default_task, :default_command - - # Registers another Bundler::Thor subclass as a command. - # - # ==== Parameters - # klass:: Bundler::Thor subclass to register - # command:: Subcommand name to use - # usage:: Short usage for the subcommand - # description:: Description for the subcommand - def register(klass, subcommand_name, usage, description, options = {}) - if klass <= Bundler::Thor::Group - desc usage, description, options - define_method(subcommand_name) { |*args| invoke(klass, args) } - else - desc usage, description, options - subcommand subcommand_name, klass - end - end - - # Defines the usage and the description of the next command. - # - # ==== Parameters - # usage - # description - # options - # - def desc(usage, description, options = {}) - if options[:for] - command = find_and_refresh_command(options[:for]) - command.usage = usage if usage - command.description = description if description - else - @usage = usage - @desc = description - @hide = options[:hide] || false - end - end - - # Defines the long description of the next command. - # - # ==== Parameters - # long description - # - def long_desc(long_description, options = {}) - if options[:for] - command = find_and_refresh_command(options[:for]) - command.long_description = long_description if long_description - else - @long_desc = long_description - end - end - - # Maps an input to a command. If you define: - # - # map "-T" => "list" - # - # Running: - # - # thor -T - # - # Will invoke the list command. - # - # ==== Parameters - # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command. - # - def map(mappings = nil) - @map ||= from_superclass(:map, {}) - - if mappings - mappings.each do |key, value| - if key.respond_to?(:each) - key.each { |subkey| @map[subkey] = value } - else - @map[key] = value - end - end - end - - @map - end - - # Declares the options for the next command to be declared. - # - # ==== Parameters - # Hash[Symbol => Object]:: The hash key is the name of the option and the value - # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric - # or :required (string). If you give a value, the type of the value is used. - # - def method_options(options = nil) - @method_options ||= {} - build_options(options, @method_options) if options - @method_options - end - - alias_method :options, :method_options - - # Adds an option to the set of method options. If :for is given as option, - # it allows you to change the options from a previous defined command. - # - # def previous_command - # # magic - # end - # - # method_option :foo => :bar, :for => :previous_command - # - # def next_command - # # magic - # end - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :default - Default value for this argument. It cannot be required and have default values. - # :aliases - Aliases for this option. - # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. - # :banner - String to show on usage notes. - # :hide - If you want to hide this option from the help. - # - def method_option(name, options = {}) - scope = if options[:for] - find_and_refresh_command(options[:for]).options - else - method_options - end - - build_option(name, options, scope) - end - alias_method :option, :method_option - - # Prints help information for the given command. - # - # ==== Parameters - # shell - # command_name - # - def command_help(shell, command_name) - meth = normalize_command_name(command_name) - command = all_commands[meth] - handle_no_command_error(meth) unless command - - shell.say "Usage:" - shell.say " #{banner(command)}" - shell.say - class_options_help(shell, nil => command.options.values) - if command.long_description - shell.say "Description:" - shell.print_wrapped(command.long_description, :indent => 2) - else - shell.say command.description - end - end - alias_method :task_help, :command_help - - # Prints help information for this class. - # - # ==== Parameters - # shell - # - def help(shell, subcommand = false) - list = printable_commands(true, subcommand) - Bundler::Thor::Util.thor_classes_in(self).each do |klass| - list += klass.printable_commands(false) - end - list.sort! { |a, b| a[0] <=> b[0] } - - if defined?(@package_name) && @package_name - shell.say "#{@package_name} commands:" - else - shell.say "Commands:" - end - - shell.print_table(list, :indent => 2, :truncate => true) - shell.say - class_options_help(shell) - end - - # Returns commands ready to be printed. - def printable_commands(all = true, subcommand = false) - (all ? all_commands : commands).map do |_, command| - next if command.hidden? - item = [] - item << banner(command, false, subcommand) - item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : "") - item - end.compact - end - alias_method :printable_tasks, :printable_commands - - def subcommands - @subcommands ||= from_superclass(:subcommands, []) - end - alias_method :subtasks, :subcommands - - def subcommand_classes - @subcommand_classes ||= {} - end - - def subcommand(subcommand, subcommand_class) - subcommands << subcommand.to_s - subcommand_class.subcommand_help subcommand - subcommand_classes[subcommand.to_s] = subcommand_class - - define_method(subcommand) do |*args| - args, opts = Bundler::Thor::Arguments.split(args) - invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}] - invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h") - invoke subcommand_class, *invoke_args - end - subcommand_class.commands.each do |_meth, command| - command.ancestor_name = subcommand - end - end - alias_method :subtask, :subcommand - - # Extend check unknown options to accept a hash of conditions. - # - # === Parameters - # options: A hash containing :only and/or :except keys - def check_unknown_options!(options = {}) - @check_unknown_options ||= {} - options.each do |key, value| - if value - @check_unknown_options[key] = Array(value) - else - @check_unknown_options.delete(key) - end - end - @check_unknown_options - end - - # Overwrite check_unknown_options? to take subcommands and options into account. - def check_unknown_options?(config) #:nodoc: - options = check_unknown_options - return false unless options - - command = config[:current_command] - return true unless command - - name = command.name - - if subcommands.include?(name) - false - elsif options[:except] - !options[:except].include?(name.to_sym) - elsif options[:only] - options[:only].include?(name.to_sym) - else - true - end - end - - # Stop parsing of options as soon as an unknown option or a regular - # argument is encountered. All remaining arguments are passed to the command. - # This is useful if you have a command that can receive arbitrary additional - # options, and where those additional options should not be handled by - # Bundler::Thor. - # - # ==== Example - # - # To better understand how this is useful, let's consider a command that calls - # an external command. A user may want to pass arbitrary options and - # arguments to that command. The command itself also accepts some options, - # which should be handled by Bundler::Thor. - # - # class_option "verbose", :type => :boolean - # stop_on_unknown_option! :exec - # check_unknown_options! :except => :exec - # - # desc "exec", "Run a shell command" - # def exec(*args) - # puts "diagnostic output" if options[:verbose] - # Kernel.exec(*args) - # end - # - # Here +exec+ can be called with +--verbose+ to get diagnostic output, - # e.g.: - # - # $ thor exec --verbose echo foo - # diagnostic output - # foo - # - # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead: - # - # $ thor exec echo --verbose foo - # --verbose foo - # - # ==== Parameters - # Symbol ...:: A list of commands that should be affected. - def stop_on_unknown_option!(*command_names) - stop_on_unknown_option.merge(command_names) - end - - def stop_on_unknown_option?(command) #:nodoc: - command && stop_on_unknown_option.include?(command.name.to_sym) - end - - # Disable the check for required options for the given commands. - # This is useful if you have a command that does not need the required options - # to work, like help. - # - # ==== Parameters - # Symbol ...:: A list of commands that should be affected. - def disable_required_check!(*command_names) - disable_required_check.merge(command_names) - end - - def disable_required_check?(command) #:nodoc: - command && disable_required_check.include?(command.name.to_sym) - end - - protected - - def stop_on_unknown_option #:nodoc: - @stop_on_unknown_option ||= Set.new - end - - # help command has the required check disabled by default. - def disable_required_check #:nodoc: - @disable_required_check ||= Set.new([:help]) - end - - # The method responsible for dispatching given the args. - def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength - meth ||= retrieve_command_name(given_args) - command = all_commands[normalize_command_name(meth)] - - if !command && config[:invoked_via_subcommand] - # We're a subcommand and our first argument didn't match any of our - # commands. So we put it back and call our default command. - given_args.unshift(meth) - command = all_commands[normalize_command_name(default_command)] - end - - if command - args, opts = Bundler::Thor::Options.split(given_args) - if stop_on_unknown_option?(command) && !args.empty? - # given_args starts with a non-option, so we treat everything as - # ordinary arguments - args.concat opts - opts.clear - end - else - args = given_args - opts = nil - command = dynamic_command_class.new(meth) - end - - opts = given_opts || opts || [] - config[:current_command] = command - config[:command_options] = command.options - - instance = new(args, opts, config) - yield instance if block_given? - args = instance.args - trailing = args[Range.new(arguments.size, -1)] - instance.invoke_command(command, trailing || []) - end - - # The banner for this class. You can customize it if you are invoking the - # thor class by another ways which is not the Bundler::Thor::Runner. It receives - # the command that is going to be invoked and a boolean which indicates if - # the namespace should be displayed as arguments. - # - def banner(command, namespace = nil, subcommand = false) - "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}" - end - - def baseclass #:nodoc: - Bundler::Thor - end - - def dynamic_command_class #:nodoc: - Bundler::Thor::DynamicCommand - end - - def create_command(meth) #:nodoc: - @usage ||= nil - @desc ||= nil - @long_desc ||= nil - @hide ||= nil - - if @usage && @desc - base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command - commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options) - @usage, @desc, @long_desc, @method_options, @hide = nil - true - elsif all_commands[meth] || meth == "method_missing" - true - else - puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " \ - "Call desc if you want this method to be available as command or declare it inside a " \ - "no_commands{} block. Invoked from #{caller[1].inspect}." - false - end - end - alias_method :create_task, :create_command - - def initialize_added #:nodoc: - class_options.merge!(method_options) - @method_options = nil - end - - # Retrieve the command name from given args. - def retrieve_command_name(args) #:nodoc: - meth = args.first.to_s unless args.empty? - args.shift if meth && (map[meth] || meth !~ /^\-/) - end - alias_method :retrieve_task_name, :retrieve_command_name - - # receives a (possibly nil) command name and returns a name that is in - # the commands hash. In addition to normalizing aliases, this logic - # will determine if a shortened command is an unambiguous substring of - # a command or alias. - # - # +normalize_command_name+ also converts names like +animal-prison+ - # into +animal_prison+. - def normalize_command_name(meth) #:nodoc: - return default_command.to_s.tr("-", "_") unless meth - - possibilities = find_command_possibilities(meth) - raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]" if possibilities.size > 1 - - if possibilities.empty? - meth ||= default_command - elsif map[meth] - meth = map[meth] - else - meth = possibilities.first - end - - meth.to_s.tr("-", "_") # treat foo-bar as foo_bar - end - alias_method :normalize_task_name, :normalize_command_name - - # this is the logic that takes the command name passed in by the user - # and determines whether it is an unambiguous substrings of a command or - # alias name. - def find_command_possibilities(meth) - len = meth.to_s.length - possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort - unique_possibilities = possibilities.map { |k| map[k] || k }.uniq - - if possibilities.include?(meth) - [meth] - elsif unique_possibilities.size == 1 - unique_possibilities - else - possibilities - end - end - alias_method :find_task_possibilities, :find_command_possibilities - - def subcommand_help(cmd) - desc "help [COMMAND]", "Describe subcommands or one specific subcommand" - class_eval " - def help(command = nil, subcommand = true); super; end -" - end - alias_method :subtask_help, :subcommand_help - end - - include Bundler::Thor::Base - - map HELP_MAPPINGS => :help - - desc "help [COMMAND]", "Describe available commands or one specific command" - def help(command = nil, subcommand = false) - if command - if self.class.subcommands.include? command - self.class.subcommand_classes[command].help(shell, true) - else - self.class.command_help(shell, command) - end - else - self.class.help(shell, subcommand) - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions.rb deleted file mode 100644 index e6698572a96..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions.rb +++ /dev/null @@ -1,321 +0,0 @@ -require "uri" -require "bundler/vendor/thor/lib/thor/core_ext/io_binary_read" -require "bundler/vendor/thor/lib/thor/actions/create_file" -require "bundler/vendor/thor/lib/thor/actions/create_link" -require "bundler/vendor/thor/lib/thor/actions/directory" -require "bundler/vendor/thor/lib/thor/actions/empty_directory" -require "bundler/vendor/thor/lib/thor/actions/file_manipulation" -require "bundler/vendor/thor/lib/thor/actions/inject_into_file" - -class Bundler::Thor - module Actions - attr_accessor :behavior - - def self.included(base) #:nodoc: - base.extend ClassMethods - end - - module ClassMethods - # Hold source paths for one Bundler::Thor instance. source_paths_for_search is the - # method responsible to gather source_paths from this current class, - # inherited paths and the source root. - # - def source_paths - @_source_paths ||= [] - end - - # Stores and return the source root for this class - def source_root(path = nil) - @_source_root = path if path - @_source_root ||= nil - end - - # Returns the source paths in the following order: - # - # 1) This class source paths - # 2) Source root - # 3) Parents source paths - # - def source_paths_for_search - paths = [] - paths += source_paths - paths << source_root if source_root - paths += from_superclass(:source_paths, []) - paths - end - - # Add runtime options that help actions execution. - # - def add_runtime_options! - class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime, - :desc => "Overwrite files that already exist" - - class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime, - :desc => "Run but do not make any changes" - - class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime, - :desc => "Suppress status output" - - class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime, - :desc => "Skip files that already exist" - end - end - - # Extends initializer to add more configuration options. - # - # ==== Configuration - # behavior:: The actions default behavior. Can be :invoke or :revoke. - # It also accepts :force, :skip and :pretend to set the behavior - # and the respective option. - # - # destination_root:: The root directory needed for some actions. - # - def initialize(args = [], options = {}, config = {}) - self.behavior = case config[:behavior].to_s - when "force", "skip" - _cleanup_options_and_set(options, config[:behavior]) - :invoke - when "revoke" - :revoke - else - :invoke - end - - super - self.destination_root = config[:destination_root] - end - - # Wraps an action object and call it accordingly to the thor class behavior. - # - def action(instance) #:nodoc: - if behavior == :revoke - instance.revoke! - else - instance.invoke! - end - end - - # Returns the root for this thor class (also aliased as destination root). - # - def destination_root - @destination_stack.last - end - - # Sets the root for this thor class. Relatives path are added to the - # directory where the script was invoked and expanded. - # - def destination_root=(root) - @destination_stack ||= [] - @destination_stack[0] = File.expand_path(root || "") - end - - # Returns the given path relative to the absolute root (ie, root where - # the script started). - # - def relative_to_original_destination_root(path, remove_dot = true) - path = path.dup - if path.gsub!(@destination_stack[0], ".") - remove_dot ? (path[2..-1] || "") : path - else - path - end - end - - # Holds source paths in instance so they can be manipulated. - # - def source_paths - @source_paths ||= self.class.source_paths_for_search - end - - # Receives a file or directory and search for it in the source paths. - # - def find_in_source_paths(file) - possible_files = [file, file + TEMPLATE_EXTNAME] - relative_root = relative_to_original_destination_root(destination_root, false) - - source_paths.each do |source| - possible_files.each do |f| - source_file = File.expand_path(f, File.join(source, relative_root)) - return source_file if File.exist?(source_file) - end - end - - message = "Could not find #{file.inspect} in any of your source paths. ".dup - - unless self.class.source_root - message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. " - end - - message << if source_paths.empty? - "Currently you have no source paths." - else - "Your current source paths are: \n#{source_paths.join("\n")}" - end - - raise Error, message - end - - # Do something in the root or on a provided subfolder. If a relative path - # is given it's referenced from the current root. The full path is yielded - # to the block you provide. The path is set back to the previous path when - # the method exits. - # - # ==== Parameters - # dir:: the directory to move to. - # config:: give :verbose => true to log and use padding. - # - def inside(dir = "", config = {}, &block) - verbose = config.fetch(:verbose, false) - pretend = options[:pretend] - - say_status :inside, dir, verbose - shell.padding += 1 if verbose - @destination_stack.push File.expand_path(dir, destination_root) - - # If the directory doesnt exist and we're not pretending - if !File.exist?(destination_root) && !pretend - require "fileutils" - FileUtils.mkdir_p(destination_root) - end - - if pretend - # In pretend mode, just yield down to the block - block.arity == 1 ? yield(destination_root) : yield - else - require "fileutils" - FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield } - end - - @destination_stack.pop - shell.padding -= 1 if verbose - end - - # Goes to the root and execute the given block. - # - def in_root - inside(@destination_stack.first) { yield } - end - - # Loads an external file and execute it in the instance binding. - # - # ==== Parameters - # path:: The path to the file to execute. Can be a web address or - # a relative path from the source root. - # - # ==== Examples - # - # apply "http://gist.github.com/103208" - # - # apply "recipes/jquery.rb" - # - def apply(path, config = {}) - verbose = config.fetch(:verbose, true) - is_uri = path =~ %r{^https?\://} - path = find_in_source_paths(path) unless is_uri - - say_status :apply, path, verbose - shell.padding += 1 if verbose - - contents = if is_uri - open(path, "Accept" => "application/x-thor-template", &:read) - else - open(path, &:read) - end - - instance_eval(contents, path) - shell.padding -= 1 if verbose - end - - # Executes a command returning the contents of the command. - # - # ==== Parameters - # command:: the command to be executed. - # config:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with - # to append an executable to command execution. - # - # ==== Example - # - # inside('vendor') do - # run('ln -s ~/edge rails') - # end - # - def run(command, config = {}) - return unless behavior == :invoke - - destination = relative_to_original_destination_root(destination_root, false) - desc = "#{command} from #{destination.inspect}" - - if config[:with] - desc = "#{File.basename(config[:with].to_s)} #{desc}" - command = "#{config[:with]} #{command}" - end - - say_status :run, desc, config.fetch(:verbose, true) - - unless options[:pretend] - config[:capture] ? `#{command}` : system(command.to_s) - end - end - - # Executes a ruby script (taking into account WIN32 platform quirks). - # - # ==== Parameters - # command:: the command to be executed. - # config:: give :verbose => false to not log the status. - # - def run_ruby_script(command, config = {}) - return unless behavior == :invoke - run command, config.merge(:with => Bundler::Thor::Util.ruby_command) - end - - # Run a thor command. A hash of options can be given and it's converted to - # switches. - # - # ==== Parameters - # command:: the command to be invoked - # args:: arguments to the command - # config:: give :verbose => false to not log the status, :capture => true to hide to output. - # Other options are given as parameter to Bundler::Thor. - # - # - # ==== Examples - # - # thor :install, "http://gist.github.com/103208" - # #=> thor install http://gist.github.com/103208 - # - # thor :list, :all => true, :substring => 'rails' - # #=> thor list --all --substring=rails - # - def thor(command, *args) - config = args.last.is_a?(Hash) ? args.pop : {} - verbose = config.key?(:verbose) ? config.delete(:verbose) : true - pretend = config.key?(:pretend) ? config.delete(:pretend) : false - capture = config.key?(:capture) ? config.delete(:capture) : false - - args.unshift(command) - args.push Bundler::Thor::Options.to_switches(config) - command = args.join(" ").strip - - run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture - end - - protected - - # Allow current root to be shared between invocations. - # - def _shared_configuration #:nodoc: - super.merge!(:destination_root => destination_root) - end - - def _cleanup_options_and_set(options, key) #:nodoc: - case options - when Array - %w(--force -f --skip -s).each { |i| options.delete(i) } - options << "--#{key}" - when Hash - [:force, :skip, "force", "skip"].each { |i| options.delete(i) } - options.merge!(key => true) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/create_file.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/create_file.rb deleted file mode 100644 index 97d22d9bbdd..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/create_file.rb +++ /dev/null @@ -1,104 +0,0 @@ -require "bundler/vendor/thor/lib/thor/actions/empty_directory" - -class Bundler::Thor - module Actions - # Create a new file relative to the destination root with the given data, - # which is the return value of a block or a data string. - # - # ==== Parameters - # destination:: the relative path to the destination root. - # data:: the data to append to the file. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # create_file "lib/fun_party.rb" do - # hostname = ask("What is the virtual hostname I should use?") - # "vhost.name = #{hostname}" - # end - # - # create_file "config/apache.conf", "your apache config" - # - def create_file(destination, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - data = args.first - action CreateFile.new(self, destination, block || data.to_s, config) - end - alias_method :add_file, :create_file - - # CreateFile is a subset of Template, which instead of rendering a file with - # ERB, it gets the content from the user. - # - class CreateFile < EmptyDirectory #:nodoc: - attr_reader :data - - def initialize(base, destination, data, config = {}) - @data = data - super(base, destination, config) - end - - # Checks if the content of the file at the destination is identical to the rendered result. - # - # ==== Returns - # Boolean:: true if it is identical, false otherwise. - # - def identical? - exists? && File.binread(destination) == render - end - - # Holds the content to be added to the file. - # - def render - @render ||= if data.is_a?(Proc) - data.call - else - data - end - end - - def invoke! - invoke_with_conflict_check do - require "fileutils" - FileUtils.mkdir_p(File.dirname(destination)) - File.open(destination, "wb") { |f| f.write render } - end - given_destination - end - - protected - - # Now on conflict we check if the file is identical or not. - # - def on_conflict_behavior(&block) - if identical? - say_status :identical, :blue - else - options = base.options.merge(config) - force_or_skip_or_conflict(options[:force], options[:skip], &block) - end - end - - # If force is true, run the action, otherwise check if it's not being - # skipped. If both are false, show the file_collision menu, if the menu - # returns true, force it, otherwise skip. - # - def force_or_skip_or_conflict(force, skip, &block) - if force - say_status :force, :yellow - yield unless pretend? - elsif skip - say_status :skip, :yellow - else - say_status :conflict, :red - force_or_skip_or_conflict(force_on_collision?, true, &block) - end - end - - # Shows the file collision menu to the user and gets the result. - # - def force_on_collision? - base.shell.file_collision(destination) { render } - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/create_link.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/create_link.rb deleted file mode 100644 index 3a664401b41..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/create_link.rb +++ /dev/null @@ -1,60 +0,0 @@ -require "bundler/vendor/thor/lib/thor/actions/create_file" - -class Bundler::Thor - module Actions - # Create a new file relative to the destination root from the given source. - # - # ==== Parameters - # destination:: the relative path to the destination root. - # source:: the relative path to the source root. - # config:: give :verbose => false to not log the status. - # :: give :symbolic => false for hard link. - # - # ==== Examples - # - # create_link "config/apache.conf", "/etc/apache.conf" - # - def create_link(destination, *args) - config = args.last.is_a?(Hash) ? args.pop : {} - source = args.first - action CreateLink.new(self, destination, source, config) - end - alias_method :add_link, :create_link - - # CreateLink is a subset of CreateFile, which instead of taking a block of - # data, just takes a source string from the user. - # - class CreateLink < CreateFile #:nodoc: - attr_reader :data - - # Checks if the content of the file at the destination is identical to the rendered result. - # - # ==== Returns - # Boolean:: true if it is identical, false otherwise. - # - def identical? - exists? && File.identical?(render, destination) - end - - def invoke! - invoke_with_conflict_check do - require "fileutils" - FileUtils.mkdir_p(File.dirname(destination)) - # Create a symlink by default - config[:symbolic] = true if config[:symbolic].nil? - File.unlink(destination) if exists? - if config[:symbolic] - File.symlink(render, destination) - else - File.link(render, destination) - end - end - given_destination - end - - def exists? - super || File.symlink?(destination) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/directory.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/directory.rb deleted file mode 100644 index f555f7b7e0f..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/directory.rb +++ /dev/null @@ -1,118 +0,0 @@ -require "bundler/vendor/thor/lib/thor/actions/empty_directory" - -class Bundler::Thor - module Actions - # Copies recursively the files from source directory to root directory. - # If any of the files finishes with .tt, it's considered to be a template - # and is placed in the destination without the extension .tt. If any - # empty directory is found, it's copied and all .empty_directory files are - # ignored. If any file name is wrapped within % signs, the text within - # the % signs will be executed as a method and replaced with the returned - # value. Let's suppose a doc directory with the following files: - # - # doc/ - # components/.empty_directory - # README - # rdoc.rb.tt - # %app_name%.rb - # - # When invoked as: - # - # directory "doc" - # - # It will create a doc directory in the destination with the following - # files (assuming that the `app_name` method returns the value "blog"): - # - # doc/ - # components/ - # README - # rdoc.rb - # blog.rb - # - # Encoded path note: Since Bundler::Thor internals use Object#respond_to? to check if it can - # expand %something%, this `something` should be a public method in the class calling - # #directory. If a method is private, Bundler::Thor stack raises PrivateMethodEncodedError. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # If :recursive => false, does not look for paths recursively. - # If :mode => :preserve, preserve the file mode from the source. - # If :exclude_pattern => /regexp/, prevents copying files that match that regexp. - # - # ==== Examples - # - # directory "doc" - # directory "doc", "docs", :recursive => false - # - def directory(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source - action Directory.new(self, source, destination || source, config, &block) - end - - class Directory < EmptyDirectory #:nodoc: - attr_reader :source - - def initialize(base, source, destination = nil, config = {}, &block) - @source = File.expand_path(base.find_in_source_paths(source.to_s)) - @block = block - super(base, destination, {:recursive => true}.merge(config)) - end - - def invoke! - base.empty_directory given_destination, config - execute! - end - - def revoke! - execute! - end - - protected - - def execute! - lookup = Util.escape_globs(source) - lookup = config[:recursive] ? File.join(lookup, "**") : lookup - lookup = file_level_lookup(lookup) - - files(lookup).sort.each do |file_source| - next if File.directory?(file_source) - next if config[:exclude_pattern] && file_source.match(config[:exclude_pattern]) - file_destination = File.join(given_destination, file_source.gsub(source, ".")) - file_destination.gsub!("/./", "/") - - case file_source - when /\.empty_directory$/ - dirname = File.dirname(file_destination).gsub(%r{/\.$}, "") - next if dirname == given_destination - base.empty_directory(dirname, config) - when /#{TEMPLATE_EXTNAME}$/ - base.template(file_source, file_destination[0..-4], config, &@block) - else - base.copy_file(file_source, file_destination, config, &@block) - end - end - end - - if RUBY_VERSION < "2.0" - def file_level_lookup(previous_lookup) - File.join(previous_lookup, "{*,.[a-z]*}") - end - - def files(lookup) - Dir[lookup] - end - else - def file_level_lookup(previous_lookup) - File.join(previous_lookup, "*") - end - - def files(lookup) - Dir.glob(lookup, File::FNM_DOTMATCH) - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb deleted file mode 100644 index 284d92c19ae..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +++ /dev/null @@ -1,143 +0,0 @@ -class Bundler::Thor - module Actions - # Creates an empty directory. - # - # ==== Parameters - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # empty_directory "doc" - # - def empty_directory(destination, config = {}) - action EmptyDirectory.new(self, destination, config) - end - - # Class which holds create directory logic. This is the base class for - # other actions like create_file and directory. - # - # This implementation is based in Templater actions, created by Jonas Nicklas - # and Michael S. Klishin under MIT LICENSE. - # - class EmptyDirectory #:nodoc: - attr_reader :base, :destination, :given_destination, :relative_destination, :config - - # Initializes given the source and destination. - # - # ==== Parameters - # base:: A Bundler::Thor::Base instance - # source:: Relative path to the source of this file - # destination:: Relative path to the destination of this file - # config:: give :verbose => false to not log the status. - # - def initialize(base, destination, config = {}) - @base = base - @config = {:verbose => true}.merge(config) - self.destination = destination - end - - # Checks if the destination file already exists. - # - # ==== Returns - # Boolean:: true if the file exists, false otherwise. - # - def exists? - ::File.exist?(destination) - end - - def invoke! - invoke_with_conflict_check do - require "fileutils" - ::FileUtils.mkdir_p(destination) - end - end - - def revoke! - say_status :remove, :red - require "fileutils" - ::FileUtils.rm_rf(destination) if !pretend? && exists? - given_destination - end - - protected - - # Shortcut for pretend. - # - def pretend? - base.options[:pretend] - end - - # Sets the absolute destination value from a relative destination value. - # It also stores the given and relative destination. Let's suppose our - # script is being executed on "dest", it sets the destination root to - # "dest". The destination, given_destination and relative_destination - # are related in the following way: - # - # inside "bar" do - # empty_directory "baz" - # end - # - # destination #=> dest/bar/baz - # relative_destination #=> bar/baz - # given_destination #=> baz - # - def destination=(destination) - return unless destination - @given_destination = convert_encoded_instructions(destination.to_s) - @destination = ::File.expand_path(@given_destination, base.destination_root) - @relative_destination = base.relative_to_original_destination_root(@destination) - end - - # Filenames in the encoded form are converted. If you have a file: - # - # %file_name%.rb - # - # It calls #file_name from the base and replaces %-string with the - # return value (should be String) of #file_name: - # - # user.rb - # - # The method referenced can be either public or private. - # - def convert_encoded_instructions(filename) - filename.gsub(/%(.*?)%/) do |initial_string| - method = $1.strip - base.respond_to?(method, true) ? base.send(method) : initial_string - end - end - - # Receives a hash of options and just execute the block if some - # conditions are met. - # - def invoke_with_conflict_check(&block) - if exists? - on_conflict_behavior(&block) - else - yield unless pretend? - say_status :create, :green - end - - destination - rescue Errno::EISDIR, Errno::EEXIST - on_file_clash_behavior - end - - def on_file_clash_behavior - say_status :file_clash, :red - end - - # What to do when the destination file already exists. - # - def on_conflict_behavior - say_status :exist, :blue - end - - # Shortcut to say_status shell method. - # - def say_status(status, color) - base.shell.say_status status, relative_destination, color if config[:verbose] - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb deleted file mode 100644 index 4c83bebc861..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +++ /dev/null @@ -1,364 +0,0 @@ -require "erb" - -class Bundler::Thor - module Actions - # Copies the file from the relative source to the relative destination. If - # the destination is not given it's assumed to be equal to the source. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status, and - # :mode => :preserve, to preserve the file mode from the source. - - # - # ==== Examples - # - # copy_file "README", "doc/README" - # - # copy_file "doc/README" - # - def copy_file(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source - source = File.expand_path(find_in_source_paths(source.to_s)) - - create_file destination, nil, config do - content = File.binread(source) - content = yield(content) if block - content - end - if config[:mode] == :preserve - mode = File.stat(source).mode - chmod(destination, mode, config) - end - end - - # Links the file from the relative source to the relative destination. If - # the destination is not given it's assumed to be equal to the source. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # link_file "README", "doc/README" - # - # link_file "doc/README" - # - def link_file(source, *args) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source - source = File.expand_path(find_in_source_paths(source.to_s)) - - create_link destination, source, config - end - - # Gets the content at the given address and places it at the given relative - # destination. If a block is given instead of destination, the content of - # the url is yielded and used as location. - # - # ==== Parameters - # source:: the address of the given content. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # get "http://gist.github.com/103208", "doc/README" - # - # get "http://gist.github.com/103208" do |content| - # content.split("\n").first - # end - # - def get(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first - - if source =~ %r{^https?\://} - require "open-uri" - else - source = File.expand_path(find_in_source_paths(source.to_s)) - end - - render = open(source) { |input| input.binmode.read } - - destination ||= if block_given? - block.arity == 1 ? yield(render) : yield - else - File.basename(source) - end - - create_file destination, render, config - end - - # Gets an ERB template at the relative source, executes it and makes a copy - # at the relative destination. If the destination is not given it's assumed - # to be equal to the source removing .tt from the filename. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # template "README", "doc/README" - # - # template "doc/README" - # - def template(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "") - - source = File.expand_path(find_in_source_paths(source.to_s)) - context = config.delete(:context) || instance_eval("binding") - - create_file destination, nil, config do - content = CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer").tap do |erb| - erb.filename = source - end.result(context) - content = yield(content) if block - content - end - end - - # Changes the mode of the given file or directory. - # - # ==== Parameters - # mode:: the file mode - # path:: the name of the file to change mode - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # chmod "script/server", 0755 - # - def chmod(path, mode, config = {}) - return unless behavior == :invoke - path = File.expand_path(path, destination_root) - say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true) - unless options[:pretend] - require "fileutils" - FileUtils.chmod_R(mode, path) - end - end - - # Prepend text to a file. Since it depends on insert_into_file, it's reversible. - # - # ==== Parameters - # path:: path of the file to be changed - # data:: the data to prepend to the file, can be also given as a block. - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"' - # - # prepend_to_file 'config/environments/test.rb' do - # 'config.gem "rspec"' - # end - # - def prepend_to_file(path, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - config[:after] = /\A/ - insert_into_file(path, *(args << config), &block) - end - alias_method :prepend_file, :prepend_to_file - - # Append text to a file. Since it depends on insert_into_file, it's reversible. - # - # ==== Parameters - # path:: path of the file to be changed - # data:: the data to append to the file, can be also given as a block. - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # append_to_file 'config/environments/test.rb', 'config.gem "rspec"' - # - # append_to_file 'config/environments/test.rb' do - # 'config.gem "rspec"' - # end - # - def append_to_file(path, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - config[:before] = /\z/ - insert_into_file(path, *(args << config), &block) - end - alias_method :append_file, :append_to_file - - # Injects text right after the class definition. Since it depends on - # insert_into_file, it's reversible. - # - # ==== Parameters - # path:: path of the file to be changed - # klass:: the class to be manipulated - # data:: the data to append to the class, can be also given as a block. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n" - # - # inject_into_class "app/controllers/application_controller.rb", ApplicationController do - # " filter_parameter :password\n" - # end - # - def inject_into_class(path, klass, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - config[:after] = /class #{klass}\n|class #{klass} .*\n/ - insert_into_file(path, *(args << config), &block) - end - - # Injects text right after the module definition. Since it depends on - # insert_into_file, it's reversible. - # - # ==== Parameters - # path:: path of the file to be changed - # module_name:: the module to be manipulated - # data:: the data to append to the class, can be also given as a block. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper, " def help; 'help'; end\n" - # - # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper do - # " def help; 'help'; end\n" - # end - # - def inject_into_module(path, module_name, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - config[:after] = /module #{module_name}\n|module #{module_name} .*\n/ - insert_into_file(path, *(args << config), &block) - end - - # Run a regular expression replacement on a file. - # - # ==== Parameters - # path:: path of the file to be changed - # flag:: the regexp or string to be replaced - # replacement:: the replacement, can be also given as a block - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1' - # - # gsub_file 'README', /rake/, :green do |match| - # match << " no more. Use thor!" - # end - # - def gsub_file(path, flag, *args, &block) - return unless behavior == :invoke - config = args.last.is_a?(Hash) ? args.pop : {} - - path = File.expand_path(path, destination_root) - say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true) - - unless options[:pretend] - content = File.binread(path) - content.gsub!(flag, *args, &block) - File.open(path, "wb") { |file| file.write(content) } - end - end - - # Uncomment all lines matching a given regex. It will leave the space - # which existed before the comment hash in tact but will remove any spacing - # between the comment hash and the beginning of the line. - # - # ==== Parameters - # path:: path of the file to be changed - # flag:: the regexp or string used to decide which lines to uncomment - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # uncomment_lines 'config/initializers/session_store.rb', /active_record/ - # - def uncomment_lines(path, flag, *args) - flag = flag.respond_to?(:source) ? flag.source : flag - - gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args) - end - - # Comment all lines matching a given regex. It will leave the space - # which existed before the beginning of the line in tact and will insert - # a single space after the comment hash. - # - # ==== Parameters - # path:: path of the file to be changed - # flag:: the regexp or string used to decide which lines to comment - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # comment_lines 'config/initializers/session_store.rb', /cookie_store/ - # - def comment_lines(path, flag, *args) - flag = flag.respond_to?(:source) ? flag.source : flag - - gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args) - end - - # Removes a file at the given location. - # - # ==== Parameters - # path:: path of the file to be changed - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # remove_file 'README' - # remove_file 'app/controllers/application_controller.rb' - # - def remove_file(path, config = {}) - return unless behavior == :invoke - path = File.expand_path(path, destination_root) - - say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true) - if !options[:pretend] && File.exist?(path) - require "fileutils" - ::FileUtils.rm_rf(path) - end - end - alias_method :remove_dir, :remove_file - - attr_accessor :output_buffer - private :output_buffer, :output_buffer= - - private - - def concat(string) - @output_buffer.concat(string) - end - - def capture(*args) - with_output_buffer { yield(*args) } - end - - def with_output_buffer(buf = "".dup) #:nodoc: - raise ArgumentError, "Buffer can not be a frozen object" if buf.frozen? - old_buffer = output_buffer - self.output_buffer = buf - yield - output_buffer - ensure - self.output_buffer = old_buffer - end - - # Bundler::Thor::Actions#capture depends on what kind of buffer is used in ERB. - # Thus CapturableERB fixes ERB to use String buffer. - class CapturableERB < ERB - def set_eoutvar(compiler, eoutvar = "_erbout") - compiler.put_cmd = "#{eoutvar}.concat" - compiler.insert_cmd = "#{eoutvar}.concat" - compiler.pre_cmd = ["#{eoutvar} = ''.dup"] - compiler.post_cmd = [eoutvar] - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb deleted file mode 100644 index 349b26ff65c..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +++ /dev/null @@ -1,109 +0,0 @@ -require "bundler/vendor/thor/lib/thor/actions/empty_directory" - -class Bundler::Thor - module Actions - # Injects the given content into a file. Different from gsub_file, this - # method is reversible. - # - # ==== Parameters - # destination:: Relative path to the destination root - # data:: Data to add to the file. Can be given as a block. - # config:: give :verbose => false to not log the status and the flag - # for injection (:after or :before) or :force => true for - # insert two or more times the same content. - # - # ==== Examples - # - # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n" - # - # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do - # gems = ask "Which gems would you like to add?" - # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n") - # end - # - def insert_into_file(destination, *args, &block) - data = block_given? ? block : args.shift - config = args.shift - action InjectIntoFile.new(self, destination, data, config) - end - alias_method :inject_into_file, :insert_into_file - - class InjectIntoFile < EmptyDirectory #:nodoc: - attr_reader :replacement, :flag, :behavior - - def initialize(base, destination, data, config) - super(base, destination, {:verbose => true}.merge(config)) - - @behavior, @flag = if @config.key?(:after) - [:after, @config.delete(:after)] - else - [:before, @config.delete(:before)] - end - - @replacement = data.is_a?(Proc) ? data.call : data - @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp) - end - - def invoke! - say_status :invoke - - content = if @behavior == :after - '\0' + replacement - else - replacement + '\0' - end - - if exists? - replace!(/#{flag}/, content, config[:force]) - else - unless pretend? - raise Bundler::Thor::Error, "The file #{ destination } does not appear to exist" - end - end - end - - def revoke! - say_status :revoke - - regexp = if @behavior == :after - content = '\1\2' - /(#{flag})(.*)(#{Regexp.escape(replacement)})/m - else - content = '\2\3' - /(#{Regexp.escape(replacement)})(.*)(#{flag})/m - end - - replace!(regexp, content, true) - end - - protected - - def say_status(behavior) - status = if behavior == :invoke - if flag == /\A/ - :prepend - elsif flag == /\z/ - :append - else - :insert - end - else - :subtract - end - - super(status, config[:verbose]) - end - - # Adds the content to the file. - # - def replace!(regexp, string, force) - return if pretend? - content = File.read(destination) - if force || !content.include?(replacement) - content.gsub!(regexp, string) - File.open(destination, "wb") { |file| file.write(content) } - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/base.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/base.rb deleted file mode 100644 index 9bd10771704..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/base.rb +++ /dev/null @@ -1,679 +0,0 @@ -require "bundler/vendor/thor/lib/thor/command" -require "bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access" -require "bundler/vendor/thor/lib/thor/core_ext/ordered_hash" -require "bundler/vendor/thor/lib/thor/error" -require "bundler/vendor/thor/lib/thor/invocation" -require "bundler/vendor/thor/lib/thor/parser" -require "bundler/vendor/thor/lib/thor/shell" -require "bundler/vendor/thor/lib/thor/line_editor" -require "bundler/vendor/thor/lib/thor/util" - -class Bundler::Thor - autoload :Actions, "bundler/vendor/thor/lib/thor/actions" - autoload :RakeCompat, "bundler/vendor/thor/lib/thor/rake_compat" - autoload :Group, "bundler/vendor/thor/lib/thor/group" - - # Shortcuts for help. - HELP_MAPPINGS = %w(-h -? --help -D) - - # Bundler::Thor methods that should not be overwritten by the user. - THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root - action add_file create_file in_root inside run run_ruby_script) - - TEMPLATE_EXTNAME = ".tt" - - module Base - attr_accessor :options, :parent_options, :args - - # It receives arguments in an Array and two hashes, one for options and - # other for configuration. - # - # Notice that it does not check if all required arguments were supplied. - # It should be done by the parser. - # - # ==== Parameters - # args:: An array of objects. The objects are applied to their - # respective accessors declared with argument. - # - # options:: An options hash that will be available as self.options. - # The hash given is converted to a hash with indifferent - # access, magic predicates (options.skip?) and then frozen. - # - # config:: Configuration for this Bundler::Thor class. - # - def initialize(args = [], local_options = {}, config = {}) - parse_options = self.class.class_options - - # The start method splits inbound arguments at the first argument - # that looks like an option (starts with - or --). It then calls - # new, passing in the two halves of the arguments Array as the - # first two parameters. - - command_options = config.delete(:command_options) # hook for start - parse_options = parse_options.merge(command_options) if command_options - if local_options.is_a?(Array) - array_options = local_options - hash_options = {} - else - # Handle the case where the class was explicitly instantiated - # with pre-parsed options. - array_options = [] - hash_options = local_options - end - - # Let Bundler::Thor::Options parse the options first, so it can remove - # declared options from the array. This will leave us with - # a list of arguments that weren't declared. - stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command] - disable_required_check = self.class.disable_required_check? config[:current_command] - opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check) - self.options = opts.parse(array_options) - self.options = config[:class_options].merge(options) if config[:class_options] - - # If unknown options are disallowed, make sure that none of the - # remaining arguments looks like an option. - opts.check_unknown! if self.class.check_unknown_options?(config) - - # Add the remaining arguments from the options parser to the - # arguments passed in to initialize. Then remove any positional - # arguments declared using #argument (this is primarily used - # by Bundler::Thor::Group). Tis will leave us with the remaining - # positional arguments. - to_parse = args - to_parse += opts.remaining unless self.class.strict_args_position?(config) - - thor_args = Bundler::Thor::Arguments.new(self.class.arguments) - thor_args.parse(to_parse).each { |k, v| __send__("#{k}=", v) } - @args = thor_args.remaining - end - - class << self - def included(base) #:nodoc: - base.extend ClassMethods - base.send :include, Invocation - base.send :include, Shell - end - - # Returns the classes that inherits from Bundler::Thor or Bundler::Thor::Group. - # - # ==== Returns - # Array[Class] - # - def subclasses - @subclasses ||= [] - end - - # Returns the files where the subclasses are kept. - # - # ==== Returns - # Hash[path => Class] - # - def subclass_files - @subclass_files ||= Hash.new { |h, k| h[k] = [] } - end - - # Whenever a class inherits from Bundler::Thor or Bundler::Thor::Group, we should track the - # class and the file on Bundler::Thor::Base. This is the method responsable for it. - # - def register_klass_file(klass) #:nodoc: - file = caller[1].match(/(.*):\d+/)[1] - Bundler::Thor::Base.subclasses << klass unless Bundler::Thor::Base.subclasses.include?(klass) - - file_subclasses = Bundler::Thor::Base.subclass_files[File.expand_path(file)] - file_subclasses << klass unless file_subclasses.include?(klass) - end - end - - module ClassMethods - def attr_reader(*) #:nodoc: - no_commands { super } - end - - def attr_writer(*) #:nodoc: - no_commands { super } - end - - def attr_accessor(*) #:nodoc: - no_commands { super } - end - - # If you want to raise an error for unknown options, call check_unknown_options! - # This is disabled by default to allow dynamic invocations. - def check_unknown_options! - @check_unknown_options = true - end - - def check_unknown_options #:nodoc: - @check_unknown_options ||= from_superclass(:check_unknown_options, false) - end - - def check_unknown_options?(config) #:nodoc: - !!check_unknown_options - end - - # If you want to raise an error when the default value of an option does not match - # the type call check_default_type! - # This is disabled by default for compatibility. - def check_default_type! - @check_default_type = true - end - - def check_default_type #:nodoc: - @check_default_type ||= from_superclass(:check_default_type, false) - end - - def check_default_type? #:nodoc: - !!check_default_type - end - - # If true, option parsing is suspended as soon as an unknown option or a - # regular argument is encountered. All remaining arguments are passed to - # the command as regular arguments. - def stop_on_unknown_option?(command_name) #:nodoc: - false - end - - # If true, option set will not suspend the execution of the command when - # a required option is not provided. - def disable_required_check?(command_name) #:nodoc: - false - end - - # If you want only strict string args (useful when cascading thor classes), - # call strict_args_position! This is disabled by default to allow dynamic - # invocations. - def strict_args_position! - @strict_args_position = true - end - - def strict_args_position #:nodoc: - @strict_args_position ||= from_superclass(:strict_args_position, false) - end - - def strict_args_position?(config) #:nodoc: - !!strict_args_position - end - - # Adds an argument to the class and creates an attr_accessor for it. - # - # Arguments are different from options in several aspects. The first one - # is how they are parsed from the command line, arguments are retrieved - # from position: - # - # thor command NAME - # - # Instead of: - # - # thor command --name=NAME - # - # Besides, arguments are used inside your code as an accessor (self.argument), - # while options are all kept in a hash (self.options). - # - # Finally, arguments cannot have type :default or :boolean but can be - # optional (supplying :optional => :true or :required => false), although - # you cannot have a required argument after a non-required argument. If you - # try it, an error is raised. - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :optional - If the argument is optional or not. - # :type - The type of the argument, can be :string, :hash, :array, :numeric. - # :default - Default value for this argument. It cannot be required and have default values. - # :banner - String to show on usage notes. - # - # ==== Errors - # ArgumentError:: Raised if you supply a required argument after a non required one. - # - def argument(name, options = {}) - is_thor_reserved_word?(name, :argument) - no_commands { attr_accessor name } - - required = if options.key?(:optional) - !options[:optional] - elsif options.key?(:required) - options[:required] - else - options[:default].nil? - end - - remove_argument name - - if required - arguments.each do |argument| - next if argument.required? - raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " \ - "the non-required argument #{argument.human_name.inspect}." - end - end - - options[:required] = required - - arguments << Bundler::Thor::Argument.new(name, options) - end - - # Returns this class arguments, looking up in the ancestors chain. - # - # ==== Returns - # Array[Bundler::Thor::Argument] - # - def arguments - @arguments ||= from_superclass(:arguments, []) - end - - # Adds a bunch of options to the set of class options. - # - # class_options :foo => false, :bar => :required, :baz => :string - # - # If you prefer more detailed declaration, check class_option. - # - # ==== Parameters - # Hash[Symbol => Object] - # - def class_options(options = nil) - @class_options ||= from_superclass(:class_options, {}) - build_options(options, @class_options) if options - @class_options - end - - # Adds an option to the set of class options - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc:: -- Description for the argument. - # :required:: -- If the argument is required or not. - # :default:: -- Default value for this argument. - # :group:: -- The group for this options. Use by class options to output options in different levels. - # :aliases:: -- Aliases for this option. Note: Bundler::Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead. - # :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean. - # :banner:: -- String to show on usage notes. - # :hide:: -- If you want to hide this option from the help. - # - def class_option(name, options = {}) - build_option(name, options, class_options) - end - - # Removes a previous defined argument. If :undefine is given, undefine - # accessors as well. - # - # ==== Parameters - # names:: Arguments to be removed - # - # ==== Examples - # - # remove_argument :foo - # remove_argument :foo, :bar, :baz, :undefine => true - # - def remove_argument(*names) - options = names.last.is_a?(Hash) ? names.pop : {} - - names.each do |name| - arguments.delete_if { |a| a.name == name.to_s } - undef_method name, "#{name}=" if options[:undefine] - end - end - - # Removes a previous defined class option. - # - # ==== Parameters - # names:: Class options to be removed - # - # ==== Examples - # - # remove_class_option :foo - # remove_class_option :foo, :bar, :baz - # - def remove_class_option(*names) - names.each do |name| - class_options.delete(name) - end - end - - # Defines the group. This is used when thor list is invoked so you can specify - # that only commands from a pre-defined group will be shown. Defaults to standard. - # - # ==== Parameters - # name - # - def group(name = nil) - if name - @group = name.to_s - else - @group ||= from_superclass(:group, "standard") - end - end - - # Returns the commands for this Bundler::Thor class. - # - # ==== Returns - # OrderedHash:: An ordered hash with commands names as keys and Bundler::Thor::Command - # objects as values. - # - def commands - @commands ||= Bundler::Thor::CoreExt::OrderedHash.new - end - alias_method :tasks, :commands - - # Returns the commands for this Bundler::Thor class and all subclasses. - # - # ==== Returns - # OrderedHash:: An ordered hash with commands names as keys and Bundler::Thor::Command - # objects as values. - # - def all_commands - @all_commands ||= from_superclass(:all_commands, Bundler::Thor::CoreExt::OrderedHash.new) - @all_commands.merge!(commands) - end - alias_method :all_tasks, :all_commands - - # Removes a given command from this Bundler::Thor class. This is usually done if you - # are inheriting from another class and don't want it to be available - # anymore. - # - # By default it only remove the mapping to the command. But you can supply - # :undefine => true to undefine the method from the class as well. - # - # ==== Parameters - # name:: The name of the command to be removed - # options:: You can give :undefine => true if you want commands the method - # to be undefined from the class as well. - # - def remove_command(*names) - options = names.last.is_a?(Hash) ? names.pop : {} - - names.each do |name| - commands.delete(name.to_s) - all_commands.delete(name.to_s) - undef_method name if options[:undefine] - end - end - alias_method :remove_task, :remove_command - - # All methods defined inside the given block are not added as commands. - # - # So you can do: - # - # class MyScript < Bundler::Thor - # no_commands do - # def this_is_not_a_command - # end - # end - # end - # - # You can also add the method and remove it from the command list: - # - # class MyScript < Bundler::Thor - # def this_is_not_a_command - # end - # remove_command :this_is_not_a_command - # end - # - def no_commands - @no_commands = true - yield - ensure - @no_commands = false - end - alias_method :no_tasks, :no_commands - - # Sets the namespace for the Bundler::Thor or Bundler::Thor::Group class. By default the - # namespace is retrieved from the class name. If your Bundler::Thor class is named - # Scripts::MyScript, the help method, for example, will be called as: - # - # thor scripts:my_script -h - # - # If you change the namespace: - # - # namespace :my_scripts - # - # You change how your commands are invoked: - # - # thor my_scripts -h - # - # Finally, if you change your namespace to default: - # - # namespace :default - # - # Your commands can be invoked with a shortcut. Instead of: - # - # thor :my_command - # - def namespace(name = nil) - if name - @namespace = name.to_s - else - @namespace ||= Bundler::Thor::Util.namespace_from_thor_class(self) - end - end - - # Parses the command and options from the given args, instantiate the class - # and invoke the command. This method is used when the arguments must be parsed - # from an array. If you are inside Ruby and want to use a Bundler::Thor class, you - # can simply initialize it: - # - # script = MyScript.new(args, options, config) - # script.invoke(:command, first_arg, second_arg, third_arg) - # - def start(given_args = ARGV, config = {}) - config[:shell] ||= Bundler::Thor::Base.shell.new - dispatch(nil, given_args.dup, nil, config) - rescue Bundler::Thor::Error => e - config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message) - exit(1) if exit_on_failure? - rescue Errno::EPIPE - # This happens if a thor command is piped to something like `head`, - # which closes the pipe when it's done reading. This will also - # mean that if the pipe is closed, further unnecessary - # computation will not occur. - exit(0) - end - - # Allows to use private methods from parent in child classes as commands. - # - # ==== Parameters - # names:: Method names to be used as commands - # - # ==== Examples - # - # public_command :foo - # public_command :foo, :bar, :baz - # - def public_command(*names) - names.each do |name| - class_eval "def #{name}(*); super end" - end - end - alias_method :public_task, :public_command - - def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc: - raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace." if has_namespace - raise UndefinedCommandError, "Could not find command #{command.inspect}." - end - alias_method :handle_no_task_error, :handle_no_command_error - - def handle_argument_error(command, error, args, arity) #:nodoc: - name = [command.ancestor_name, command.name].compact.join(" ") - msg = "ERROR: \"#{basename} #{name}\" was called with ".dup - msg << "no arguments" if args.empty? - msg << "arguments " << args.inspect unless args.empty? - msg << "\nUsage: #{banner(command).inspect}" - raise InvocationError, msg - end - - protected - - # Prints the class options per group. If an option does not belong to - # any group, it's printed as Class option. - # - def class_options_help(shell, groups = {}) #:nodoc: - # Group options by group - class_options.each do |_, value| - groups[value.group] ||= [] - groups[value.group] << value - end - - # Deal with default group - global_options = groups.delete(nil) || [] - print_options(shell, global_options) - - # Print all others - groups.each do |group_name, options| - print_options(shell, options, group_name) - end - end - - # Receives a set of options and print them. - def print_options(shell, options, group_name = nil) - return if options.empty? - - list = [] - padding = options.map { |o| o.aliases.size }.max.to_i * 4 - - options.each do |option| - next if option.hide - item = [option.usage(padding)] - item.push(option.description ? "# #{option.description}" : "") - - list << item - list << ["", "# Default: #{option.default}"] if option.show_default? - list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum - end - - shell.say(group_name ? "#{group_name} options:" : "Options:") - shell.print_table(list, :indent => 2) - shell.say "" - end - - # Raises an error if the word given is a Bundler::Thor reserved word. - def is_thor_reserved_word?(word, type) #:nodoc: - return false unless THOR_RESERVED_WORDS.include?(word.to_s) - raise "#{word.inspect} is a Bundler::Thor reserved word and cannot be defined as #{type}" - end - - # Build an option and adds it to the given scope. - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described in both class_option and method_option. - # scope:: Options hash that is being built up - def build_option(name, options, scope) #:nodoc: - scope[name] = Bundler::Thor::Option.new(name, options.merge(:check_default_type => check_default_type?)) - end - - # Receives a hash of options, parse them and add to the scope. This is a - # fast way to set a bunch of options: - # - # build_options :foo => true, :bar => :required, :baz => :string - # - # ==== Parameters - # Hash[Symbol => Object] - def build_options(options, scope) #:nodoc: - options.each do |key, value| - scope[key] = Bundler::Thor::Option.parse(key, value) - end - end - - # Finds a command with the given name. If the command belongs to the current - # class, just return it, otherwise dup it and add the fresh copy to the - # current command hash. - def find_and_refresh_command(name) #:nodoc: - if commands[name.to_s] - commands[name.to_s] - elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition - commands[name.to_s] = command.clone - else - raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found." - end - end - alias_method :find_and_refresh_task, :find_and_refresh_command - - # Everytime someone inherits from a Bundler::Thor class, register the klass - # and file into baseclass. - def inherited(klass) - Bundler::Thor::Base.register_klass_file(klass) - klass.instance_variable_set(:@no_commands, false) - end - - # Fire this callback whenever a method is added. Added methods are - # tracked as commands by invoking the create_command method. - def method_added(meth) - meth = meth.to_s - - if meth == "initialize" - initialize_added - return - end - - # Return if it's not a public instance method - return unless public_method_defined?(meth.to_sym) - - @no_commands ||= false - return if @no_commands || !create_command(meth) - - is_thor_reserved_word?(meth, :command) - Bundler::Thor::Base.register_klass_file(self) - end - - # Retrieves a value from superclass. If it reaches the baseclass, - # returns default. - def from_superclass(method, default = nil) - if self == baseclass || !superclass.respond_to?(method, true) - default - else - value = superclass.send(method) - - # Ruby implements `dup` on Object, but raises a `TypeError` - # if the method is called on immediates. As a result, we - # don't have a good way to check whether dup will succeed - # without calling it and rescuing the TypeError. - begin - value.dup - rescue TypeError - value - end - - end - end - - # A flag that makes the process exit with status 1 if any error happens. - def exit_on_failure? - false - end - - # - # The basename of the program invoking the thor class. - # - def basename - File.basename($PROGRAM_NAME).split(" ").first - end - - # SIGNATURE: Sets the baseclass. This is where the superclass lookup - # finishes. - def baseclass #:nodoc: - end - - # SIGNATURE: Creates a new command if valid_command? is true. This method is - # called when a new method is added to the class. - def create_command(meth) #:nodoc: - end - alias_method :create_task, :create_command - - # SIGNATURE: Defines behavior when the initialize method is added to the - # class. - def initialize_added #:nodoc: - end - - # SIGNATURE: The hook invoked by start. - def dispatch(command, given_args, given_opts, config) #:nodoc: - raise NotImplementedError - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/command.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/command.rb deleted file mode 100644 index c636948e5dc..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/command.rb +++ /dev/null @@ -1,135 +0,0 @@ -class Bundler::Thor - class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name) - FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/ - - def initialize(name, description, long_description, usage, options = nil) - super(name.to_s, description, long_description, usage, options || {}) - end - - def initialize_copy(other) #:nodoc: - super(other) - self.options = other.options.dup if other.options - end - - def hidden? - false - end - - # By default, a command invokes a method in the thor class. You can change this - # implementation to create custom commands. - def run(instance, args = []) - arity = nil - - if private_method?(instance) - instance.class.handle_no_command_error(name) - elsif public_method?(instance) - arity = instance.method(name).arity - instance.__send__(name, *args) - elsif local_method?(instance, :method_missing) - instance.__send__(:method_missing, name.to_sym, *args) - else - instance.class.handle_no_command_error(name) - end - rescue ArgumentError => e - handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e, args, arity) : (raise e) - rescue NoMethodError => e - handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_command_error(name) : (raise e) - end - - # Returns the formatted usage by injecting given required arguments - # and required options into the given usage. - def formatted_usage(klass, namespace = true, subcommand = false) - if ancestor_name - formatted = "#{ancestor_name} ".dup # add space - elsif namespace - namespace = klass.namespace - formatted = "#{namespace.gsub(/^(default)/, '')}:".dup - end - formatted ||= "#{klass.namespace.split(':').last} ".dup if subcommand - - formatted ||= "".dup - - # Add usage with required arguments - formatted << if klass && !klass.arguments.empty? - usage.to_s.gsub(/^#{name}/) do |match| - match << " " << klass.arguments.map(&:usage).compact.join(" ") - end - else - usage.to_s - end - - # Add required options - formatted << " #{required_options}" - - # Strip and go! - formatted.strip - end - - protected - - def not_debugging?(instance) - !(instance.class.respond_to?(:debugging) && instance.class.debugging) - end - - def required_options - @required_options ||= options.map { |_, o| o.usage if o.required? }.compact.sort.join(" ") - end - - # Given a target, checks if this class name is a public method. - def public_method?(instance) #:nodoc: - !(instance.public_methods & [name.to_s, name.to_sym]).empty? - end - - def private_method?(instance) - !(instance.private_methods & [name.to_s, name.to_sym]).empty? - end - - def local_method?(instance, name) - methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false) - !(methods & [name.to_s, name.to_sym]).empty? - end - - def sans_backtrace(backtrace, caller) #:nodoc: - saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) || (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/) } - saned - caller - end - - def handle_argument_error?(instance, error, caller) - not_debugging?(instance) && (error.message =~ /wrong number of arguments/ || error.message =~ /given \d*, expected \d*/) && begin - saned = sans_backtrace(error.backtrace, caller) - # Ruby 1.9 always include the called method in the backtrace - saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9") - end - end - - def handle_no_method_error?(instance, error, caller) - not_debugging?(instance) && - error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ - end - end - Task = Command - - # A command that is hidden in help messages but still invocable. - class HiddenCommand < Command - def hidden? - true - end - end - HiddenTask = HiddenCommand - - # A dynamic command that handles method missing scenarios. - class DynamicCommand < Command - def initialize(name, options = nil) - super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options) - end - - def run(instance, args = []) - if (instance.methods & [name.to_s, name.to_sym]).empty? - super - else - instance.class.handle_no_command_error(name) - end - end - end - DynamicTask = DynamicCommand -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb deleted file mode 100644 index c167aa33b86..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +++ /dev/null @@ -1,97 +0,0 @@ -class Bundler::Thor - module CoreExt #:nodoc: - # A hash with indifferent access and magic predicates. - # - # hash = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true - # - # hash[:foo] #=> 'bar' - # hash['foo'] #=> 'bar' - # hash.foo? #=> true - # - class HashWithIndifferentAccess < ::Hash #:nodoc: - def initialize(hash = {}) - super() - hash.each do |key, value| - self[convert_key(key)] = value - end - end - - def [](key) - super(convert_key(key)) - end - - def []=(key, value) - super(convert_key(key), value) - end - - def delete(key) - super(convert_key(key)) - end - - def fetch(key, *args) - super(convert_key(key), *args) - end - - def key?(key) - super(convert_key(key)) - end - - def values_at(*indices) - indices.map { |key| self[convert_key(key)] } - end - - def merge(other) - dup.merge!(other) - end - - def merge!(other) - other.each do |key, value| - self[convert_key(key)] = value - end - self - end - - def reverse_merge(other) - self.class.new(other).merge(self) - end - - def reverse_merge!(other_hash) - replace(reverse_merge(other_hash)) - end - - def replace(other_hash) - super(other_hash) - end - - # Convert to a Hash with String keys. - def to_hash - Hash.new(default).merge!(self) - end - - protected - - def convert_key(key) - key.is_a?(Symbol) ? key.to_s : key - end - - # Magic predicates. For instance: - # - # options.force? # => !!options['force'] - # options.shebang # => "/usr/lib/local/ruby" - # options.test_framework?(:rspec) # => options[:test_framework] == :rspec - # - def method_missing(method, *args) - method = method.to_s - if method =~ /^(\w+)\?$/ - if args.empty? - !!self[$1] - else - self[$1] == args.first - end - else - self[method] - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb deleted file mode 100644 index 0f6e2e0af2f..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +++ /dev/null @@ -1,12 +0,0 @@ -class IO #:nodoc: - class << self - unless method_defined? :binread - def binread(file, *args) - raise ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3 - File.open(file, "rb") do |f| - f.read(*args) - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb deleted file mode 100644 index 76f1e43c657..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +++ /dev/null @@ -1,129 +0,0 @@ -class Bundler::Thor - module CoreExt - class OrderedHash < ::Hash - if RUBY_VERSION < "1.9" - def initialize(*args, &block) - super - @keys = [] - end - - def initialize_copy(other) - super - # make a deep copy of keys - @keys = other.keys - end - - def []=(key, value) - @keys << key unless key?(key) - super - end - - def delete(key) - if key? key - index = @keys.index(key) - @keys.delete_at index - end - super - end - - def delete_if - super - sync_keys! - self - end - - alias_method :reject!, :delete_if - - def reject(&block) - dup.reject!(&block) - end - - def keys - @keys.dup - end - - def values - @keys.map { |key| self[key] } - end - - def to_hash - self - end - - def to_a - @keys.map { |key| [key, self[key]] } - end - - def each_key - return to_enum(:each_key) unless block_given? - @keys.each { |key| yield(key) } - self - end - - def each_value - return to_enum(:each_value) unless block_given? - @keys.each { |key| yield(self[key]) } - self - end - - def each - return to_enum(:each) unless block_given? - @keys.each { |key| yield([key, self[key]]) } - self - end - - def each_pair - return to_enum(:each_pair) unless block_given? - @keys.each { |key| yield(key, self[key]) } - self - end - - alias_method :select, :find_all - - def clear - super - @keys.clear - self - end - - def shift - k = @keys.first - v = delete(k) - [k, v] - end - - def merge!(other_hash) - if block_given? - other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v } - else - other_hash.each { |k, v| self[k] = v } - end - self - end - - alias_method :update, :merge! - - def merge(other_hash, &block) - dup.merge!(other_hash, &block) - end - - # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not. - def replace(other) - super - @keys = other.keys - self - end - - def inspect - "#<#{self.class} #{super}>" - end - - private - - def sync_keys! - @keys.delete_if { |k| !key?(k) } - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/error.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/error.rb deleted file mode 100644 index 2f816081f35..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/error.rb +++ /dev/null @@ -1,32 +0,0 @@ -class Bundler::Thor - # Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those - # errors have their backtrace suppressed and are nicely shown to the user. - # - # Errors that are caused by the developer, like declaring a method which - # overwrites a thor keyword, SHOULD NOT raise a Bundler::Thor::Error. This way, we - # ensure that developer errors are shown with full backtrace. - class Error < StandardError - end - - # Raised when a command was not found. - class UndefinedCommandError < Error - end - UndefinedTaskError = UndefinedCommandError - - class AmbiguousCommandError < Error - end - AmbiguousTaskError = AmbiguousCommandError - - # Raised when a command was found, but not invoked properly. - class InvocationError < Error - end - - class UnknownArgumentError < Error - end - - class RequiredArgumentMissingError < InvocationError - end - - class MalformattedArgumentError < InvocationError - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/group.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/group.rb deleted file mode 100644 index 05ddc10cd30..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/group.rb +++ /dev/null @@ -1,281 +0,0 @@ -require "bundler/vendor/thor/lib/thor/base" - -# Bundler::Thor has a special class called Bundler::Thor::Group. The main difference to Bundler::Thor class -# is that it invokes all commands at once. It also include some methods that allows -# invocations to be done at the class method, which are not available to Bundler::Thor -# commands. -class Bundler::Thor::Group - class << self - # The description for this Bundler::Thor::Group. If none is provided, but a source root - # exists, tries to find the USAGE one folder above it, otherwise searches - # in the superclass. - # - # ==== Parameters - # description:: The description for this Bundler::Thor::Group. - # - def desc(description = nil) - if description - @desc = description - else - @desc ||= from_superclass(:desc, nil) - end - end - - # Prints help information. - # - # ==== Options - # short:: When true, shows only usage. - # - def help(shell) - shell.say "Usage:" - shell.say " #{banner}\n" - shell.say - class_options_help(shell) - shell.say desc if desc - end - - # Stores invocations for this class merging with superclass values. - # - def invocations #:nodoc: - @invocations ||= from_superclass(:invocations, {}) - end - - # Stores invocation blocks used on invoke_from_option. - # - def invocation_blocks #:nodoc: - @invocation_blocks ||= from_superclass(:invocation_blocks, {}) - end - - # Invoke the given namespace or class given. It adds an instance - # method that will invoke the klass and command. You can give a block to - # configure how it will be invoked. - # - # The namespace/class given will have its options showed on the help - # usage. Check invoke_from_option for more information. - # - def invoke(*names, &block) - options = names.last.is_a?(Hash) ? names.pop : {} - verbose = options.fetch(:verbose, true) - - names.each do |name| - invocations[name] = false - invocation_blocks[name] = block if block_given? - - class_eval <<-METHOD, __FILE__, __LINE__ - def _invoke_#{name.to_s.gsub(/\W/, '_')} - klass, command = self.class.prepare_for_invocation(nil, #{name.inspect}) - - if klass - say_status :invoke, #{name.inspect}, #{verbose.inspect} - block = self.class.invocation_blocks[#{name.inspect}] - _invoke_for_class_method klass, command, &block - else - say_status :error, %(#{name.inspect} [not found]), :red - end - end - METHOD - end - end - - # Invoke a thor class based on the value supplied by the user to the - # given option named "name". A class option must be created before this - # method is invoked for each name given. - # - # ==== Examples - # - # class GemGenerator < Bundler::Thor::Group - # class_option :test_framework, :type => :string - # invoke_from_option :test_framework - # end - # - # ==== Boolean options - # - # In some cases, you want to invoke a thor class if some option is true or - # false. This is automatically handled by invoke_from_option. Then the - # option name is used to invoke the generator. - # - # ==== Preparing for invocation - # - # In some cases you want to customize how a specified hook is going to be - # invoked. You can do that by overwriting the class method - # prepare_for_invocation. The class method must necessarily return a klass - # and an optional command. - # - # ==== Custom invocations - # - # You can also supply a block to customize how the option is going to be - # invoked. The block receives two parameters, an instance of the current - # class and the klass to be invoked. - # - def invoke_from_option(*names, &block) - options = names.last.is_a?(Hash) ? names.pop : {} - verbose = options.fetch(:verbose, :white) - - names.each do |name| - unless class_options.key?(name) - raise ArgumentError, "You have to define the option #{name.inspect} " \ - "before setting invoke_from_option." - end - - invocations[name] = true - invocation_blocks[name] = block if block_given? - - class_eval <<-METHOD, __FILE__, __LINE__ - def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')} - return unless options[#{name.inspect}] - - value = options[#{name.inspect}] - value = #{name.inspect} if TrueClass === value - klass, command = self.class.prepare_for_invocation(#{name.inspect}, value) - - if klass - say_status :invoke, value, #{verbose.inspect} - block = self.class.invocation_blocks[#{name.inspect}] - _invoke_for_class_method klass, command, &block - else - say_status :error, %(\#{value} [not found]), :red - end - end - METHOD - end - end - - # Remove a previously added invocation. - # - # ==== Examples - # - # remove_invocation :test_framework - # - def remove_invocation(*names) - names.each do |name| - remove_command(name) - remove_class_option(name) - invocations.delete(name) - invocation_blocks.delete(name) - end - end - - # Overwrite class options help to allow invoked generators options to be - # shown recursively when invoking a generator. - # - def class_options_help(shell, groups = {}) #:nodoc: - get_options_from_invocations(groups, class_options) do |klass| - klass.send(:get_options_from_invocations, groups, class_options) - end - super(shell, groups) - end - - # Get invocations array and merge options from invocations. Those - # options are added to group_options hash. Options that already exists - # in base_options are not added twice. - # - def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength - invocations.each do |name, from_option| - value = if from_option - option = class_options[name] - option.type == :boolean ? name : option.default - else - name - end - next unless value - - klass, _ = prepare_for_invocation(name, value) - next unless klass && klass.respond_to?(:class_options) - - value = value.to_s - human_name = value.respond_to?(:classify) ? value.classify : value - - group_options[human_name] ||= [] - group_options[human_name] += klass.class_options.values.select do |class_option| - base_options[class_option.name.to_sym].nil? && class_option.group.nil? && - !group_options.values.flatten.any? { |i| i.name == class_option.name } - end - - yield klass if block_given? - end - end - - # Returns commands ready to be printed. - def printable_commands(*) - item = [] - item << banner - item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "") - [item] - end - alias_method :printable_tasks, :printable_commands - - def handle_argument_error(command, error, _args, arity) #:nodoc: - msg = "#{basename} #{command.name} takes #{arity} argument".dup - msg << "s" if arity > 1 - msg << ", but it should not." - raise error, msg - end - - protected - - # The method responsible for dispatching given the args. - def dispatch(command, given_args, given_opts, config) #:nodoc: - if Bundler::Thor::HELP_MAPPINGS.include?(given_args.first) - help(config[:shell]) - return - end - - args, opts = Bundler::Thor::Options.split(given_args) - opts = given_opts || opts - - instance = new(args, opts, config) - yield instance if block_given? - - if command - instance.invoke_command(all_commands[command]) - else - instance.invoke_all - end - end - - # The banner for this class. You can customize it if you are invoking the - # thor class by another ways which is not the Bundler::Thor::Runner. - def banner - "#{basename} #{self_command.formatted_usage(self, false)}" - end - - # Represents the whole class as a command. - def self_command #:nodoc: - Bundler::Thor::DynamicCommand.new(namespace, class_options) - end - alias_method :self_task, :self_command - - def baseclass #:nodoc: - Bundler::Thor::Group - end - - def create_command(meth) #:nodoc: - commands[meth.to_s] = Bundler::Thor::Command.new(meth, nil, nil, nil, nil) - true - end - alias_method :create_task, :create_command - end - - include Bundler::Thor::Base - -protected - - # Shortcut to invoke with padding and block handling. Use internally by - # invoke and invoke_from_option class methods. - def _invoke_for_class_method(klass, command = nil, *args, &block) #:nodoc: - with_padding do - if block - case block.arity - when 3 - yield(self, klass, command) - when 2 - yield(self, klass) - when 1 - instance_exec(klass, &block) - end - else - invoke klass, command, *args - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/invocation.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/invocation.rb deleted file mode 100644 index 866d2212a7f..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/invocation.rb +++ /dev/null @@ -1,177 +0,0 @@ -class Bundler::Thor - module Invocation - def self.included(base) #:nodoc: - base.extend ClassMethods - end - - module ClassMethods - # This method is responsible for receiving a name and find the proper - # class and command for it. The key is an optional parameter which is - # available only in class methods invocations (i.e. in Bundler::Thor::Group). - def prepare_for_invocation(key, name) #:nodoc: - case name - when Symbol, String - Bundler::Thor::Util.find_class_and_command_by_namespace(name.to_s, !key) - else - name - end - end - end - - # Make initializer aware of invocations and the initialization args. - def initialize(args = [], options = {}, config = {}, &block) #:nodoc: - @_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] } - @_initializer = [args, options, config] - super - end - - # Make the current command chain accessible with in a Bundler::Thor-(sub)command - def current_command_chain - @_invocations.values.flatten.map(&:to_sym) - end - - # Receives a name and invokes it. The name can be a string (either "command" or - # "namespace:command"), a Bundler::Thor::Command, a Class or a Bundler::Thor instance. If the - # command cannot be guessed by name, it can also be supplied as second argument. - # - # You can also supply the arguments, options and configuration values for - # the command to be invoked, if none is given, the same values used to - # initialize the invoker are used to initialize the invoked. - # - # When no name is given, it will invoke the default command of the current class. - # - # ==== Examples - # - # class A < Bundler::Thor - # def foo - # invoke :bar - # invoke "b:hello", ["Erik"] - # end - # - # def bar - # invoke "b:hello", ["Erik"] - # end - # end - # - # class B < Bundler::Thor - # def hello(name) - # puts "hello #{name}" - # end - # end - # - # You can notice that the method "foo" above invokes two commands: "bar", - # which belongs to the same class and "hello" which belongs to the class B. - # - # By using an invocation system you ensure that a command is invoked only once. - # In the example above, invoking "foo" will invoke "b:hello" just once, even - # if it's invoked later by "bar" method. - # - # When class A invokes class B, all arguments used on A initialization are - # supplied to B. This allows lazy parse of options. Let's suppose you have - # some rspec commands: - # - # class Rspec < Bundler::Thor::Group - # class_option :mock_framework, :type => :string, :default => :rr - # - # def invoke_mock_framework - # invoke "rspec:#{options[:mock_framework]}" - # end - # end - # - # As you noticed, it invokes the given mock framework, which might have its - # own options: - # - # class Rspec::RR < Bundler::Thor::Group - # class_option :style, :type => :string, :default => :mock - # end - # - # Since it's not rspec concern to parse mock framework options, when RR - # is invoked all options are parsed again, so RR can extract only the options - # that it's going to use. - # - # If you want Rspec::RR to be initialized with its own set of options, you - # have to do that explicitly: - # - # invoke "rspec:rr", [], :style => :foo - # - # Besides giving an instance, you can also give a class to invoke: - # - # invoke Rspec::RR, [], :style => :foo - # - def invoke(name = nil, *args) - if name.nil? - warn "[Bundler::Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}" - return invoke_all - end - - args.unshift(nil) if args.first.is_a?(Array) || args.first.nil? - command, args, opts, config = args - - klass, command = _retrieve_class_and_command(name, command) - raise "Missing Bundler::Thor class for invoke #{name}" unless klass - raise "Expected Bundler::Thor class, got #{klass}" unless klass <= Bundler::Thor::Base - - args, opts, config = _parse_initialization_options(args, opts, config) - klass.send(:dispatch, command, args, opts, config) do |instance| - instance.parent_options = options - end - end - - # Invoke the given command if the given args. - def invoke_command(command, *args) #:nodoc: - current = @_invocations[self.class] - - unless current.include?(command.name) - current << command.name - command.run(self, *args) - end - end - alias_method :invoke_task, :invoke_command - - # Invoke all commands for the current instance. - def invoke_all #:nodoc: - self.class.all_commands.map { |_, command| invoke_command(command) } - end - - # Invokes using shell padding. - def invoke_with_padding(*args) - with_padding { invoke(*args) } - end - - protected - - # Configuration values that are shared between invocations. - def _shared_configuration #:nodoc: - {:invocations => @_invocations} - end - - # This method simply retrieves the class and command to be invoked. - # If the name is nil or the given name is a command in the current class, - # use the given name and return self as class. Otherwise, call - # prepare_for_invocation in the current class. - def _retrieve_class_and_command(name, sent_command = nil) #:nodoc: - if name.nil? - [self.class, nil] - elsif self.class.all_commands[name.to_s] - [self.class, name.to_s] - else - klass, command = self.class.prepare_for_invocation(nil, name) - [klass, command || sent_command] - end - end - alias_method :_retrieve_class_and_task, :_retrieve_class_and_command - - # Initialize klass using values stored in the @_initializer. - def _parse_initialization_options(args, opts, config) #:nodoc: - stored_args, stored_opts, stored_config = @_initializer - - args ||= stored_args.dup - opts ||= stored_opts.dup - - config ||= {} - config = stored_config.merge(_shared_configuration).merge!(config) - - [args, opts, config] - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor.rb deleted file mode 100644 index ce81a17484d..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor.rb +++ /dev/null @@ -1,17 +0,0 @@ -require "bundler/vendor/thor/lib/thor/line_editor/basic" -require "bundler/vendor/thor/lib/thor/line_editor/readline" - -class Bundler::Thor - module LineEditor - def self.readline(prompt, options = {}) - best_available.new(prompt, options).readline - end - - def self.best_available - [ - Bundler::Thor::LineEditor::Readline, - Bundler::Thor::LineEditor::Basic - ].detect(&:available?) - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor/basic.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor/basic.rb deleted file mode 100644 index 0adb2b3137f..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor/basic.rb +++ /dev/null @@ -1,37 +0,0 @@ -class Bundler::Thor - module LineEditor - class Basic - attr_reader :prompt, :options - - def self.available? - true - end - - def initialize(prompt, options) - @prompt = prompt - @options = options - end - - def readline - $stdout.print(prompt) - get_input - end - - private - - def get_input - if echo? - $stdin.gets - else - # Lazy-load io/console since it is gem-ified as of 2.3 - require "io/console" if RUBY_VERSION > "1.9.2" - $stdin.noecho(&:gets) - end - end - - def echo? - options.fetch(:echo, true) - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor/readline.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor/readline.rb deleted file mode 100644 index dd39cff35dc..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/line_editor/readline.rb +++ /dev/null @@ -1,88 +0,0 @@ -begin - require "readline" -rescue LoadError -end - -class Bundler::Thor - module LineEditor - class Readline < Basic - def self.available? - Object.const_defined?(:Readline) - end - - def readline - if echo? - ::Readline.completion_append_character = nil - # Ruby 1.8.7 does not allow Readline.completion_proc= to receive nil. - if complete = completion_proc - ::Readline.completion_proc = complete - end - ::Readline.readline(prompt, add_to_history?) - else - super - end - end - - private - - def add_to_history? - options.fetch(:add_to_history, true) - end - - def completion_proc - if use_path_completion? - proc { |text| PathCompletion.new(text).matches } - elsif completion_options.any? - proc do |text| - completion_options.select { |option| option.start_with?(text) } - end - end - end - - def completion_options - options.fetch(:limited_to, []) - end - - def use_path_completion? - options.fetch(:path, false) - end - - class PathCompletion - attr_reader :text - private :text - - def initialize(text) - @text = text - end - - def matches - relative_matches - end - - private - - def relative_matches - absolute_matches.map { |path| path.sub(base_path, "") } - end - - def absolute_matches - Dir[glob_pattern].map do |path| - if File.directory?(path) - "#{path}/" - else - path - end - end - end - - def glob_pattern - "#{base_path}#{text}*" - end - - def base_path - "#{Dir.pwd}/" - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser.rb deleted file mode 100644 index 08f80e565de..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser.rb +++ /dev/null @@ -1,4 +0,0 @@ -require "bundler/vendor/thor/lib/thor/parser/argument" -require "bundler/vendor/thor/lib/thor/parser/arguments" -require "bundler/vendor/thor/lib/thor/parser/option" -require "bundler/vendor/thor/lib/thor/parser/options" diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/argument.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/argument.rb deleted file mode 100644 index dfe73985835..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/argument.rb +++ /dev/null @@ -1,70 +0,0 @@ -class Bundler::Thor - class Argument #:nodoc: - VALID_TYPES = [:numeric, :hash, :array, :string] - - attr_reader :name, :description, :enum, :required, :type, :default, :banner - alias_method :human_name, :name - - def initialize(name, options = {}) - class_name = self.class.name.split("::").last - - type = options[:type] - - raise ArgumentError, "#{class_name} name can't be nil." if name.nil? - raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) - - @name = name.to_s - @description = options[:desc] - @required = options.key?(:required) ? options[:required] : true - @type = (type || :string).to_sym - @default = options[:default] - @banner = options[:banner] || default_banner - @enum = options[:enum] - - validate! # Trigger specific validations - end - - def usage - required? ? banner : "[#{banner}]" - end - - def required? - required - end - - def show_default? - case default - when Array, String, Hash - !default.empty? - else - default - end - end - - protected - - def validate! - raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? - raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array) - end - - def valid_type?(type) - self.class::VALID_TYPES.include?(type.to_sym) - end - - def default_banner - case type - when :boolean - nil - when :string, :default - human_name.upcase - when :numeric - "N" - when :hash - "key:value" - when :array - "one two three" - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/arguments.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/arguments.rb deleted file mode 100644 index 1fd790f4b73..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/arguments.rb +++ /dev/null @@ -1,175 +0,0 @@ -class Bundler::Thor - class Arguments #:nodoc: # rubocop:disable ClassLength - NUMERIC = /[-+]?(\d*\.\d+|\d+)/ - - # Receives an array of args and returns two arrays, one with arguments - # and one with switches. - # - def self.split(args) - arguments = [] - - args.each do |item| - break if item =~ /^-/ - arguments << item - end - - [arguments, args[Range.new(arguments.size, -1)]] - end - - def self.parse(*args) - to_parse = args.pop - new(*args).parse(to_parse) - end - - # Takes an array of Bundler::Thor::Argument objects. - # - def initialize(arguments = []) - @assigns = {} - @non_assigned_required = [] - @switches = arguments - - arguments.each do |argument| - if !argument.default.nil? - @assigns[argument.human_name] = argument.default - elsif argument.required? - @non_assigned_required << argument - end - end - end - - def parse(args) - @pile = args.dup - - @switches.each do |argument| - break unless peek - @non_assigned_required.delete(argument) - @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name) - end - - check_requirement! - @assigns - end - - def remaining - @pile - end - - private - - def no_or_skip?(arg) - arg =~ /^--(no|skip)-([-\w]+)$/ - $2 - end - - def last? - @pile.empty? - end - - def peek - @pile.first - end - - def shift - @pile.shift - end - - def unshift(arg) - if arg.is_a?(Array) - @pile = arg + @pile - else - @pile.unshift(arg) - end - end - - def current_is_value? - peek && peek.to_s !~ /^-/ - end - - # Runs through the argument array getting strings that contains ":" and - # mark it as a hash: - # - # [ "name:string", "age:integer" ] - # - # Becomes: - # - # { "name" => "string", "age" => "integer" } - # - def parse_hash(name) - return shift if peek.is_a?(Hash) - hash = {} - - while current_is_value? && peek.include?(":") - key, value = shift.split(":", 2) - raise MalformattedArgumentError, "You can't specify '#{key}' more than once in option '#{name}'; got #{key}:#{hash[key]} and #{key}:#{value}" if hash.include? key - hash[key] = value - end - hash - end - - # Runs through the argument array getting all strings until no string is - # found or a switch is found. - # - # ["a", "b", "c"] - # - # And returns it as an array: - # - # ["a", "b", "c"] - # - def parse_array(name) - return shift if peek.is_a?(Array) - array = [] - array << shift while current_is_value? - array - end - - # Check if the peek is numeric format and return a Float or Integer. - # Check if the peek is included in enum if enum is provided. - # Otherwise raises an error. - # - def parse_numeric(name) - return shift if peek.is_a?(Numeric) - - unless peek =~ NUMERIC && $& == peek - raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}" - end - - value = $&.index(".") ? shift.to_f : shift.to_i - if @switches.is_a?(Hash) && switch = @switches[name] - if switch.enum && !switch.enum.include?(value) - raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" - end - end - value - end - - # Parse string: - # for --string-arg, just return the current value in the pile - # for --no-string-arg, nil - # Check if the peek is included in enum if enum is provided. Otherwise raises an error. - # - def parse_string(name) - if no_or_skip?(name) - nil - else - value = shift - if @switches.is_a?(Hash) && switch = @switches[name] - if switch.enum && !switch.enum.include?(value) - raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" - end - end - value - end - end - - # Raises an error if @non_assigned_required array is not empty. - # - def check_requirement! - return if @non_assigned_required.empty? - names = @non_assigned_required.map do |o| - o.respond_to?(:switch_name) ? o.switch_name : o.human_name - end.join("', '") - class_name = self.class.name.split("::").last.downcase - raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'" - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/option.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/option.rb deleted file mode 100644 index 85169b56c8b..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/option.rb +++ /dev/null @@ -1,146 +0,0 @@ -class Bundler::Thor - class Option < Argument #:nodoc: - attr_reader :aliases, :group, :lazy_default, :hide - - VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] - - def initialize(name, options = {}) - @check_default_type = options[:check_default_type] - options[:required] = false unless options.key?(:required) - super - @lazy_default = options[:lazy_default] - @group = options[:group].to_s.capitalize if options[:group] - @aliases = Array(options[:aliases]) - @hide = options[:hide] - end - - # This parse quick options given as method_options. It makes several - # assumptions, but you can be more specific using the option method. - # - # parse :foo => "bar" - # #=> Option foo with default value bar - # - # parse [:foo, :baz] => "bar" - # #=> Option foo with default value bar and alias :baz - # - # parse :foo => :required - # #=> Required option foo without default value - # - # parse :foo => 2 - # #=> Option foo with default value 2 and type numeric - # - # parse :foo => :numeric - # #=> Option foo without default value and type numeric - # - # parse :foo => true - # #=> Option foo with default value true and type boolean - # - # The valid types are :boolean, :numeric, :hash, :array and :string. If none - # is given a default type is assumed. This default type accepts arguments as - # string (--foo=value) or booleans (just --foo). - # - # By default all options are optional, unless :required is given. - # - def self.parse(key, value) - if key.is_a?(Array) - name, *aliases = key - else - name = key - aliases = [] - end - - name = name.to_s - default = value - - type = case value - when Symbol - default = nil - if VALID_TYPES.include?(value) - value - elsif required = (value == :required) # rubocop:disable AssignmentInCondition - :string - end - when TrueClass, FalseClass - :boolean - when Numeric - :numeric - when Hash, Array, String - value.class.name.downcase.to_sym - end - - new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases) - end - - def switch_name - @switch_name ||= dasherized? ? name : dasherize(name) - end - - def human_name - @human_name ||= dasherized? ? undasherize(name) : name - end - - def usage(padding = 0) - sample = if banner && !banner.to_s.empty? - "#{switch_name}=#{banner}".dup - else - switch_name - end - - sample = "[#{sample}]".dup unless required? - - if boolean? - sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-") - end - - if aliases.empty? - (" " * padding) << sample - else - "#{aliases.join(', ')}, #{sample}" - end - end - - VALID_TYPES.each do |type| - class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{type}? - self.type == #{type.inspect} - end - RUBY - end - - protected - - def validate! - raise ArgumentError, "An option cannot be boolean and required." if boolean? && required? - validate_default_type! if @check_default_type - end - - def validate_default_type! - default_type = case @default - when nil - return - when TrueClass, FalseClass - required? ? :string : :boolean - when Numeric - :numeric - when Symbol - :string - when Hash, Array, String - @default.class.name.downcase.to_sym - end - - raise ArgumentError, "Expected #{@type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})" unless default_type == @type - end - - def dasherized? - name.index("-") == 0 - end - - def undasherize(str) - str.sub(/^-{1,2}/, "") - end - - def dasherize(str) - (str.length > 1 ? "--" : "-") + str.tr("_", "-") - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/options.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/options.rb deleted file mode 100644 index 70f6366842c..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/parser/options.rb +++ /dev/null @@ -1,221 +0,0 @@ -class Bundler::Thor - class Options < Arguments #:nodoc: # rubocop:disable ClassLength - LONG_RE = /^(--\w+(?:-\w+)*)$/ - SHORT_RE = /^(-[a-z])$/i - EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i - SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args - SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i - OPTS_END = "--".freeze - - # Receives a hash and makes it switches. - def self.to_switches(options) - options.map do |key, value| - case value - when true - "--#{key}" - when Array - "--#{key} #{value.map(&:inspect).join(' ')}" - when Hash - "--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}" - when nil, false - nil - else - "--#{key} #{value.inspect}" - end - end.compact.join(" ") - end - - # Takes a hash of Bundler::Thor::Option and a hash with defaults. - # - # If +stop_on_unknown+ is true, #parse will stop as soon as it encounters - # an unknown option or a regular argument. - def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false) - @stop_on_unknown = stop_on_unknown - @disable_required_check = disable_required_check - options = hash_options.values - super(options) - - # Add defaults - defaults.each do |key, value| - @assigns[key.to_s] = value - @non_assigned_required.delete(hash_options[key]) - end - - @shorts = {} - @switches = {} - @extra = [] - - options.each do |option| - @switches[option.switch_name] = option - - option.aliases.each do |short| - name = short.to_s.sub(/^(?!\-)/, "-") - @shorts[name] ||= option.switch_name - end - end - end - - def remaining - @extra - end - - def peek - return super unless @parsing_options - - result = super - if result == OPTS_END - shift - @parsing_options = false - super - else - result - end - end - - def parse(args) # rubocop:disable MethodLength - @pile = args.dup - @parsing_options = true - - while peek - if parsing_options? - match, is_switch = current_is_switch? - shifted = shift - - if is_switch - case shifted - when SHORT_SQ_RE - unshift($1.split("").map { |f| "-#{f}" }) - next - when EQ_RE, SHORT_NUM - unshift($2) - switch = $1 - when LONG_RE, SHORT_RE - switch = $1 - end - - switch = normalize_switch(switch) - option = switch_option(switch) - @assigns[option.human_name] = parse_peek(switch, option) - elsif @stop_on_unknown - @parsing_options = false - @extra << shifted - @extra << shift while peek - break - elsif match - @extra << shifted - @extra << shift while peek && peek !~ /^-/ - else - @extra << shifted - end - else - @extra << shift - end - end - - check_requirement! unless @disable_required_check - - assigns = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new(@assigns) - assigns.freeze - assigns - end - - def check_unknown! - # an unknown option starts with - or -- and has no more --'s afterward. - unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ } - raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty? - end - - protected - - # Check if the current value in peek is a registered switch. - # - # Two booleans are returned. The first is true if the current value - # starts with a hyphen; the second is true if it is a registered switch. - def current_is_switch? - case peek - when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM - [true, switch?($1)] - when SHORT_SQ_RE - [true, $1.split("").any? { |f| switch?("-#{f}") }] - else - [false, false] - end - end - - def current_is_switch_formatted? - case peek - when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE - true - else - false - end - end - - def current_is_value? - peek && (!parsing_options? || super) - end - - def switch?(arg) - switch_option(normalize_switch(arg)) - end - - def switch_option(arg) - if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition - @switches[arg] || @switches["--#{match}"] - else - @switches[arg] - end - end - - # Check if the given argument is actually a shortcut. - # - def normalize_switch(arg) - (@shorts[arg] || arg).tr("_", "-") - end - - def parsing_options? - peek - @parsing_options - end - - # Parse boolean values which can be given as --foo=true, --foo or --no-foo. - # - def parse_boolean(switch) - if current_is_value? - if ["true", "TRUE", "t", "T", true].include?(peek) - shift - true - elsif ["false", "FALSE", "f", "F", false].include?(peek) - shift - false - else - !no_or_skip?(switch) - end - else - @switches.key?(switch) || !no_or_skip?(switch) - end - end - - # Parse the value at the peek analyzing if it requires an input or not. - # - def parse_peek(switch, option) - if parsing_options? && (current_is_switch_formatted? || last?) - if option.boolean? - # No problem for boolean types - elsif no_or_skip?(switch) - return nil # User set value to nil - elsif option.string? && !option.required? - # Return the default if there is one, else the human name - return option.lazy_default || option.default || option.human_name - elsif option.lazy_default - return option.lazy_default - else - raise MalformattedArgumentError, "No value provided for option '#{switch}'" - end - end - - @non_assigned_required.delete(option) - send(:"parse_#{option.type}", switch) - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/rake_compat.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/rake_compat.rb deleted file mode 100644 index 60282e29914..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/rake_compat.rb +++ /dev/null @@ -1,71 +0,0 @@ -require "rake" -require "rake/dsl_definition" - -class Bundler::Thor - # Adds a compatibility layer to your Bundler::Thor classes which allows you to use - # rake package tasks. For example, to use rspec rake tasks, one can do: - # - # require 'bundler/vendor/thor/lib/thor/rake_compat' - # require 'rspec/core/rake_task' - # - # class Default < Bundler::Thor - # include Bundler::Thor::RakeCompat - # - # RSpec::Core::RakeTask.new(:spec) do |t| - # t.spec_opts = ['--options', './.rspec'] - # t.spec_files = FileList['spec/**/*_spec.rb'] - # end - # end - # - module RakeCompat - include Rake::DSL if defined?(Rake::DSL) - - def self.rake_classes - @rake_classes ||= [] - end - - def self.included(base) - # Hack. Make rakefile point to invoker, so rdoc task is generated properly. - rakefile = File.basename(caller[0].match(/(.*):\d+/)[1]) - Rake.application.instance_variable_set(:@rakefile, rakefile) - rake_classes << base - end - end -end - -# override task on (main), for compatibility with Rake 0.9 -instance_eval do - alias rake_namespace namespace - - def task(*) - task = super - - if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition - non_namespaced_name = task.name.split(":").last - - description = non_namespaced_name - description << task.arg_names.map { |n| n.to_s.upcase }.join(" ") - description.strip! - - klass.desc description, Rake.application.last_description || non_namespaced_name - Rake.application.last_description = nil - klass.send :define_method, non_namespaced_name do |*args| - Rake::Task[task.name.to_sym].invoke(*args) - end - end - - task - end - - def namespace(name) - if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition - const_name = Bundler::Thor::Util.camel_case(name.to_s).to_sym - klass.const_set(const_name, Class.new(Bundler::Thor)) - new_klass = klass.const_get(const_name) - Bundler::Thor::RakeCompat.rake_classes << new_klass - end - - super - Bundler::Thor::RakeCompat.rake_classes.pop - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/runner.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/runner.rb deleted file mode 100644 index b110b8d4781..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/runner.rb +++ /dev/null @@ -1,324 +0,0 @@ -require "bundler/vendor/thor/lib/thor" -require "bundler/vendor/thor/lib/thor/group" -require "bundler/vendor/thor/lib/thor/core_ext/io_binary_read" - -require "yaml" -require "digest" -require "pathname" - -class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength - map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version - - def self.banner(command, all = false, subcommand = false) - "thor " + command.formatted_usage(self, all, subcommand) - end - - def self.exit_on_failure? - true - end - - # Override Bundler::Thor#help so it can give information about any class and any method. - # - def help(meth = nil) - if meth && !respond_to?(meth) - initialize_thorfiles(meth) - klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth) - self.class.handle_no_command_error(command, false) if klass.nil? - klass.start(["-h", command].compact, :shell => shell) - else - super - end - end - - # If a command is not found on Bundler::Thor::Runner, method missing is invoked and - # Bundler::Thor::Runner is then responsible for finding the command in all classes. - # - def method_missing(meth, *args) - meth = meth.to_s - initialize_thorfiles(meth) - klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth) - self.class.handle_no_command_error(command, false) if klass.nil? - args.unshift(command) if command - klass.start(args, :shell => shell) - end - - desc "install NAME", "Install an optionally named Bundler::Thor file into your system commands" - method_options :as => :string, :relative => :boolean, :force => :boolean - def install(name) # rubocop:disable MethodLength - initialize_thorfiles - - # If a directory name is provided as the argument, look for a 'main.thor' - # command in said directory. - begin - if File.directory?(File.expand_path(name)) - base = File.join(name, "main.thor") - package = :directory - contents = open(base, &:read) - else - base = name - package = :file - contents = open(name, &:read) - end - rescue OpenURI::HTTPError - raise Error, "Error opening URI '#{name}'" - rescue Errno::ENOENT - raise Error, "Error opening file '#{name}'" - end - - say "Your Bundler::Thorfile contains:" - say contents - - unless options["force"] - return false if no?("Do you wish to continue [y/N]?") - end - - as = options["as"] || begin - first_line = contents.split("\n")[0] - (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil - end - - unless as - basename = File.basename(name) - as = ask("Please specify a name for #{name} in the system repository [#{basename}]:") - as = basename if as.empty? - end - - location = if options[:relative] || name =~ %r{^https?://} - name - else - File.expand_path(name) - end - - thor_yaml[as] = { - :filename => Digest(:MD5).hexdigest(name + as), - :location => location, - :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base) - } - - save_yaml(thor_yaml) - say "Storing thor file in your system repository" - destination = File.join(thor_root, thor_yaml[as][:filename]) - - if package == :file - File.open(destination, "w") { |f| f.puts contents } - else - require "fileutils" - FileUtils.cp_r(name, destination) - end - - thor_yaml[as][:filename] # Indicate success - end - - desc "version", "Show Bundler::Thor version" - def version - require "bundler/vendor/thor/lib/thor/version" - say "Bundler::Thor #{Bundler::Thor::VERSION}" - end - - desc "uninstall NAME", "Uninstall a named Bundler::Thor module" - def uninstall(name) - raise Error, "Can't find module '#{name}'" unless thor_yaml[name] - say "Uninstalling #{name}." - require "fileutils" - FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s)) - - thor_yaml.delete(name) - save_yaml(thor_yaml) - - puts "Done." - end - - desc "update NAME", "Update a Bundler::Thor file from its original location" - def update(name) - raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location] - - say "Updating '#{name}' from #{thor_yaml[name][:location]}" - - old_filename = thor_yaml[name][:filename] - self.options = options.merge("as" => name) - - if File.directory? File.expand_path(name) - require "fileutils" - FileUtils.rm_rf(File.join(thor_root, old_filename)) - - thor_yaml.delete(old_filename) - save_yaml(thor_yaml) - - filename = install(name) - else - filename = install(thor_yaml[name][:location]) - end - - File.delete(File.join(thor_root, old_filename)) unless filename == old_filename - end - - desc "installed", "List the installed Bundler::Thor modules and commands" - method_options :internal => :boolean - def installed - initialize_thorfiles(nil, true) - display_klasses(true, options["internal"]) - end - - desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)" - method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean - def list(search = "") - initialize_thorfiles - - search = ".*#{search}" if options["substring"] - search = /^#{search}.*/i - group = options[:group] || "standard" - - klasses = Bundler::Thor::Base.subclasses.select do |k| - (options[:all] || k.group == group) && k.namespace =~ search - end - - display_klasses(false, false, klasses) - end - -private - - def thor_root - Bundler::Thor::Util.thor_root - end - - def thor_yaml - @thor_yaml ||= begin - yaml_file = File.join(thor_root, "thor.yml") - yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file) - yaml || {} - end - end - - # Save the yaml file. If none exists in thor root, creates one. - # - def save_yaml(yaml) - yaml_file = File.join(thor_root, "thor.yml") - - unless File.exist?(yaml_file) - require "fileutils" - FileUtils.mkdir_p(thor_root) - yaml_file = File.join(thor_root, "thor.yml") - FileUtils.touch(yaml_file) - end - - File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml } - end - - # Load the Bundler::Thorfiles. If relevant_to is supplied, looks for specific files - # in the thor_root instead of loading them all. - # - # By default, it also traverses the current path until find Bundler::Thor files, as - # described in thorfiles. This look up can be skipped by supplying - # skip_lookup true. - # - def initialize_thorfiles(relevant_to = nil, skip_lookup = false) - thorfiles(relevant_to, skip_lookup).each do |f| - Bundler::Thor::Util.load_thorfile(f, nil, options[:debug]) unless Bundler::Thor::Base.subclass_files.keys.include?(File.expand_path(f)) - end - end - - # Finds Bundler::Thorfiles by traversing from your current directory down to the root - # directory of your system. If at any time we find a Bundler::Thor file, we stop. - # - # We also ensure that system-wide Bundler::Thorfiles are loaded first, so local - # Bundler::Thorfiles can override them. - # - # ==== Example - # - # If we start at /Users/wycats/dev/thor ... - # - # 1. /Users/wycats/dev/thor - # 2. /Users/wycats/dev - # 3. /Users/wycats <-- we find a Bundler::Thorfile here, so we stop - # - # Suppose we start at c:\Documents and Settings\james\dev\thor ... - # - # 1. c:\Documents and Settings\james\dev\thor - # 2. c:\Documents and Settings\james\dev - # 3. c:\Documents and Settings\james - # 4. c:\Documents and Settings - # 5. c:\ <-- no Bundler::Thorfiles found! - # - def thorfiles(relevant_to = nil, skip_lookup = false) - thorfiles = [] - - unless skip_lookup - Pathname.pwd.ascend do |path| - thorfiles = Bundler::Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten - break unless thorfiles.empty? - end - end - - files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Bundler::Thor::Util.thor_root_glob) - files += thorfiles - files -= ["#{thor_root}/thor.yml"] - - files.map! do |file| - File.directory?(file) ? File.join(file, "main.thor") : file - end - end - - # Load Bundler::Thorfiles relevant to the given method. If you provide "foo:bar" it - # will load all thor files in the thor.yaml that has "foo" e "foo:bar" - # namespaces registered. - # - def thorfiles_relevant_to(meth) - lookup = [meth, meth.split(":")[0...-1].join(":")] - - files = thor_yaml.select do |_, v| - v[:namespaces] && !(v[:namespaces] & lookup).empty? - end - - files.map { |_, v| File.join(thor_root, (v[:filename]).to_s) } - end - - # Display information about the given klasses. If with_module is given, - # it shows a table with information extracted from the yaml file. - # - def display_klasses(with_modules = false, show_internal = false, klasses = Bundler::Thor::Base.subclasses) - klasses -= [Bundler::Thor, Bundler::Thor::Runner, Bundler::Thor::Group] unless show_internal - - raise Error, "No Bundler::Thor commands available" if klasses.empty? - show_modules if with_modules && !thor_yaml.empty? - - list = Hash.new { |h, k| h[k] = [] } - groups = klasses.select { |k| k.ancestors.include?(Bundler::Thor::Group) } - - # Get classes which inherit from Bundler::Thor - (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) } - - # Get classes which inherit from Bundler::Thor::Base - groups.map! { |k| k.printable_commands(false).first } - list["root"] = groups - - # Order namespaces with default coming first - list = list.sort { |a, b| a[0].sub(/^default/, "") <=> b[0].sub(/^default/, "") } - list.each { |n, commands| display_commands(n, commands) unless commands.empty? } - end - - def display_commands(namespace, list) #:nodoc: - list.sort! { |a, b| a[0] <=> b[0] } - - say shell.set_color(namespace, :blue, true) - say "-" * namespace.size - - print_table(list, :truncate => true) - say - end - alias_method :display_tasks, :display_commands - - def show_modules #:nodoc: - info = [] - labels = %w(Modules Namespaces) - - info << labels - info << ["-" * labels[0].size, "-" * labels[1].size] - - thor_yaml.each do |name, hash| - info << [name, hash[:namespaces].join(", ")] - end - - print_table info - say "" - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell.rb deleted file mode 100644 index e9455493242..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell.rb +++ /dev/null @@ -1,81 +0,0 @@ -require "rbconfig" - -class Bundler::Thor - module Base - class << self - attr_writer :shell - - # Returns the shell used in all Bundler::Thor classes. If you are in a Unix platform - # it will use a colored log, otherwise it will use a basic one without color. - # - def shell - @shell ||= if ENV["THOR_SHELL"] && !ENV["THOR_SHELL"].empty? - Bundler::Thor::Shell.const_get(ENV["THOR_SHELL"]) - elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"] - Bundler::Thor::Shell::Basic - else - Bundler::Thor::Shell::Color - end - end - end - end - - module Shell - SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width] - attr_writer :shell - - autoload :Basic, "bundler/vendor/thor/lib/thor/shell/basic" - autoload :Color, "bundler/vendor/thor/lib/thor/shell/color" - autoload :HTML, "bundler/vendor/thor/lib/thor/shell/html" - - # Add shell to initialize config values. - # - # ==== Configuration - # shell:: An instance of the shell to be used. - # - # ==== Examples - # - # class MyScript < Bundler::Thor - # argument :first, :type => :numeric - # end - # - # MyScript.new [1.0], { :foo => :bar }, :shell => Bundler::Thor::Shell::Basic.new - # - def initialize(args = [], options = {}, config = {}) - super - self.shell = config[:shell] - shell.base ||= self if shell.respond_to?(:base) - end - - # Holds the shell for the given Bundler::Thor instance. If no shell is given, - # it gets a default shell from Bundler::Thor::Base.shell. - def shell - @shell ||= Bundler::Thor::Base.shell.new - end - - # Common methods that are delegated to the shell. - SHELL_DELEGATED_METHODS.each do |method| - module_eval <<-METHOD, __FILE__, __LINE__ - def #{method}(*args,&block) - shell.#{method}(*args,&block) - end - METHOD - end - - # Yields the given block with padding. - def with_padding - shell.padding += 1 - yield - ensure - shell.padding -= 1 - end - - protected - - # Allow shell to be shared between invocations. - # - def _shared_configuration #:nodoc: - super.merge!(:shell => shell) - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/basic.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/basic.rb deleted file mode 100644 index 5162390efd1..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/basic.rb +++ /dev/null @@ -1,437 +0,0 @@ -class Bundler::Thor - module Shell - class Basic - attr_accessor :base - attr_reader :padding - - # Initialize base, mute and padding to nil. - # - def initialize #:nodoc: - @base = nil - @mute = false - @padding = 0 - @always_force = false - end - - # Mute everything that's inside given block - # - def mute - @mute = true - yield - ensure - @mute = false - end - - # Check if base is muted - # - def mute? - @mute - end - - # Sets the output padding, not allowing less than zero values. - # - def padding=(value) - @padding = [0, value].max - end - - # Sets the output padding while executing a block and resets it. - # - def indent(count = 1) - orig_padding = padding - self.padding = padding + count - yield - self.padding = orig_padding - end - - # Asks something to the user and receives a response. - # - # If asked to limit the correct responses, you can pass in an - # array of acceptable answers. If one of those is not supplied, - # they will be shown a message stating that one of those answers - # must be given and re-asked the question. - # - # If asking for sensitive information, the :echo option can be set - # to false to mask user input from $stdin. - # - # If the required input is a path, then set the path option to - # true. This will enable tab completion for file paths relative - # to the current working directory on systems that support - # Readline. - # - # ==== Example - # ask("What is your name?") - # - # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"]) - # - # ask("What is your password?", :echo => false) - # - # ask("Where should the file be saved?", :path => true) - # - def ask(statement, *args) - options = args.last.is_a?(Hash) ? args.pop : {} - color = args.first - - if options[:limited_to] - ask_filtered(statement, color, options) - else - ask_simply(statement, color, options) - end - end - - # Say (print) something to the user. If the sentence ends with a whitespace - # or tab character, a new line is not appended (print + flush). Otherwise - # are passed straight to puts (behavior got from Highline). - # - # ==== Example - # say("I know you knew that.") - # - def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/)) - buffer = prepare_message(message, *color) - buffer << "\n" if force_new_line && !message.to_s.end_with?("\n") - - stdout.print(buffer) - stdout.flush - end - - # Say a status with the given color and appends the message. Since this - # method is used frequently by actions, it allows nil or false to be given - # in log_status, avoiding the message from being shown. If a Symbol is - # given in log_status, it's used as the color. - # - def say_status(status, message, log_status = true) - return if quiet? || log_status == false - spaces = " " * (padding + 1) - color = log_status.is_a?(Symbol) ? log_status : :green - - status = status.to_s.rjust(12) - status = set_color status, color, true if color - - buffer = "#{status}#{spaces}#{message}" - buffer = "#{buffer}\n" unless buffer.end_with?("\n") - - stdout.print(buffer) - stdout.flush - end - - # Make a question the to user and returns true if the user replies "y" or - # "yes". - # - def yes?(statement, color = nil) - !!(ask(statement, color, :add_to_history => false) =~ is?(:yes)) - end - - # Make a question the to user and returns true if the user replies "n" or - # "no". - # - def no?(statement, color = nil) - !!(ask(statement, color, :add_to_history => false) =~ is?(:no)) - end - - # Prints values in columns - # - # ==== Parameters - # Array[String, String, ...] - # - def print_in_columns(array) - return if array.empty? - colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2 - array.each_with_index do |value, index| - # Don't output trailing spaces when printing the last column - if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length - stdout.puts value - else - stdout.printf("%-#{colwidth}s", value) - end - end - end - - # Prints a table. - # - # ==== Parameters - # Array[Array[String, String, ...]] - # - # ==== Options - # indent:: Indent the first column by indent value. - # colwidth:: Force the first column to colwidth spaces wide. - # - def print_table(array, options = {}) # rubocop:disable MethodLength - return if array.empty? - - formats = [] - indent = options[:indent].to_i - colwidth = options[:colwidth] - options[:truncate] = terminal_width if options[:truncate] == true - - formats << "%-#{colwidth + 2}s".dup if colwidth - start = colwidth ? 1 : 0 - - colcount = array.max { |a, b| a.size <=> b.size }.size - - maximas = [] - - start.upto(colcount - 1) do |index| - maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max - maximas << maxima - formats << if index == colcount - 1 - # Don't output 2 trailing spaces when printing the last column - "%-s".dup - else - "%-#{maxima + 2}s".dup - end - end - - formats[0] = formats[0].insert(0, " " * indent) - formats << "%s" - - array.each do |row| - sentence = "".dup - - row.each_with_index do |column, index| - maxima = maximas[index] - - f = if column.is_a?(Numeric) - if index == row.size - 1 - # Don't output 2 trailing spaces when printing the last column - "%#{maxima}s" - else - "%#{maxima}s " - end - else - formats[index] - end - sentence << f % column.to_s - end - - sentence = truncate(sentence, options[:truncate]) if options[:truncate] - stdout.puts sentence - end - end - - # Prints a long string, word-wrapping the text to the current width of the - # terminal display. Ideal for printing heredocs. - # - # ==== Parameters - # String - # - # ==== Options - # indent:: Indent each line of the printed paragraph by indent value. - # - def print_wrapped(message, options = {}) - indent = options[:indent] || 0 - width = terminal_width - indent - paras = message.split("\n\n") - - paras.map! do |unwrapped| - unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") } - end - - paras.each do |para| - para.split("\n").each do |line| - stdout.puts line.insert(0, " " * indent) - end - stdout.puts unless para == paras.last - end - end - - # Deals with file collision and returns true if the file should be - # overwritten and false otherwise. If a block is given, it uses the block - # response as the content for the diff. - # - # ==== Parameters - # destination:: the destination file to solve conflicts - # block:: an optional block that returns the value to be used in diff - # - def file_collision(destination) - return true if @always_force - options = block_given? ? "[Ynaqdh]" : "[Ynaqh]" - - loop do - answer = ask( - %[Overwrite #{destination}? (enter "h" for help) #{options}], - :add_to_history => false - ) - - case answer - when nil - say "" - return true - when is?(:yes), is?(:force), "" - return true - when is?(:no), is?(:skip) - return false - when is?(:always) - return @always_force = true - when is?(:quit) - say "Aborting..." - raise SystemExit - when is?(:diff) - show_diff(destination, yield) if block_given? - say "Retrying..." - else - say file_collision_help - end - end - end - - # This code was copied from Rake, available under MIT-LICENSE - # Copyright (c) 2003, 2004 Jim Weirich - def terminal_width - result = if ENV["THOR_COLUMNS"] - ENV["THOR_COLUMNS"].to_i - else - unix? ? dynamic_width : 80 - end - result < 10 ? 80 : result - rescue - 80 - end - - # Called if something goes wrong during the execution. This is used by Bundler::Thor - # internally and should not be used inside your scripts. If something went - # wrong, you can always raise an exception. If you raise a Bundler::Thor::Error, it - # will be rescued and wrapped in the method below. - # - def error(statement) - stderr.puts statement - end - - # Apply color to the given string with optional bold. Disabled in the - # Bundler::Thor::Shell::Basic class. - # - def set_color(string, *) #:nodoc: - string - end - - protected - - def prepare_message(message, *color) - spaces = " " * padding - spaces + set_color(message.to_s, *color) - end - - def can_display_colors? - false - end - - def lookup_color(color) - return color unless color.is_a?(Symbol) - self.class.const_get(color.to_s.upcase) - end - - def stdout - $stdout - end - - def stderr - $stderr - end - - def is?(value) #:nodoc: - value = value.to_s - - if value.size == 1 - /\A#{value}\z/i - else - /\A(#{value}|#{value[0, 1]})\z/i - end - end - - def file_collision_help #:nodoc: - <<-HELP - Y - yes, overwrite - n - no, do not overwrite - a - all, overwrite this and all others - q - quit, abort - d - diff, show the differences between the old and the new - h - help, show this help - HELP - end - - def show_diff(destination, content) #:nodoc: - diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u" - - require "tempfile" - Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp| - temp.write content - temp.rewind - system %(#{diff_cmd} "#{destination}" "#{temp.path}") - end - end - - def quiet? #:nodoc: - mute? || (base && base.options[:quiet]) - end - - # Calculate the dynamic width of the terminal - def dynamic_width - @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) - end - - def dynamic_width_stty - `stty size 2>/dev/null`.split[1].to_i - end - - def dynamic_width_tput - `tput cols 2>/dev/null`.to_i - end - - def unix? - RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i - end - - def truncate(string, width) - as_unicode do - chars = string.chars.to_a - if chars.length <= width - chars.join - else - chars[0, width - 3].join + "..." - end - end - end - - if "".respond_to?(:encode) - def as_unicode - yield - end - else - def as_unicode - old = $KCODE - $KCODE = "U" - yield - ensure - $KCODE = old - end - end - - def ask_simply(statement, color, options) - default = options[:default] - message = [statement, ("(#{default})" if default), nil].uniq.join(" ") - message = prepare_message(message, *color) - result = Bundler::Thor::LineEditor.readline(message, options) - - return unless result - - result = result.strip - - if default && result == "" - default - else - result - end - end - - def ask_filtered(statement, color, options) - answer_set = options[:limited_to] - correct_answer = nil - until correct_answer - answers = answer_set.join(", ") - answer = ask_simply("#{statement} [#{answers}]", color, options) - correct_answer = answer_set.include?(answer) ? answer : nil - say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer - end - correct_answer - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/color.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/color.rb deleted file mode 100644 index da289cb50cf..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/color.rb +++ /dev/null @@ -1,149 +0,0 @@ -require "bundler/vendor/thor/lib/thor/shell/basic" - -class Bundler::Thor - module Shell - # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check - # Bundler::Thor::Shell::Basic to see all available methods. - # - class Color < Basic - # Embed in a String to clear all previous ANSI sequences. - CLEAR = "\e[0m" - # The start of an ANSI bold sequence. - BOLD = "\e[1m" - - # Set the terminal's foreground ANSI color to black. - BLACK = "\e[30m" - # Set the terminal's foreground ANSI color to red. - RED = "\e[31m" - # Set the terminal's foreground ANSI color to green. - GREEN = "\e[32m" - # Set the terminal's foreground ANSI color to yellow. - YELLOW = "\e[33m" - # Set the terminal's foreground ANSI color to blue. - BLUE = "\e[34m" - # Set the terminal's foreground ANSI color to magenta. - MAGENTA = "\e[35m" - # Set the terminal's foreground ANSI color to cyan. - CYAN = "\e[36m" - # Set the terminal's foreground ANSI color to white. - WHITE = "\e[37m" - - # Set the terminal's background ANSI color to black. - ON_BLACK = "\e[40m" - # Set the terminal's background ANSI color to red. - ON_RED = "\e[41m" - # Set the terminal's background ANSI color to green. - ON_GREEN = "\e[42m" - # Set the terminal's background ANSI color to yellow. - ON_YELLOW = "\e[43m" - # Set the terminal's background ANSI color to blue. - ON_BLUE = "\e[44m" - # Set the terminal's background ANSI color to magenta. - ON_MAGENTA = "\e[45m" - # Set the terminal's background ANSI color to cyan. - ON_CYAN = "\e[46m" - # Set the terminal's background ANSI color to white. - ON_WHITE = "\e[47m" - - # Set color by using a string or one of the defined constants. If a third - # option is set to true, it also adds bold to the string. This is based - # on Highline implementation and it automatically appends CLEAR to the end - # of the returned String. - # - # Pass foreground, background and bold options to this method as - # symbols. - # - # Example: - # - # set_color "Hi!", :red, :on_white, :bold - # - # The available colors are: - # - # :bold - # :black - # :red - # :green - # :yellow - # :blue - # :magenta - # :cyan - # :white - # :on_black - # :on_red - # :on_green - # :on_yellow - # :on_blue - # :on_magenta - # :on_cyan - # :on_white - def set_color(string, *colors) - if colors.compact.empty? || !can_display_colors? - string - elsif colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } - ansi_colors = colors.map { |color| lookup_color(color) } - "#{ansi_colors.join}#{string}#{CLEAR}" - else - # The old API was `set_color(color, bold=boolean)`. We - # continue to support the old API because you should never - # break old APIs unnecessarily :P - foreground, bold = colors - foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol) - - bold = bold ? BOLD : "" - "#{bold}#{foreground}#{string}#{CLEAR}" - end - end - - protected - - def can_display_colors? - stdout.tty? - end - - # Overwrite show_diff to show diff with colors if Diff::LCS is - # available. - # - def show_diff(destination, content) #:nodoc: - if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? - actual = File.binread(destination).to_s.split("\n") - content = content.to_s.split("\n") - - Diff::LCS.sdiff(actual, content).each do |diff| - output_diff_line(diff) - end - else - super - end - end - - def output_diff_line(diff) #:nodoc: - case diff.action - when "-" - say "- #{diff.old_element.chomp}", :red, true - when "+" - say "+ #{diff.new_element.chomp}", :green, true - when "!" - say "- #{diff.old_element.chomp}", :red, true - say "+ #{diff.new_element.chomp}", :green, true - else - say " #{diff.old_element.chomp}", nil, true - end - end - - # Check if Diff::LCS is loaded. If it is, use it to create pretty output - # for diff. - # - def diff_lcs_loaded? #:nodoc: - return true if defined?(Diff::LCS) - return @diff_lcs_loaded unless @diff_lcs_loaded.nil? - - @diff_lcs_loaded = begin - require "diff/lcs" - true - rescue LoadError - false - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/html.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/html.rb deleted file mode 100644 index 83d20549882..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/shell/html.rb +++ /dev/null @@ -1,126 +0,0 @@ -require "bundler/vendor/thor/lib/thor/shell/basic" - -class Bundler::Thor - module Shell - # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check - # Bundler::Thor::Shell::Basic to see all available methods. - # - class HTML < Basic - # The start of an HTML bold sequence. - BOLD = "font-weight: bold" - - # Set the terminal's foreground HTML color to black. - BLACK = "color: black" - # Set the terminal's foreground HTML color to red. - RED = "color: red" - # Set the terminal's foreground HTML color to green. - GREEN = "color: green" - # Set the terminal's foreground HTML color to yellow. - YELLOW = "color: yellow" - # Set the terminal's foreground HTML color to blue. - BLUE = "color: blue" - # Set the terminal's foreground HTML color to magenta. - MAGENTA = "color: magenta" - # Set the terminal's foreground HTML color to cyan. - CYAN = "color: cyan" - # Set the terminal's foreground HTML color to white. - WHITE = "color: white" - - # Set the terminal's background HTML color to black. - ON_BLACK = "background-color: black" - # Set the terminal's background HTML color to red. - ON_RED = "background-color: red" - # Set the terminal's background HTML color to green. - ON_GREEN = "background-color: green" - # Set the terminal's background HTML color to yellow. - ON_YELLOW = "background-color: yellow" - # Set the terminal's background HTML color to blue. - ON_BLUE = "background-color: blue" - # Set the terminal's background HTML color to magenta. - ON_MAGENTA = "background-color: magenta" - # Set the terminal's background HTML color to cyan. - ON_CYAN = "background-color: cyan" - # Set the terminal's background HTML color to white. - ON_WHITE = "background-color: white" - - # Set color by using a string or one of the defined constants. If a third - # option is set to true, it also adds bold to the string. This is based - # on Highline implementation and it automatically appends CLEAR to the end - # of the returned String. - # - def set_color(string, *colors) - if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } - html_colors = colors.map { |color| lookup_color(color) } - "#{string}" - else - color, bold = colors - html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) - styles = [html_color] - styles << BOLD if bold - "#{string}" - end - end - - # Ask something to the user and receives a response. - # - # ==== Example - # ask("What is your name?") - # - # TODO: Implement #ask for Bundler::Thor::Shell::HTML - def ask(statement, color = nil) - raise NotImplementedError, "Implement #ask for Bundler::Thor::Shell::HTML" - end - - protected - - def can_display_colors? - true - end - - # Overwrite show_diff to show diff with colors if Diff::LCS is - # available. - # - def show_diff(destination, content) #:nodoc: - if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? - actual = File.binread(destination).to_s.split("\n") - content = content.to_s.split("\n") - - Diff::LCS.sdiff(actual, content).each do |diff| - output_diff_line(diff) - end - else - super - end - end - - def output_diff_line(diff) #:nodoc: - case diff.action - when "-" - say "- #{diff.old_element.chomp}", :red, true - when "+" - say "+ #{diff.new_element.chomp}", :green, true - when "!" - say "- #{diff.old_element.chomp}", :red, true - say "+ #{diff.new_element.chomp}", :green, true - else - say " #{diff.old_element.chomp}", nil, true - end - end - - # Check if Diff::LCS is loaded. If it is, use it to create pretty output - # for diff. - # - def diff_lcs_loaded? #:nodoc: - return true if defined?(Diff::LCS) - return @diff_lcs_loaded unless @diff_lcs_loaded.nil? - - @diff_lcs_loaded = begin - require "diff/lcs" - true - rescue LoadError - false - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/util.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/util.rb deleted file mode 100644 index 5d03177a28d..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/util.rb +++ /dev/null @@ -1,268 +0,0 @@ -require "rbconfig" - -class Bundler::Thor - module Sandbox #:nodoc: - end - - # This module holds several utilities: - # - # 1) Methods to convert thor namespaces to constants and vice-versa. - # - # Bundler::Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz" - # - # 2) Loading thor files and sandboxing: - # - # Bundler::Thor::Util.load_thorfile("~/.thor/foo") - # - module Util - class << self - # Receives a namespace and search for it in the Bundler::Thor::Base subclasses. - # - # ==== Parameters - # namespace:: The namespace to search for. - # - def find_by_namespace(namespace) - namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/ - Bundler::Thor::Base.subclasses.detect { |klass| klass.namespace == namespace } - end - - # Receives a constant and converts it to a Bundler::Thor namespace. Since Bundler::Thor - # commands can be added to a sandbox, this method is also responsable for - # removing the sandbox namespace. - # - # This method should not be used in general because it's used to deal with - # older versions of Bundler::Thor. On current versions, if you need to get the - # namespace from a class, just call namespace on it. - # - # ==== Parameters - # constant:: The constant to be converted to the thor path. - # - # ==== Returns - # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz" - # - def namespace_from_thor_class(constant) - constant = constant.to_s.gsub(/^Bundler::Thor::Sandbox::/, "") - constant = snake_case(constant).squeeze(":") - constant - end - - # Given the contents, evaluate it inside the sandbox and returns the - # namespaces defined in the sandbox. - # - # ==== Parameters - # contents - # - # ==== Returns - # Array[Object] - # - def namespaces_in_content(contents, file = __FILE__) - old_constants = Bundler::Thor::Base.subclasses.dup - Bundler::Thor::Base.subclasses.clear - - load_thorfile(file, contents) - - new_constants = Bundler::Thor::Base.subclasses.dup - Bundler::Thor::Base.subclasses.replace(old_constants) - - new_constants.map!(&:namespace) - new_constants.compact! - new_constants - end - - # Returns the thor classes declared inside the given class. - # - def thor_classes_in(klass) - stringfied_constants = klass.constants.map(&:to_s) - Bundler::Thor::Base.subclasses.select do |subclass| - next unless subclass.name - stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", "")) - end - end - - # Receives a string and convert it to snake case. SnakeCase returns snake_case. - # - # ==== Parameters - # String - # - # ==== Returns - # String - # - def snake_case(str) - return str.downcase if str =~ /^[A-Z_]+$/ - str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/ - $+.downcase - end - - # Receives a string and convert it to camel case. camel_case returns CamelCase. - # - # ==== Parameters - # String - # - # ==== Returns - # String - # - def camel_case(str) - return str if str !~ /_/ && str =~ /[A-Z]+.*/ - str.split("_").map(&:capitalize).join - end - - # Receives a namespace and tries to retrieve a Bundler::Thor or Bundler::Thor::Group class - # from it. It first searches for a class using the all the given namespace, - # if it's not found, removes the highest entry and searches for the class - # again. If found, returns the highest entry as the class name. - # - # ==== Examples - # - # class Foo::Bar < Bundler::Thor - # def baz - # end - # end - # - # class Baz::Foo < Bundler::Thor::Group - # end - # - # Bundler::Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command - # Bundler::Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil - # Bundler::Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz" - # - # ==== Parameters - # namespace - # - def find_class_and_command_by_namespace(namespace, fallback = true) - if namespace.include?(":") # look for a namespaced command - pieces = namespace.split(":") - command = pieces.pop - klass = Bundler::Thor::Util.find_by_namespace(pieces.join(":")) - end - unless klass # look for a Bundler::Thor::Group with the right name - klass = Bundler::Thor::Util.find_by_namespace(namespace) - command = nil - end - if !klass && fallback # try a command in the default namespace - command = namespace - klass = Bundler::Thor::Util.find_by_namespace("") - end - [klass, command] - end - alias_method :find_class_and_task_by_namespace, :find_class_and_command_by_namespace - - # Receives a path and load the thor file in the path. The file is evaluated - # inside the sandbox to avoid namespacing conflicts. - # - def load_thorfile(path, content = nil, debug = false) - content ||= File.binread(path) - - begin - Bundler::Thor::Sandbox.class_eval(content, path) - rescue StandardError => e - $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}") - if debug - $stderr.puts(*e.backtrace) - else - $stderr.puts(e.backtrace.first) - end - end - end - - def user_home - @@user_home ||= if ENV["HOME"] - ENV["HOME"] - elsif ENV["USERPROFILE"] - ENV["USERPROFILE"] - elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"] - File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"]) - elsif ENV["APPDATA"] - ENV["APPDATA"] - else - begin - File.expand_path("~") - rescue - if File::ALT_SEPARATOR - "C:/" - else - "/" - end - end - end - end - - # Returns the root where thor files are located, depending on the OS. - # - def thor_root - File.join(user_home, ".thor").tr('\\', "/") - end - - # Returns the files in the thor root. On Windows thor_root will be something - # like this: - # - # C:\Documents and Settings\james\.thor - # - # If we don't #gsub the \ character, Dir.glob will fail. - # - def thor_root_glob - files = Dir["#{escape_globs(thor_root)}/*"] - - files.map! do |file| - File.directory?(file) ? File.join(file, "main.thor") : file - end - end - - # Where to look for Bundler::Thor files. - # - def globs_for(path) - path = escape_globs(path) - ["#{path}/Bundler::Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] - end - - # Return the path to the ruby interpreter taking into account multiple - # installations and windows extensions. - # - def ruby_command - @ruby_command ||= begin - ruby_name = RbConfig::CONFIG["ruby_install_name"] - ruby = File.join(RbConfig::CONFIG["bindir"], ruby_name) - ruby << RbConfig::CONFIG["EXEEXT"] - - # avoid using different name than ruby (on platforms supporting links) - if ruby_name != "ruby" && File.respond_to?(:readlink) - begin - alternate_ruby = File.join(RbConfig::CONFIG["bindir"], "ruby") - alternate_ruby << RbConfig::CONFIG["EXEEXT"] - - # ruby is a symlink - if File.symlink? alternate_ruby - linked_ruby = File.readlink alternate_ruby - - # symlink points to 'ruby_install_name' - ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby - end - rescue NotImplementedError # rubocop:disable HandleExceptions - # just ignore on windows - end - end - - # escape string in case path to ruby executable contain spaces. - ruby.sub!(/.*\s.*/m, '"\&"') - ruby - end - end - - # Returns a string that has had any glob characters escaped. - # The glob characters are `* ? { } [ ]`. - # - # ==== Examples - # - # Bundler::Thor::Util.escape_globs('[apps]') # => '\[apps\]' - # - # ==== Parameters - # String - # - # ==== Returns - # String - # - def escape_globs(path) - path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&') - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/version.rb b/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/version.rb deleted file mode 100644 index df8f18821aa..00000000000 --- a/lib/ruby/stdlib/bundler/vendor/thor/lib/thor/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Bundler::Thor - VERSION = "0.20.0" -end diff --git a/lib/ruby/stdlib/bundler/vendored_fileutils.rb b/lib/ruby/stdlib/bundler/vendored_fileutils.rb deleted file mode 100644 index d14e98baf72..00000000000 --- a/lib/ruby/stdlib/bundler/vendored_fileutils.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Bundler; end -if RUBY_VERSION >= "2.4" - require "bundler/vendor/fileutils/lib/fileutils" -else - # the version we vendor is 2.4+ - require "fileutils" -end diff --git a/lib/ruby/stdlib/bundler/vendored_molinillo.rb b/lib/ruby/stdlib/bundler/vendored_molinillo.rb deleted file mode 100644 index 061b634f728..00000000000 --- a/lib/ruby/stdlib/bundler/vendored_molinillo.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -module Bundler; end -require "bundler/vendor/molinillo/lib/molinillo" diff --git a/lib/ruby/stdlib/bundler/vendored_persistent.rb b/lib/ruby/stdlib/bundler/vendored_persistent.rb deleted file mode 100644 index de9c42fcc14..00000000000 --- a/lib/ruby/stdlib/bundler/vendored_persistent.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -# We forcibly require OpenSSL, because net/http/persistent will only autoload -# it. On some Rubies, autoload fails but explicit require succeeds. -begin - require "openssl" -rescue LoadError - # some Ruby builds don't have OpenSSL -end -module Bundler - module Persistent - module Net - module HTTP - end - end - end -end -require "bundler/vendor/net-http-persistent/lib/net/http/persistent" - -module Bundler - class PersistentHTTP < Persistent::Net::HTTP::Persistent - def connection_for(uri) - connection = super - warn_old_tls_version_rubygems_connection(uri, connection) - connection - end - - def warn_old_tls_version_rubygems_connection(uri, connection) - return unless connection.use_ssl? - return unless (uri.host || "").end_with?("rubygems.org") - - socket = connection.instance_variable_get(:@socket) - return unless socket - socket_io = socket.io - return unless socket_io.respond_to?(:ssl_version) - ssl_version = socket_io.ssl_version - - case ssl_version - when /TLSv([\d\.]+)/ - version = Gem::Version.new($1) - if version < Gem::Version.new("1.2") - Bundler.ui.warn \ - "Warning: Your Ruby version is compiled against a copy of OpenSSL that is very old. " \ - "Starting in January 2018, RubyGems.org will refuse connection requests from these " \ - "very old versions of OpenSSL. If you will need to continue installing gems after " \ - "January 2018, please follow this guide to upgrade: http://ruby.to/tls-outdated.", - :wrap => true - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vendored_thor.rb b/lib/ruby/stdlib/bundler/vendored_thor.rb deleted file mode 100644 index 8cca090f551..00000000000 --- a/lib/ruby/stdlib/bundler/vendored_thor.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -module Bundler - def self.require_thor_actions - Kernel.send(:require, "bundler/vendor/thor/lib/thor/actions") - end -end -require "bundler/vendor/thor/lib/thor" diff --git a/lib/ruby/stdlib/bundler/version.rb b/lib/ruby/stdlib/bundler/version.rb deleted file mode 100644 index feab75b8d12..00000000000 --- a/lib/ruby/stdlib/bundler/version.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: false - -# Ruby 1.9.3 and old RubyGems don't play nice with frozen version strings -# rubocop:disable MutableConstant - -module Bundler - # We're doing this because we might write tests that deal - # with other versions of bundler and we are unsure how to - # handle this better. - VERSION = "1.17.3" unless defined?(::Bundler::VERSION) - - def self.overwrite_loaded_gem_version - begin - require "rubygems" - rescue LoadError - return - end - return unless bundler_spec = Gem.loaded_specs["bundler"] - return if bundler_spec.version == VERSION - bundler_spec.version = Bundler::VERSION - end - private_class_method :overwrite_loaded_gem_version - overwrite_loaded_gem_version - - def self.bundler_major_version - @bundler_major_version ||= VERSION.split(".").first.to_i - end -end diff --git a/lib/ruby/stdlib/bundler/version_ranges.rb b/lib/ruby/stdlib/bundler/version_ranges.rb deleted file mode 100644 index ec25716cde7..00000000000 --- a/lib/ruby/stdlib/bundler/version_ranges.rb +++ /dev/null @@ -1,76 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module VersionRanges - NEq = Struct.new(:version) - ReqR = Struct.new(:left, :right) - class ReqR - Endpoint = Struct.new(:version, :inclusive) - def to_s - "#{left.inclusive ? "[" : "("}#{left.version}, #{right.version}#{right.inclusive ? "]" : ")"}" - end - INFINITY = Object.new.freeze - ZERO = Gem::Version.new("0.a") - - def cover?(v) - return false if left.inclusive && left.version > v - return false if !left.inclusive && left.version >= v - - if right.version != INFINITY - return false if right.inclusive && right.version < v - return false if !right.inclusive && right.version <= v - end - - true - end - - def empty? - left.version == right.version && !(left.inclusive && right.inclusive) - end - - def single? - left.version == right.version - end - - UNIVERSAL = ReqR.new(ReqR::Endpoint.new(Gem::Version.new("0.a"), true), ReqR::Endpoint.new(ReqR::INFINITY, false)).freeze - end - - def self.for_many(requirements) - requirements = requirements.map(&:requirements).flatten(1).map {|r| r.join(" ") } - requirements << ">= 0.a" if requirements.empty? - requirement = Gem::Requirement.new(requirements) - self.for(requirement) - end - - def self.for(requirement) - ranges = requirement.requirements.map do |op, v| - case op - when "=" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(v, true)) - when "!=" then NEq.new(v) - when ">=" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(ReqR::INFINITY, false)) - when ">" then ReqR.new(ReqR::Endpoint.new(v, false), ReqR::Endpoint.new(ReqR::INFINITY, false)) - when "<" then ReqR.new(ReqR::Endpoint.new(ReqR::ZERO, true), ReqR::Endpoint.new(v, false)) - when "<=" then ReqR.new(ReqR::Endpoint.new(ReqR::ZERO, true), ReqR::Endpoint.new(v, true)) - when "~>" then ReqR.new(ReqR::Endpoint.new(v, true), ReqR::Endpoint.new(v.bump, false)) - else raise "unknown version op #{op} in requirement #{requirement}" - end - end.uniq - ranges, neqs = ranges.partition {|r| !r.is_a?(NEq) } - - [ranges.sort_by {|range| [range.left.version, range.left.inclusive ? 0 : 1] }, neqs.map(&:version)] - end - - def self.empty?(ranges, neqs) - !ranges.reduce(ReqR::UNIVERSAL) do |last_range, curr_range| - next false unless last_range - next false if curr_range.single? && neqs.include?(curr_range.left.version) - next curr_range if last_range.right.version == ReqR::INFINITY - case last_range.right.version <=> curr_range.left.version - when 1 then next curr_range - when 0 then next(last_range.right.inclusive && curr_range.left.inclusive && !neqs.include?(curr_range.left.version) && curr_range) - when -1 then next false - end - end - end - end -end diff --git a/lib/ruby/stdlib/bundler/vlad.rb b/lib/ruby/stdlib/bundler/vlad.rb deleted file mode 100644 index 68181e7db83..00000000000 --- a/lib/ruby/stdlib/bundler/vlad.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require "bundler/shared_helpers" -Bundler::SharedHelpers.major_deprecation 2, - "The Bundler task for Vlad" - -# Vlad task for Bundler. -# -# Add "require 'bundler/vlad'" in your Vlad deploy.rb, and -# include the vlad:bundle:install task in your vlad:deploy task. -require "bundler/deployment" - -include Rake::DSL if defined? Rake::DSL - -namespace :vlad do - Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, :roles => :app) -end diff --git a/lib/ruby/stdlib/bundler/worker.rb b/lib/ruby/stdlib/bundler/worker.rb deleted file mode 100644 index e91cfa78057..00000000000 --- a/lib/ruby/stdlib/bundler/worker.rb +++ /dev/null @@ -1,106 +0,0 @@ -# frozen_string_literal: true - -require "thread" - -module Bundler - class Worker - POISON = Object.new - - class WrappedException < StandardError - attr_reader :exception - def initialize(exn) - @exception = exn - end - end - - # @return [String] the name of the worker - attr_reader :name - - # Creates a worker pool of specified size - # - # @param size [Integer] Size of pool - # @param name [String] name the name of the worker - # @param func [Proc] job to run in inside the worker pool - def initialize(size, name, func) - @name = name - @request_queue = Queue.new - @response_queue = Queue.new - @func = func - @size = size - @threads = nil - SharedHelpers.trap("INT") { abort_threads } - end - - # Enqueue a request to be executed in the worker pool - # - # @param obj [String] mostly it is name of spec that should be downloaded - def enq(obj) - create_threads unless @threads - @request_queue.enq obj - end - - # Retrieves results of job function being executed in worker pool - def deq - result = @response_queue.deq - raise result.exception if result.is_a?(WrappedException) - result - end - - def stop - stop_threads - end - - private - - def process_queue(i) - loop do - obj = @request_queue.deq - break if obj.equal? POISON - @response_queue.enq apply_func(obj, i) - end - end - - def apply_func(obj, i) - @func.call(obj, i) - rescue Exception => e - WrappedException.new(e) - end - - # Stop the worker threads by sending a poison object down the request queue - # so as worker threads after retrieving it, shut themselves down - def stop_threads - return unless @threads - @threads.each { @request_queue.enq POISON } - @threads.each(&:join) - @threads = nil - end - - def abort_threads - return unless @threads - Bundler.ui.debug("\n#{caller.join("\n")}") - @threads.each(&:exit) - exit 1 - end - - def create_threads - creation_errors = [] - - @threads = Array.new(@size) do |i| - begin - Thread.start { process_queue(i) }.tap do |thread| - thread.name = "#{name} Worker ##{i}" if thread.respond_to?(:name=) - end - rescue ThreadError => e - creation_errors << e - nil - end - end.compact - - return if creation_errors.empty? - - message = "Failed to create threads for the #{name} worker: #{creation_errors.map(&:to_s).uniq.join(", ")}" - raise ThreadCreationError, message if @threads.empty? - Bundler.ui.info message - end - end -end diff --git a/lib/ruby/stdlib/bundler/yaml_serializer.rb b/lib/ruby/stdlib/bundler/yaml_serializer.rb deleted file mode 100644 index 0fd81c40eff..00000000000 --- a/lib/ruby/stdlib/bundler/yaml_serializer.rb +++ /dev/null @@ -1,90 +0,0 @@ -# frozen_string_literal: true - -module Bundler - # A stub yaml serializer that can handle only hashes and strings (as of now). - module YAMLSerializer - module_function - - def dump(hash) - yaml = String.new("---") - yaml << dump_hash(hash) - end - - def dump_hash(hash) - yaml = String.new("\n") - hash.each do |k, v| - yaml << k << ":" - if v.is_a?(Hash) - yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines - elsif v.is_a?(Array) # Expected to be array of strings - yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n" - else - yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n" - end - end - yaml - end - - ARRAY_REGEX = / - ^ - (?:[ ]*-[ ]) # '- ' before array items - (['"]?) # optional opening quote - (.*) # value - \1 # matching closing quote - $ - /xo - - HASH_REGEX = / - ^ - ([ ]*) # indentations - (.+) # key - (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value) - [ ]? - (?: !\s)? # optional exclamation mark found with ruby 1.9.3 - (['"]?) # optional opening quote - (.*) # value - \3 # matching closing quote - $ - /xo - - def load(str) - res = {} - stack = [res] - last_hash = nil - last_empty_key = nil - str.split(/\r?\n/).each do |line| - if match = HASH_REGEX.match(line) - indent, key, quote, val = match.captures - key = convert_to_backward_compatible_key(key) - depth = indent.scan(/ /).length - if quote.empty? && val.empty? - new_hash = {} - stack[depth][key] = new_hash - stack[depth + 1] = new_hash - last_empty_key = key - last_hash = stack[depth] - else - stack[depth][key] = val - end - elsif match = ARRAY_REGEX.match(line) - _, val = match.captures - last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array) - - last_hash[last_empty_key].push(val) - end - end - res - end - - # for settings' keys - def convert_to_backward_compatible_key(key) - key = "#{key}/" if key =~ /https?:/i && key !~ %r{/\Z} - key = key.gsub(".", "__") if key.include?(".") - key - end - - class << self - private :dump_hash, :convert_to_backward_compatible_key - end - end -end diff --git a/lib/ruby/stdlib/complex.rb b/lib/ruby/stdlib/complex.rb deleted file mode 100644 index 5a30273c8e3..00000000000 --- a/lib/ruby/stdlib/complex.rb +++ /dev/null @@ -1,2 +0,0 @@ -# Temporary stub file due to LOADED_FEATURES search not picking up short names -# See https://github.com/jruby/jruby/issues/5590 diff --git a/lib/ruby/stdlib/coverage.rb b/lib/ruby/stdlib/coverage.rb index 71ff6e05c36..f3ad0abcb51 100644 --- a/lib/ruby/stdlib/coverage.rb +++ b/lib/ruby/stdlib/coverage.rb @@ -10,7 +10,7 @@ def self.line_stub(file) visitor = org.jruby.ast.visitor.NodeVisitor.impl do |name, node| if node.newline? - lines[node.position.line] = 0 + lines[node.line] = 0 end node.child_nodes.each {|child| child && child.accept(visitor)} diff --git a/lib/ruby/stdlib/enumerator.rb b/lib/ruby/stdlib/enumerator.rb deleted file mode 100644 index 5a30273c8e3..00000000000 --- a/lib/ruby/stdlib/enumerator.rb +++ /dev/null @@ -1,2 +0,0 @@ -# Temporary stub file due to LOADED_FEATURES search not picking up short names -# See https://github.com/jruby/jruby/issues/5590 diff --git a/lib/ruby/stdlib/jruby/compiler.rb b/lib/ruby/stdlib/jruby/compiler.rb index da2e59e321f..0dfac6b42dd 100644 --- a/lib/ruby/stdlib/jruby/compiler.rb +++ b/lib/ruby/stdlib/jruby/compiler.rb @@ -3,6 +3,7 @@ require 'digest/sha1' require 'jruby' require 'jruby/compiler/java_class' +require 'pathname' module JRuby::Compiler ByteArrayInputStream = java.io.ByteArrayInputStream @@ -249,9 +250,12 @@ def compile_files_with_options(filenames, options = default_options) if class_filename.start_with?(options[:target]) # full-path target_file = class_filename else - target_file = File.join(options[:target], class_filename) - end + abs_class_filename = File.absolute_path(class_filename) + abs_basedir = File.absolute_path(options[:basedir]) + relative_class_filename = Pathname.new(abs_class_filename).relative_path_from(abs_basedir) + target_file = File.join(options[:target], relative_class_filename) + end FileUtils.mkdir_p File.dirname(target_file) # write class diff --git a/lib/ruby/stdlib/jruby/util.rb b/lib/ruby/stdlib/jruby/util.rb deleted file mode 100644 index 5a30273c8e3..00000000000 --- a/lib/ruby/stdlib/jruby/util.rb +++ /dev/null @@ -1,2 +0,0 @@ -# Temporary stub file due to LOADED_FEATURES search not picking up short names -# See https://github.com/jruby/jruby/issues/5590 diff --git a/lib/ruby/stdlib/rational.rb b/lib/ruby/stdlib/rational.rb deleted file mode 100644 index 5a30273c8e3..00000000000 --- a/lib/ruby/stdlib/rational.rb +++ /dev/null @@ -1,2 +0,0 @@ -# Temporary stub file due to LOADED_FEATURES search not picking up short names -# See https://github.com/jruby/jruby/issues/5590 diff --git a/lib/ruby/stdlib/thread.rb b/lib/ruby/stdlib/thread.rb deleted file mode 100644 index 5a30273c8e3..00000000000 --- a/lib/ruby/stdlib/thread.rb +++ /dev/null @@ -1,2 +0,0 @@ -# Temporary stub file due to LOADED_FEATURES search not picking up short names -# See https://github.com/jruby/jruby/issues/5590 diff --git a/maven/jruby/src/it/bouncycastle/pom.xml b/maven/jruby/src/it/bouncycastle/pom.xml index 63e5048251c..798e841fa44 100644 --- a/maven/jruby/src/it/bouncycastle/pom.xml +++ b/maven/jruby/src/it/bouncycastle/pom.xml @@ -26,7 +26,7 @@ junit junit - 4.11 + 4.13.1 test diff --git a/maven/jruby/src/it/extended/pom.xml b/maven/jruby/src/it/extended/pom.xml index 579a452480c..878906be968 100644 --- a/maven/jruby/src/it/extended/pom.xml +++ b/maven/jruby/src/it/extended/pom.xml @@ -20,7 +20,7 @@ junit junit - 4.8.2 + 4.13.1 test diff --git a/maven/jruby/src/it/terminate-container-and-extensions-GH-3300/pom.xml b/maven/jruby/src/it/terminate-container-and-extensions-GH-3300/pom.xml index d88943f5d53..db66f4db205 100644 --- a/maven/jruby/src/it/terminate-container-and-extensions-GH-3300/pom.xml +++ b/maven/jruby/src/it/terminate-container-and-extensions-GH-3300/pom.xml @@ -20,7 +20,7 @@ junit junit - 4.11 + 4.13.1 test diff --git a/pom.rb b/pom.rb index 4bece27189f..355a8ab9dae 100644 --- a/pom.rb +++ b/pom.rb @@ -82,12 +82,12 @@ 'jar-dependencies.version' => '0.4.1', 'jruby-launcher.version' => '1.1.6', 'ant.version' => '1.9.8', - 'asm.version' => '7.1', - 'jffi.version' => '1.3.0', + 'asm.version' => '9.0', + 'jffi.version' => '1.3.1', 'joda.time.version' => '2.10.5' ) plugin_management do - jar( 'junit:junit:4.12', + jar( 'junit:junit:4.13.1', :scope => 'test' ) plugin( 'org.apache.felix:maven-bundle-plugin:4.2.1', diff --git a/pom.xml b/pom.xml index a4c64e0491d..05dfb06fb2d 100644 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,7 @@ DO NOT MODIFIY - GENERATED CODE 1.9.8 - 7.1 + 9.0 1.8 1.8 github @@ -114,7 +114,7 @@ DO NOT MODIFIY - GENERATED CODE j2ee*/pom.xml osgi*/pom.xml 0.4.1 - 1.3.0 + 1.3.1 2.10.5 1.1.6 ${project.basedir} @@ -141,7 +141,7 @@ DO NOT MODIFIY - GENERATED CODE junit junit - 4.12 + 4.13.1 test diff --git a/rakelib/rubyspec.rake b/rakelib/rubyspec.rake index b9fe4d25f35..9810bf7fe99 100644 --- a/rakelib/rubyspec.rake +++ b/rakelib/rubyspec.rake @@ -24,7 +24,7 @@ namespace :spec do mspec :compile_mode => "OFF", :format => MSPEC_FORMAT, :spec_target => ":fast", - :jruby_opts => "-I. --dev" + :jruby_opts => "--dev" end desc "Run fast specs that do not spawn many subprocesses" @@ -40,7 +40,7 @@ namespace :spec do mspec :compile_mode => "OFF", :format => "s", :spec_target => ":slow", - :jruby_opts => "-I. --dev --debug" + :jruby_opts => "--dev --debug" end desc "Run rubyspecs expected to pass" diff --git a/spec/java_integration/interfaces/java8_methods_spec.rb b/spec/java_integration/interfaces/java8_methods_spec.rb index 1b1d480b06a..897f19c2ec9 100644 --- a/spec/java_integration/interfaces/java8_methods_spec.rb +++ b/spec/java_integration/interfaces/java8_methods_spec.rb @@ -1,6 +1,6 @@ require File.dirname(__FILE__) + "/../spec_helper" -describe "an interface (Java 8+)" do +describe "an interface" do before :all do require 'tmpdir'; @tmpdir = Dir.mktmpdir @@ -118,11 +118,30 @@ expect(method.name).to eq(:"bar()") # abstract end if RUBY_VERSION > '1.9' - it "(default) java_method is callable" do + it "default java_method is callable" do method = Java::Java8Interface.java_method(:foo, [ java.lang.Object ]) expect( method.bind(Java::Java8Implementor.new).call '' ).to eql 'foo Java8Implementor' end + it "binds default method as instance method" do + expect( Java::Java8Interface.instance_methods(false) ).to include :foo + expect( Java::Java8Implementor.new.foo(42) ).to eq("42foo Java8Implementor") + end + + it "binds default method as instance method (Ruby receiver)" do + klass = Class.new do + include java.util.Iterator + def hasNext; false end + def next; nil end + end + expect( java.util.Iterator.instance_methods(false) ).to include :remove + begin + klass.new.remove + rescue java.lang.UnsupportedOperationException + # pass + end + end + it "java_send works on implemented interface (default method)" do impl = Java::Java8Implementor.new expect(impl.java_send(:bar)).to eq("Java8Implementor") @@ -228,4 +247,4 @@ def javac_compile(files) compilation_task.call # returns boolean end -end if ENV_JAVA['java.specification.version'] >= '1.8' +end diff --git a/spec/mspec/lib/mspec/helpers/io.rb b/spec/mspec/lib/mspec/helpers/io.rb index 1938255d1a4..29c6c37a1a6 100644 --- a/spec/mspec/lib/mspec/helpers/io.rb +++ b/spec/mspec/lib/mspec/helpers/io.rb @@ -85,7 +85,3 @@ def new_io(name, mode = "w:utf-8") File.new(name, mode) end end - -def find_unused_fd - Dir.entries("/dev/fd").map(&:to_i).max + 1 -end diff --git a/spec/mspec/lib/mspec/matchers/include.rb b/spec/mspec/lib/mspec/matchers/include.rb index 0b7eaf3ce22..3f07f355482 100644 --- a/spec/mspec/lib/mspec/matchers/include.rb +++ b/spec/mspec/lib/mspec/matchers/include.rb @@ -15,11 +15,11 @@ def matches?(actual) end def failure_message - ["Expected #{@actual.inspect}", "to include #{@element.inspect}"] + ["Expected #{MSpec.format(@actual)}", "to include #{MSpec.format(@element)}"] end def negative_failure_message - ["Expected #{@actual.inspect}", "not to include #{@element.inspect}"] + ["Expected #{MSpec.format(@actual)}", "not to include #{MSpec.format(@element)}"] end end diff --git a/spec/mspec/lib/mspec/mocks/mock.rb b/spec/mspec/lib/mspec/mocks/mock.rb index bce41b630f9..28a083cc150 100644 --- a/spec/mspec/lib/mspec/mocks/mock.rb +++ b/spec/mspec/lib/mspec/mocks/mock.rb @@ -180,7 +180,7 @@ def self.verify_call(obj, sym, *args, &block) mock_respond_to? obj, *args else SpecExpectation.fail_with("Mock '#{name_or_inspect obj}': method #{sym}\n", - "called with unexpected arguments #{inspect_args compare}") + "called with unexpected arguments #{inspect_args args}") end end diff --git a/spec/mspec/lib/mspec/runner/actions/leakchecker.rb b/spec/mspec/lib/mspec/runner/actions/leakchecker.rb index 9efabc79b41..596b120d9f1 100644 --- a/spec/mspec/lib/mspec/runner/actions/leakchecker.rb +++ b/spec/mspec/lib/mspec/runner/actions/leakchecker.rb @@ -36,6 +36,7 @@ def initialize @thread_info = find_threads @env_info = find_env @argv_info = find_argv + @globals_info = find_globals @encoding_info = find_encodings end @@ -48,9 +49,10 @@ def check(state) check_process_leak check_env check_argv + check_globals check_encodings check_tracepoints - GC.start if !@leaks.empty? + GC.start unless @leaks.empty? @leaks.empty? end @@ -244,6 +246,19 @@ def check_argv end end + def find_globals + { verbose: $VERBOSE, debug: $DEBUG } + end + + def check_globals + old_globals = @globals_info + new_globals = find_globals + if new_globals != old_globals + leak "Globals changed: #{old_globals.inspect} to #{new_globals.inspect}" + @globals_info = new_globals + end + end + def find_encodings [Encoding.default_internal, Encoding.default_external] end diff --git a/spec/mspec/lib/mspec/utils/warnings.rb b/spec/mspec/lib/mspec/utils/warnings.rb index 1cd9153a376..288dbe71aa2 100644 --- a/spec/mspec/lib/mspec/utils/warnings.rb +++ b/spec/mspec/lib/mspec/utils/warnings.rb @@ -45,7 +45,6 @@ def Warning.warn(message) when /\/(argf|io|stringio)\/.+(ARGF|IO)#(lines|chars|bytes|codepoints) is deprecated/ when /Thread\.exclusive is deprecated.+\n.+thread\/exclusive_spec\.rb/ when /hash\/shared\/index\.rb:\d+: warning: Hash#index is deprecated; use Hash#key/ - when /env\/shared\/key\.rb:\d+: warning: ENV\.index is deprecated; use ENV\.key/ when /exponent(_spec)?\.rb:\d+: warning: in a\*\*b, b may be too big/ when /enumerator\/(new_spec|initialize_spec)\.rb:\d+: warning: Enumerator\.new without a block is deprecated/ when /Pattern matching is experimental, and the behavior may change in future versions of Ruby!/ diff --git a/spec/regression/GH-6441_NPE_on_long_case_spec.rb b/spec/regression/GH-6441_NPE_on_long_case_spec.rb new file mode 100644 index 00000000000..04702757364 --- /dev/null +++ b/spec/regression/GH-6441_NPE_on_long_case_spec.rb @@ -0,0 +1,74 @@ +require 'rspec' + +describe "A parse which uses enough parser states" do + it "will properly allocate and complete without NPEing" do + def test(num) + case num + when 55 + when 64 + when 65 + when 66 + when 67 + when 68 + when 69 + when 80 + when 81 + when 82 + when 83 + when 84 + when 85 + when 86 + when 87 + when 88 + when 96 + when 97 + when 98 + when 99 + when 100 + when 101 + when 112 + when 120 + when 121 + when 128 + when 130 + when 144 + when 145 + when 146 + when 147 + when 148 + when 149 + when 150 + when 160 + when 176 + when 177 + when 178 + when 179 + when 180 + when 181 + when 182 + when 183 + when 184 + when 185 + when 190 + when 200 + when 201 + when 202 + when 250 + when 251 + when 260 + when 261 + when 280 + when 281 + when 300 + when 301 + when 302 + when 320 + when 350 + when 500 + return "Video" + end + end + + expect(test(500)).to eq("Video") + end +end diff --git a/spec/regression/GH-6480_float_garbage_after_exponent_spec.rb b/spec/regression/GH-6480_float_garbage_after_exponent_spec.rb new file mode 100644 index 00000000000..28dd74805ba --- /dev/null +++ b/spec/regression/GH-6480_float_garbage_after_exponent_spec.rb @@ -0,0 +1,6 @@ +describe 'Kernel#Float' do + it 'raises an error when exponent has extra garbage after it' do + expect { Float("661e7086-33af-11eb") }.to raise_error(ArgumentError) + end +end + diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 5db9256572f..a26b525b1cd 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -113,6 +113,9 @@ Lint/Debugger: Exclude: - 'core/binding/fixtures/irb.rb' +Lint/Loop: + Enabled: false + Style/Lambda: Enabled: true EnforcedStyle: literal diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml index 7a5f9f74c56..a469213841d 100644 --- a/spec/ruby/.rubocop_todo.yml +++ b/spec/ruby/.rubocop_todo.yml @@ -76,12 +76,6 @@ Lint/LiteralInInterpolation: - 'language/undef_spec.rb' - 'library/net/ftp/connect_spec.rb' -# Offense count: 16 -Lint/Loop: - Exclude: - - 'language/until_spec.rb' - - 'language/while_spec.rb' - # Offense count: 8 # Cop supports --auto-correct. Lint/MultipleComparison: diff --git a/spec/ruby/command_line/dash_upper_w_spec.rb b/spec/ruby/command_line/dash_upper_w_spec.rb index 31bb976ad21..62c617b892c 100644 --- a/spec/ruby/command_line/dash_upper_w_spec.rb +++ b/spec/ruby/command_line/dash_upper_w_spec.rb @@ -18,3 +18,35 @@ describe "The -W command line option with 2" do it_behaves_like :command_line_verbose, "-W2" end + +ruby_version_is "2.7" do + describe "The -W command line option with :no-deprecated" do + it "suppresses deprecation warnings" do + result = ruby_exe('$; = ""', options: '-w', args: '2>&1') + result.should =~ /is deprecated/ + + result = ruby_exe('$; = ""', options: '-w -W:no-deprecated', args: '2>&1') + result.should == "" + end + end + + describe "The -W command line option with :no-experimental" do + before do + ruby_version_is ""..."3.0" do + @src = 'case 0; in a; end' + end + + ruby_version_is "3.0" do + @src = '1 => a' + end + end + + it "suppresses experimental warnings" do + result = ruby_exe(@src, args: '2>&1') + result.should =~ /is experimental/ + + result = ruby_exe(@src, options: '-W:no-experimental', args: '2>&1') + result.should == "" + end + end +end diff --git a/spec/ruby/command_line/feature_spec.rb b/spec/ruby/command_line/feature_spec.rb index 8848249c641..16e106b37d5 100644 --- a/spec/ruby/command_line/feature_spec.rb +++ b/spec/ruby/command_line/feature_spec.rb @@ -37,11 +37,13 @@ ruby_exe("p 'foo'.frozen?", options: "--disable-frozen-string-literal").chomp.should == "false" end - it "can be used with all for enable" do - e = "p [defined?(Gem), defined?(DidYouMean), $VERBOSE, 'foo'.frozen?]" - env = {'RUBYOPT' => '-w'} - # Use a single variant here because it can be quite slow as it might enable jit, etc - ruby_exe(e, options: "--enable-all", env: env).chomp.should == "[\"constant\", \"constant\", true, true]" + platform_is_not :darwin do # frequently hangs for >60s on GitHub Actions macos-latest + it "can be used with all for enable" do + e = "p [defined?(Gem), defined?(DidYouMean), $VERBOSE, 'foo'.frozen?]" + env = {'RUBYOPT' => '-w'} + # Use a single variant here because it can be quite slow as it might enable jit, etc + ruby_exe(e, options: "--enable-all", env: env).chomp.should == "[\"constant\", \"constant\", true, true]" + end end it "can be used with all for disable" do diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb index 2db42f77efc..a739f23eb8c 100644 --- a/spec/ruby/command_line/rubyopt_spec.rb +++ b/spec/ruby/command_line/rubyopt_spec.rb @@ -59,6 +59,26 @@ ruby_exe("p $VERBOSE", escape: true).chomp.should == "true" end + ruby_version_is "2.7" do + it "suppresses deprecation warnings for '-W:no-deprecated'" do + ENV["RUBYOPT"] = '-W:no-deprecated' + result = ruby_exe('$; = ""', args: '2>&1') + result.should == "" + end + + it "suppresses experimental warnings for '-W:no-experimental'" do + ENV["RUBYOPT"] = '-W:no-experimental' + result = ruby_exe('case 0; in a; end', args: '2>&1') + result.should == "" + end + + it "suppresses deprecation and experimental warnings for '-W:no-deprecated -W:no-experimental'" do + ENV["RUBYOPT"] = '-W:no-deprecated -W:no-experimental' + result = ruby_exe('case ($; = ""); in a; end', args: '2>&1') + result.should == "" + end + end + it "requires the file for '-r'" do f = fixture __FILE__, "rubyopt" ENV["RUBYOPT"] = "-r#{f}" diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb index e7cd114b9b8..2f9fb8a3ec4 100644 --- a/spec/ruby/core/array/flatten_spec.rb +++ b/spec/ruby/core/array/flatten_spec.rb @@ -75,12 +75,24 @@ [[obj]].flatten(1) end - it "returns subclass instance for Array subclasses" do - ArraySpecs::MyArray[].flatten.should be_an_instance_of(ArraySpecs::MyArray) - ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) - ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) - ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == ArraySpecs::MyArray[1, 2, 3, 4] - [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it "returns subclass instance for Array subclasses" do + ArraySpecs::MyArray[].flatten.should be_an_instance_of(ArraySpecs::MyArray) + ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) + ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) + ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == ArraySpecs::MyArray[1, 2, 3, 4] + [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) + end + end + + ruby_version_is '3.0' do + it "returns Array instance for Array subclasses" do + ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4] + [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) + end end it "is not destructive" do diff --git a/spec/ruby/core/array/minmax_spec.rb b/spec/ruby/core/array/minmax_spec.rb new file mode 100644 index 00000000000..e11fe63347c --- /dev/null +++ b/spec/ruby/core/array/minmax_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../spec_helper' +require_relative '../../shared/enumerable/minmax' + +describe "Array#minmax" do + before :each do + @enum = [6, 4, 5, 10, 8] + @empty_enum = [] + @incomparable_enum = [BasicObject.new, BasicObject.new] + @incompatible_enum = [11, "22"] + @strs = ["333", "2", "60", "55555", "1010", "111"] + end + + it_behaves_like :enumerable_minmax, :minmax +end diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb index 8ccec13d429..16e407348b4 100644 --- a/spec/ruby/core/array/multiply_spec.rb +++ b/spec/ruby/core/array/multiply_spec.rb @@ -76,10 +76,20 @@ def obj.to_str() "2" end @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] end - it "returns a subclass instance" do - (@array * 0).should be_an_instance_of(ArraySpecs::MyArray) - (@array * 1).should be_an_instance_of(ArraySpecs::MyArray) - (@array * 2).should be_an_instance_of(ArraySpecs::MyArray) + ruby_version_is ''...'3.0' do + it "returns a subclass instance" do + (@array * 0).should be_an_instance_of(ArraySpecs::MyArray) + (@array * 1).should be_an_instance_of(ArraySpecs::MyArray) + (@array * 2).should be_an_instance_of(ArraySpecs::MyArray) + end + end + + ruby_version_is '3.0' do + it "returns an Array instance" do + (@array * 0).should be_an_instance_of(Array) + (@array * 1).should be_an_instance_of(Array) + (@array * 2).should be_an_instance_of(Array) + end end it "does not call #initialize on the subclass instance" do diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb index f36890fa4ee..845be768c67 100644 --- a/spec/ruby/core/array/shared/slice.rb +++ b/spec/ruby/core/array/shared/slice.rb @@ -397,28 +397,56 @@ def to.to_int() -2 end @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] end - it "returns a subclass instance with [n, m]" do - @array.send(@method, 0, 2).should be_an_instance_of(ArraySpecs::MyArray) + ruby_version_is ''...'3.0' do + it "returns a subclass instance with [n, m]" do + @array.send(@method, 0, 2).should be_an_instance_of(ArraySpecs::MyArray) + end + + it "returns a subclass instance with [-n, m]" do + @array.send(@method, -3, 2).should be_an_instance_of(ArraySpecs::MyArray) + end + + it "returns a subclass instance with [n..m]" do + @array.send(@method, 1..3).should be_an_instance_of(ArraySpecs::MyArray) + end + + it "returns a subclass instance with [n...m]" do + @array.send(@method, 1...3).should be_an_instance_of(ArraySpecs::MyArray) + end + + it "returns a subclass instance with [-n..-m]" do + @array.send(@method, -3..-1).should be_an_instance_of(ArraySpecs::MyArray) + end + + it "returns a subclass instance with [-n...-m]" do + @array.send(@method, -3...-1).should be_an_instance_of(ArraySpecs::MyArray) + end end - it "returns a subclass instance with [-n, m]" do - @array.send(@method, -3, 2).should be_an_instance_of(ArraySpecs::MyArray) - end + ruby_version_is '3.0' do + it "returns a Array instance with [n, m]" do + @array.send(@method, 0, 2).should be_an_instance_of(Array) + end - it "returns a subclass instance with [n..m]" do - @array.send(@method, 1..3).should be_an_instance_of(ArraySpecs::MyArray) - end + it "returns a Array instance with [-n, m]" do + @array.send(@method, -3, 2).should be_an_instance_of(Array) + end - it "returns a subclass instance with [n...m]" do - @array.send(@method, 1...3).should be_an_instance_of(ArraySpecs::MyArray) - end + it "returns a Array instance with [n..m]" do + @array.send(@method, 1..3).should be_an_instance_of(Array) + end - it "returns a subclass instance with [-n..-m]" do - @array.send(@method, -3..-1).should be_an_instance_of(ArraySpecs::MyArray) - end + it "returns a Array instance with [n...m]" do + @array.send(@method, 1...3).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n..-m]" do + @array.send(@method, -3..-1).should be_an_instance_of(Array) + end - it "returns a subclass instance with [-n...-m]" do - @array.send(@method, -3...-1).should be_an_instance_of(ArraySpecs::MyArray) + it "returns a Array instance with [-n...-m]" do + @array.send(@method, -3...-1).should be_an_instance_of(Array) + end end it "returns an empty array when m == n with [m...n]" do diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb index fd604987c1a..5911c23e6ab 100644 --- a/spec/ruby/core/array/uniq_spec.rb +++ b/spec/ruby/core/array/uniq_spec.rb @@ -128,8 +128,16 @@ def obj.eql?(o) [false, nil, 42].uniq { :bar }.should == [false] end - it "returns subclass instance on Array subclasses" do - ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(ArraySpecs::MyArray) + ruby_version_is ''...'3.0' do + it "returns subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(ArraySpecs::MyArray) + end + end + + ruby_version_is '3.0' do + it "returns Array instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array) + end end it "properly handles an identical item even when its #eql? isn't reflexive" do diff --git a/spec/ruby/core/class/new_spec.rb b/spec/ruby/core/class/new_spec.rb index 989d674558f..93152a83ee5 100644 --- a/spec/ruby/core/class/new_spec.rb +++ b/spec/ruby/core/class/new_spec.rb @@ -95,12 +95,13 @@ def message2; "hello"; end end it "raises a TypeError when given a non-Class" do - error_msg = /superclass must be a Class/ - -> { Class.new("") }.should raise_error(TypeError, error_msg) - -> { Class.new(1) }.should raise_error(TypeError, error_msg) - -> { Class.new(:symbol) }.should raise_error(TypeError, error_msg) - -> { Class.new(mock('o')) }.should raise_error(TypeError, error_msg) - -> { Class.new(Module.new) }.should raise_error(TypeError, error_msg) + error_msg = /superclass must be a.*Class/ + -> { Class.new("") }.should raise_error(TypeError, error_msg) + -> { Class.new(1) }.should raise_error(TypeError, error_msg) + -> { Class.new(:symbol) }.should raise_error(TypeError, error_msg) + -> { Class.new(mock('o')) }.should raise_error(TypeError, error_msg) + -> { Class.new(Module.new) }.should raise_error(TypeError, error_msg) + -> { Class.new(BasicObject.new) }.should raise_error(TypeError, error_msg) end end diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb index 96dba56c93b..71b1438b727 100644 --- a/spec/ruby/core/dir/fixtures/common.rb +++ b/spec/ruby/core/dir/fixtures/common.rb @@ -36,6 +36,8 @@ def self.mock_dir_files .dotfile .dotsubdir/.dotfile .dotsubdir/nondotfile + nested/.dotsubir/.dotfile + nested/.dotsubir/nondotfile deeply/.dotfile deeply/nested/.dotfile.ext @@ -160,6 +162,7 @@ def self.expected_paths dir_filename_ordering file_one.ext file_two.ext + nested nondotfile special subdir_one diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb index d4888ee1470..9b6e2b2d3d6 100644 --- a/spec/ruby/core/dir/glob_spec.rb +++ b/spec/ruby/core/dir/glob_spec.rb @@ -59,6 +59,8 @@ deeply/nested/directory/ deeply/nested/directory/structure/ dir/ + nested/ + nested/.dotsubir/ special/ special/test{1}/ subdir_one/ @@ -68,6 +70,18 @@ Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected end + it "recursively matches files and directories in nested dot subdirectory with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do + expected = %w[ + nested/. + nested/.dotsubir + nested/.dotsubir/. + nested/.dotsubir/.dotfile + nested/.dotsubir/nondotfile + ] + + Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort + end + # This is a separate case to check **/ coming after a constant # directory as well. it "recursively matches any subdirectories except './' or '../' with '**/' and option File::FNM_DOTMATCH" do @@ -80,6 +94,8 @@ ./deeply/nested/directory/ ./deeply/nested/directory/structure/ ./dir/ + ./nested/ + ./nested/.dotsubir/ ./special/ ./special/test{1}/ ./subdir_one/ diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb index fcaa0d8a435..f6d41ba209d 100644 --- a/spec/ruby/core/dir/shared/glob.rb +++ b/spec/ruby/core/dir/shared/glob.rb @@ -53,6 +53,7 @@ dir_filename_ordering file_one.ext file_two.ext + nested nondotfile special subdir_one @@ -156,6 +157,7 @@ dir_filename_ordering file_one.ext file_two.ext + nested nondotfile special subdir_one @@ -177,6 +179,7 @@ deeply/nested/directory/ deeply/nested/directory/structure/ dir/ + nested/ special/ special/test{1}/ subdir_one/ diff --git a/spec/ruby/core/encoding/list_spec.rb b/spec/ruby/core/encoding/list_spec.rb index 2a2078974e5..8efd94ab9c8 100644 --- a/spec/ruby/core/encoding/list_spec.rb +++ b/spec/ruby/core/encoding/list_spec.rb @@ -12,7 +12,7 @@ end it "returns each encoding only once" do - orig = Encoding.list.map {|e| e.name} + orig = Encoding.list.map { |e| e.name } orig.should == orig.uniq end @@ -33,7 +33,17 @@ end it "includes dummy encodings" do - Encoding.list.select {|e| e.dummy?}.should_not == [] + Encoding.list.select { |e| e.dummy? }.should_not == [] + end + + it 'includes UTF-8 encoding' do + Encoding.list.should.include?(Encoding::UTF_8) + end + + ruby_version_is "2.7" do + it 'includes CESU-8 encoding' do + Encoding.list.should.include?(Encoding::CESU_8) + end end # TODO: Find example that illustrates this diff --git a/spec/ruby/core/enumerable/minmax_spec.rb b/spec/ruby/core/enumerable/minmax_spec.rb index 29f1ecf82cd..f5f17ef0796 100644 --- a/spec/ruby/core/enumerable/minmax_spec.rb +++ b/spec/ruby/core/enumerable/minmax_spec.rb @@ -1,41 +1,17 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative '../../shared/enumerable/minmax' describe "Enumerable#minmax" do before :each do @enum = EnumerableSpecs::Numerous.new(6, 4, 5, 10, 8) - + @empty_enum = EnumerableSpecs::Empty.new + @incomparable_enum = EnumerableSpecs::Numerous.new(BasicObject.new, BasicObject.new) + @incompatible_enum = EnumerableSpecs::Numerous.new(11,"22") @strs = EnumerableSpecs::Numerous.new("333", "2", "60", "55555", "1010", "111") end - it "min should return the minimum element" do - @enum.minmax.should == [4, 10] - @strs.minmax.should == ["1010", "60" ] - end - - it "returns [nil, nil] for an empty Enumerable" do - EnumerableSpecs::Empty.new.minmax.should == [nil, nil] - end - - it "raises an ArgumentError when elements are incomparable" do - -> do - EnumerableSpecs::Numerous.new(11,"22").minmax - end.should raise_error(ArgumentError) - -> do - EnumerableSpecs::Numerous.new(11,12,22,33).minmax{|a, b| nil} - end.should raise_error(ArgumentError) - end - - it "raises a NoMethodError for elements without #<=>" do - -> do - EnumerableSpecs::Numerous.new(BasicObject.new, BasicObject.new).minmax - end.should raise_error(NoMethodError) - end - - it "returns the minimum when using a block rule" do - @enum.minmax {|a,b| b <=> a }.should == [10, 4] - @strs.minmax {|a,b| a.length <=> b.length }.should == ["2", "55555"] - end + it_behaves_like :enumerable_minmax, :minmax it "gathers whole arrays as elements when each yields multiple" do multi = EnumerableSpecs::YieldsMulti.new diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/step_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/step_spec.rb index 20a5cb6e7bf..8b00fd43097 100644 --- a/spec/ruby/core/enumerator/arithmetic_sequence/step_spec.rb +++ b/spec/ruby/core/enumerator/arithmetic_sequence/step_spec.rb @@ -5,11 +5,9 @@ it "returns the original value given to step method" do (1..10).step.step.should == 1 (1..10).step(3).step.should == 3 - (1..10).step(0).step.should == 0 1.step(10).step.should == 1 1.step(10, 3).step.should == 3 - 1.step(10, 0).step.should == 0 end end end diff --git a/spec/ruby/core/env/shared/key.rb b/spec/ruby/core/env/shared/key.rb index fcb3a9b8c57..93396d2aca3 100644 --- a/spec/ruby/core/env/shared/key.rb +++ b/spec/ruby/core/env/shared/key.rb @@ -9,15 +9,23 @@ it "returns the index associated with the passed value" do ENV["foo"] = "bar" - ENV.send(@method, "bar").should == "foo" + suppress_warning { + ENV.send(@method, "bar").should == "foo" + } end it "returns nil if the passed value is not found" do ENV.delete("foo") - ENV.send(@method, "foo").should be_nil + suppress_warning { + ENV.send(@method, "foo").should be_nil + } end it "raises TypeError if the argument is not a String and does not respond to #to_str" do - -> { ENV.send(@method, Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String") + -> { + suppress_warning { + ENV.send(@method, Object.new) + } + }.should raise_error(TypeError, "no implicit conversion of Object into String") end end diff --git a/spec/ruby/core/exception/errno_spec.rb b/spec/ruby/core/exception/errno_spec.rb index 78b3eafc2af..095a926e09e 100644 --- a/spec/ruby/core/exception/errno_spec.rb +++ b/spec/ruby/core/exception/errno_spec.rb @@ -47,4 +47,12 @@ it "is defined" do Errno.should have_constant(:ENOTSUP) end + + it "is the same class as Errno::EOPNOTSUPP if they represent the same errno value" do + if Errno::ENOTSUP::Errno == Errno::EOPNOTSUPP::Errno + Errno::ENOTSUP.should == Errno::EOPNOTSUPP + else + Errno::ENOTSUP.should_not == Errno::EOPNOTSUPP + end + end end diff --git a/spec/ruby/core/exception/system_exit_spec.rb b/spec/ruby/core/exception/system_exit_spec.rb new file mode 100644 index 00000000000..5c6116576ba --- /dev/null +++ b/spec/ruby/core/exception/system_exit_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../spec_helper' + +describe "SystemExit" do + it "sets the exit status and exits silently when raised" do + code = 'raise SystemExit.new(7)' + result = ruby_exe(code, args: "2>&1") + result.should == "" + $?.exitstatus.should == 7 + end + + it "sets the exit status and exits silently when raised when subclassed" do + code = 'class CustomExit < SystemExit; end; raise CustomExit.new(8)' + result = ruby_exe(code, args: "2>&1") + result.should == "" + $?.exitstatus.should == 8 + end +end diff --git a/spec/ruby/core/fiber/fixtures/classes.rb b/spec/ruby/core/fiber/fixtures/classes.rb new file mode 100644 index 00000000000..c00facd6e16 --- /dev/null +++ b/spec/ruby/core/fiber/fixtures/classes.rb @@ -0,0 +1,12 @@ +module FiberSpecs + + class NewFiberToRaise + def self.raise(*args) + fiber = Fiber.new { Fiber.yield } + fiber.resume + fiber.raise(*args) + end + end + + class CustomError < StandardError; end +end diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb new file mode 100644 index 00000000000..fd1cc911b50 --- /dev/null +++ b/spec/ruby/core/fiber/raise_spec.rb @@ -0,0 +1,76 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative '../../shared/kernel/raise' + +ruby_version_is "2.7" do + describe "Fiber#raise" do + it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise + end + + describe "Fiber#raise" do + it 'raises RuntimeError by default' do + -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError) + end + + it "raises FiberError if Fiber is not born" do + fiber = Fiber.new { true } + -> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber") + end + + it "raises FiberError if Fiber is dead" do + fiber = Fiber.new { true } + fiber.resume + -> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) + end + + it 'accepts error class' do + -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError) + end + + it 'accepts error message' do + -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message") + end + + it 'does not accept array of backtrace information only' do + -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError) + end + + it 'does not accept integer' do + -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError) + end + + it 'accepts error class with error message' do + -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error') + end + + it 'accepts error class with with error message and backtrace information' do + -> { + FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo'] + }.should raise_error(FiberSpecs::CustomError) { |e| + e.message.should == 'test error' + e.backtrace.should == ['foo', 'boo'] + } + end + + it 'does not accept only error message and backtrace information' do + -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError) + end + + it "raises a FiberError if invoked from a different Thread" do + fiber = Fiber.new { Fiber.yield } + fiber.resume + Thread.new do + -> { + fiber.raise + }.should raise_error(FiberError, "fiber called across threads") + end.join + end + + it "kills Fiber" do + fiber = Fiber.new { Fiber.yield :first; :second } + fiber.resume + -> { fiber.raise }.should raise_error + -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) + end + end +end diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb index 97495c50594..273bc866af7 100644 --- a/spec/ruby/core/fiber/resume_spec.rb +++ b/spec/ruby/core/fiber/resume_spec.rb @@ -6,9 +6,40 @@ end describe "Fiber#resume" do - it "raises a FiberError if the Fiber tries to resume itself" do - fiber = Fiber.new { fiber.resume } - -> { fiber.resume }.should raise_error(FiberError, /double resume/) + it "runs until Fiber.yield" do + obj = mock('obj') + obj.should_not_receive(:do) + fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do } + fiber.resume + end + + it "resumes from the last call to Fiber.yield on subsequent invocations" do + fiber = Fiber.new { Fiber.yield :first; :second } + fiber.resume.should == :first + fiber.resume.should == :second + end + + it "sets the block parameters to its arguments on the first invocation" do + first = mock('first') + first.should_receive(:arg).with(:first).twice + + fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; } + fiber.resume :first + fiber.resume :second + end + + ruby_version_is '3.0' do + it "raises a FiberError if the Fiber tries to resume itself" do + fiber = Fiber.new { fiber.resume } + -> { fiber.resume }.should raise_error(FiberError, /current fiber/) + end + end + + ruby_version_is '' ... '3.0' do + it "raises a FiberError if the Fiber tries to resume itself" do + fiber = Fiber.new { fiber.resume } + -> { fiber.resume }.should raise_error(FiberError, /double resume/) + end end it "returns control to the calling Fiber if called from one" do diff --git a/spec/ruby/core/file/extname_spec.rb b/spec/ruby/core/file/extname_spec.rb index e9b53bc24d0..e182ed44f2f 100644 --- a/spec/ruby/core/file/extname_spec.rb +++ b/spec/ruby/core/file/extname_spec.rb @@ -12,6 +12,16 @@ File.extname(".app.conf").should == ".conf" end + it "returns unfrozen strings" do + File.extname("foo.rb").frozen?.should == false + File.extname("/foo/bar.rb").frozen?.should == false + File.extname("/foo.rb/bar.c").frozen?.should == false + File.extname("bar").frozen?.should == false + File.extname(".bashrc").frozen?.should == false + File.extname("/foo.bar/baz").frozen?.should == false + File.extname(".app.conf").frozen?.should == false + end + it "returns the extension for edge cases" do File.extname("").should == "" File.extname(".").should == "" diff --git a/spec/ruby/core/file/lchmod_spec.rb b/spec/ruby/core/file/lchmod_spec.rb index 4abe42526d2..7420b95e4a3 100644 --- a/spec/ruby/core/file/lchmod_spec.rb +++ b/spec/ruby/core/file/lchmod_spec.rb @@ -29,22 +29,4 @@ File.stat(@lname).should.writable? end end - - platform_is :openbsd, :aix do - it "returns false from #respond_to?" do - File.respond_to?(:lchmod).should be_false - end - - it "raises a NotImplementedError when called" do - -> { File.lchmod 0, "foo" }.should raise_error(NotImplementedError) - end - end - - platform_is :linux do - it "raises a NotImplementedError or Errno::ENOTSUP when called" do - -> { File.lchmod 0, "foo" }.should raise_error(Exception) { |e| - [NotImplementedError, Errno::ENOTSUP].should include(e.class) - } - end - end end diff --git a/spec/ruby/core/file/link_spec.rb b/spec/ruby/core/file/link_spec.rb index cc63c76aa33..a5d5b4815fa 100644 --- a/spec/ruby/core/file/link_spec.rb +++ b/spec/ruby/core/file/link_spec.rb @@ -13,7 +13,7 @@ rm_r @link, @file end - platform_is_not :windows do + platform_is_not :windows, :android do it "link a file with another" do File.link(@file, @link).should == 0 File.should.exist?(@link) diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb index d964acc8556..0a5abe33f07 100644 --- a/spec/ruby/core/file/shared/path.rb +++ b/spec/ruby/core/file/shared/path.rb @@ -15,6 +15,23 @@ @file.send(@method).should be_an_instance_of(String) end + it "returns a different String on every call" do + @file = File.new @path + path1 = @file.send(@method) + path2 = @file.send(@method) + path1.should == path2 + path1.should_not.equal?(path2) + end + + it "returns a mutable String" do + @file = File.new @path.dup.freeze + path = @file.send(@method) + path.should == @path + path.should_not.frozen? + path << "test" + @file.send(@method).should == @path + end + it "calls to_str on argument and returns exact value" do path = mock('path') path.should_receive(:to_str).and_return(@path) diff --git a/spec/ruby/core/file/stat/nlink_spec.rb b/spec/ruby/core/file/stat/nlink_spec.rb index 2dd0bff1248..7143923cfcf 100644 --- a/spec/ruby/core/file/stat/nlink_spec.rb +++ b/spec/ruby/core/file/stat/nlink_spec.rb @@ -11,7 +11,7 @@ rm_r @link, @file end - platform_is_not :windows do + platform_is_not :windows, :android do it "returns the number of links to a file" do File::Stat.new(@file).nlink.should == 1 File.link(@file, @link) diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb index 96627b1fc6c..19cb80d5f83 100644 --- a/spec/ruby/core/file/utime_spec.rb +++ b/spec/ruby/core/file/utime_spec.rb @@ -72,13 +72,17 @@ platform_is :linux do platform_is wordsize: 64 do - it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10)" do + it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19)" do # https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps # "Therefore, timestamps should not overflow until May 2446." + # https://lwn.net/Articles/804382/ + # "On-disk timestamps hitting the y2038 limit..." + # The problem seems to be being improved, but currently it actually fails on XFS on RHEL8 + # https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz time = Time.at(1<<44) File.utime(time, time, @file1) - [559444, 2446].should.include? File.atime(@file1).year - [559444, 2446].should.include? File.mtime(@file1).year + [559444, 2446, 2038].should.include? File.atime(@file1).year + [559444, 2446, 2038].should.include? File.mtime(@file1).year end end end diff --git a/spec/ruby/core/hash/element_reference_spec.rb b/spec/ruby/core/hash/element_reference_spec.rb index 2eb65d37893..e271f37ea6b 100644 --- a/spec/ruby/core/hash/element_reference_spec.rb +++ b/spec/ruby/core/hash/element_reference_spec.rb @@ -117,4 +117,18 @@ key = HashSpecs::KeyWithPrivateHash.new { key => 42 }[key].should == 42 end + + it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do + code = <<-EOC + load '#{fixture __FILE__, "name.rb"}' + hash = { true => 42, false => 42, 1 => 42, 2.0 => 42, "hello" => 42, :ok => 42 } + [true, false, 1, 2.0, "hello", :ok].each do |value| + raise "incorrect value" unless hash[value] == 42 + end + puts "Ok." + EOC + result = ruby_exe(code, args: "2>&1") + result.should == "Ok.\n" + end + end diff --git a/spec/ruby/core/hash/fixtures/name.rb b/spec/ruby/core/hash/fixtures/name.rb new file mode 100644 index 00000000000..b203bf6ae44 --- /dev/null +++ b/spec/ruby/core/hash/fixtures/name.rb @@ -0,0 +1,30 @@ +class TrueClass + def hash + raise "TrueClass#hash should not be called" + end +end +class FalseClass + def hash + raise "FalseClass#hash should not be called" + end +end +class Integer + def hash + raise "Integer#hash should not be called" + end +end +class Float + def hash + raise "Float#hash should not be called" + end +end +class String + def hash + raise "String#hash should not be called" + end +end +class Symbol + def hash + raise "Symbol#hash should not be called" + end +end diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb new file mode 100644 index 00000000000..005886a4828 --- /dev/null +++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb @@ -0,0 +1,47 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "2.7" do + describe "Hash.ruby2_keywords_hash?" do + it "returns false if the Hash is not a keywords Hash" do + Hash.ruby2_keywords_hash?({}).should == false + end + + it "returns true if the Hash is a keywords Hash marked by Module#ruby2_keywords" do + obj = Class.new { + ruby2_keywords def m(*args) + args.last + end + }.new + Hash.ruby2_keywords_hash?(obj.m(a: 1)).should == true + end + + it "raises TypeError for non-Hash" do + -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError) + end + end + + describe "Hash.ruby2_keywords_hash" do + it "returns a copy of a Hash and marks the copy as a keywords Hash" do + h = {a: 1}.freeze + kw = Hash.ruby2_keywords_hash(h) + Hash.ruby2_keywords_hash?(h).should == false + Hash.ruby2_keywords_hash?(kw).should == true + kw.should == h + end + + it "returns an instance of the subclass if called on an instance of a subclass of Hash" do + h = HashSpecs::MyHash.new + h[:a] = 1 + kw = Hash.ruby2_keywords_hash(h) + kw.class.should == HashSpecs::MyHash + Hash.ruby2_keywords_hash?(h).should == false + Hash.ruby2_keywords_hash?(kw).should == true + kw.should == h + end + + it "raises TypeError for non-Hash" do + -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError) + end + end +end diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb index 84ffb41e33f..eca0e5a8e8e 100644 --- a/spec/ruby/core/hash/shared/store.rb +++ b/spec/ruby/core/hash/shared/store.rb @@ -95,4 +95,21 @@ def key.reverse() "bar" end hash.each { hash.send(@method, 1, :foo) } hash.should == {1 => :foo, 3 => 4, 5 => 6} end + + it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do + code = <<-EOC + load '#{fixture __FILE__, "name.rb"}' + hash = {} + [true, false, 1, 2.0, "hello", :ok].each do |value| + hash[value] = 42 + raise "incorrect value" unless hash[value] == 42 + hash[value] = 43 + raise "incorrect value" unless hash[value] == 43 + end + puts "OK" + puts hash.size + EOC + result = ruby_exe(code, args: "2>&1") + result.should == "OK\n6\n" + end end diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb index a8755eeb84e..9f105e42412 100644 --- a/spec/ruby/core/integer/chr_spec.rb +++ b/spec/ruby/core/integer/chr_spec.rb @@ -240,4 +240,17 @@ -> { integer.chr(encoding_name) }.should raise_error(RangeError) end end + + ruby_version_is "2.7" do + it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do + # see more details here https://en.wikipedia.org/wiki/CESU-8 + # code points from U+0000 to U+FFFF is encoded in the same way as in UTF-8 + 0x0045.chr(Encoding::CESU_8).bytes.should == 0x0045.chr(Encoding::UTF_8).bytes + + # code points in range from U+10000 to U+10FFFF is CESU-8 data containing a 6-byte surrogate pair, + # which decodes to a 4-byte UTF-8 string + 0x10400.chr(Encoding::CESU_8).bytes.should != 0x10400.chr(Encoding::UTF_8).bytes + 0x10400.chr(Encoding::CESU_8).bytes.to_a.should == [0xED, 0xA0, 0x81, 0xED, 0xB0, 0x80] + end + end end diff --git a/spec/ruby/core/integer/shared/comparison_coerce.rb b/spec/ruby/core/integer/shared/comparison_coerce.rb index 50437f77f5a..af52f5e99b0 100644 --- a/spec/ruby/core/integer/shared/comparison_coerce.rb +++ b/spec/ruby/core/integer/shared/comparison_coerce.rb @@ -1,27 +1,5 @@ require_relative '../fixtures/classes' -describe :integer_comparison_coerce_rescue, shared: true do - it "rescues exception (StandardError and subclasses) raised in other#coerce and raises ArgumentError" do - b = mock("numeric with failed #coerce") - b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError) - - # e.g. 1 > b - -> { - -> { 1.send(@method, b) }.should raise_error(ArgumentError, /comparison of Integer with MockObject failed/) - }.should complain(/Numerical comparison operators will no more rescue exceptions of #coerce/) - end - - it "does not rescue Exception and StandardError siblings raised in other#coerce" do - [Exception, NoMemoryError].each do |exception| - b = mock("numeric with failed #coerce") - b.should_receive(:coerce).and_raise(exception) - - # e.g. 1 > b - -> { 1.send(@method, b) }.should raise_error(exception) - end - end -end - describe :integer_comparison_coerce_not_rescue, shared: true do it "does not rescue exception raised in other#coerce" do b = mock("numeric with failed #coerce") diff --git a/spec/ruby/core/io/set_encoding_by_bom_spec.rb b/spec/ruby/core/io/set_encoding_by_bom_spec.rb new file mode 100644 index 00000000000..b8e4eedcb95 --- /dev/null +++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb @@ -0,0 +1,57 @@ +require_relative '../../spec_helper' + +describe "IO#set_encoding_by_bom" do + before :each do + @name = tmp('io_set_encoding_by_bom.txt') + touch(@name) + @io = new_io(@name, 'rb') + end + + after :each do + @io.close unless @io.closed? + rm_r @name + end + + ruby_version_is "2.7" do + it "returns the result encoding if found BOM UTF-8 sequence" do + File.binwrite(@name, "\u{FEFF}abc") + + @io.set_encoding_by_bom.should == Encoding::UTF_8 + @io.external_encoding.should == Encoding::UTF_8 + end + + it "returns the result encoding if found BOM UTF_16LE sequence" do + File.binwrite(@name, "\xFF\xFEabc") + + @io.set_encoding_by_bom.should == Encoding::UTF_16LE + @io.external_encoding.should == Encoding::UTF_16LE + end + + it "returns the result encoding if found BOM UTF_16BE sequence" do + File.binwrite(@name, "\xFE\xFFabc") + + @io.set_encoding_by_bom.should == Encoding::UTF_16BE + @io.external_encoding.should == Encoding::UTF_16BE + end + + it "returns nil if found BOM sequence not provided" do + File.write(@name, "abc") + + @io.set_encoding_by_bom.should == nil + end + + it 'returns exception if io not in binary mode' do + not_binary_io = new_io(@name, 'r') + + -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode') + ensure + not_binary_io.close + end + + it 'returns exception if encoding already set' do + @io.set_encoding("utf-8") + + -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already') + end + end +end diff --git a/spec/ruby/core/kernel/backtick_spec.rb b/spec/ruby/core/kernel/backtick_spec.rb index 391583b5390..834d5636c1d 100644 --- a/spec/ruby/core/kernel/backtick_spec.rb +++ b/spec/ruby/core/kernel/backtick_spec.rb @@ -36,6 +36,10 @@ end platform_is_not :windows do + it "handles invalid UTF-8 bytes in command" do + `echo "testing\xC2 a non UTF-8 string"`.b.should == "testing\xC2 a non UTF-8 string\n".b + end + it "sets $? to the exit status of the executed sub-process" do ip = 'world' `echo disc #{ip}` diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb index c4e00840859..8050b5b3abd 100644 --- a/spec/ruby/core/kernel/caller_locations_spec.rb +++ b/spec/ruby/core/kernel/caller_locations_spec.rb @@ -65,4 +65,16 @@ it "must return the same locations when called with 1..-1 and when called with no arguments" do caller_locations.map(&:to_s).should == caller_locations(1..-1).map(&:to_s) end + + guard -> { Kernel.instance_method(:tap).source_location } do + it "includes core library methods defined in Ruby" do + file, line = Kernel.instance_method(:tap).source_location + file.should.start_with?(' { Kernel.instance_method(:tap).source_location } do + it "includes core library methods defined in Ruby" do + file, line = Kernel.instance_method(:tap).source_location + file.should.start_with?('" +end diff --git a/spec/ruby/core/kernel/respond_to_spec.rb b/spec/ruby/core/kernel/respond_to_spec.rb index e7efc9f2750..5b3ea3f6517 100644 --- a/spec/ruby/core/kernel/respond_to_spec.rb +++ b/spec/ruby/core/kernel/respond_to_spec.rb @@ -25,7 +25,7 @@ end it "throws a type error if argument can't be coerced into a Symbol" do - -> { @a.respond_to?(Object.new) }.should raise_error(TypeError) + -> { @a.respond_to?(Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/) end it "returns false if obj responds to the given protected method" do @@ -69,5 +69,4 @@ class KernelSpecs::Foo; def bar; 'done'; end; end KernelSpecs::Foo.new.respond_to?(:bar).should == true KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false end - end diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb index 6c6895e3178..4e0322025cc 100644 --- a/spec/ruby/core/kernel/shared/require.rb +++ b/spec/ruby/core/kernel/shared/require.rb @@ -160,6 +160,14 @@ ScratchPad.recorded.should == [:loaded] end + it "accepts an Object with #to_path in $LOAD_PATH" do + obj = mock("to_path") + obj.should_receive(:to_path).at_least(:once).and_return(CODE_LOADING_DIR) + $LOAD_PATH << obj + @object.send(@method, "load_fixture.rb").should be_true + ScratchPad.recorded.should == [:loaded] + end + it "does not require file twice after $LOAD_PATH change" do $LOAD_PATH << CODE_LOADING_DIR @object.require("load_fixture.rb").should be_true diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb index 060e73963e0..22b2c4d0a40 100644 --- a/spec/ruby/core/kernel/taint_spec.rb +++ b/spec/ruby/core/kernel/taint_spec.rb @@ -44,4 +44,19 @@ end end end + + ruby_version_is "2.7"..."3.0" do + it "is a no-op" do + o = Object.new + o.taint + o.should_not.tainted? + end + + it "warns in verbose mode" do + -> { + obj = mock("tainted") + obj.taint + }.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true) + end + end end diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb index dbd6bc939ac..022938bfc15 100644 --- a/spec/ruby/core/kernel/tainted_spec.rb +++ b/spec/ruby/core/kernel/tainted_spec.rb @@ -11,4 +11,21 @@ p.should.tainted? end end + + ruby_version_is "2.7"..."3.0" do + it "is a no-op" do + o = mock('o') + p = mock('p') + p.taint + o.should_not.tainted? + p.should_not.tainted? + end + + it "warns in verbose mode" do + -> { + o = mock('o') + o.tainted? + }.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true) + end + end end diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb index 1d209ea1dc4..399983f74d5 100644 --- a/spec/ruby/core/kernel/trust_spec.rb +++ b/spec/ruby/core/kernel/trust_spec.rb @@ -24,4 +24,20 @@ o.trust.should equal(o) end end + + ruby_version_is "2.7"..."3.0" do + it "is a no-op" do + o = Object.new.untrust + o.should_not.untrusted? + o.trust + o.should_not.untrusted? + end + + it "warns in verbose mode" do + -> { + o = Object.new.untrust + o.trust + }.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true) + end + end end diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb index 171d32b3569..44d87da5d5b 100644 --- a/spec/ruby/core/kernel/untaint_spec.rb +++ b/spec/ruby/core/kernel/untaint_spec.rb @@ -24,4 +24,20 @@ o.untaint.should equal(o) end end + + ruby_version_is "2.7"..."3.0" do + it "is a no-op" do + o = Object.new.taint + o.should_not.tainted? + o.untaint + o.should_not.tainted? + end + + it "warns in verbose mode" do + -> { + o = Object.new.taint + o.untaint + }.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true) + end + end end diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb index fca7c9ea472..aff0fec57ba 100644 --- a/spec/ruby/core/kernel/untrust_spec.rb +++ b/spec/ruby/core/kernel/untrust_spec.rb @@ -24,4 +24,19 @@ o.untrust.should equal(o) end end + + ruby_version_is "2.7"..."3.0" do + it "is a no-op" do + o = Object.new + o.untrust + o.should_not.untrusted? + end + + it "warns in verbose mode" do + -> { + o = Object.new + o.untrust + }.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true) + end + end end diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb index 65cbffa3add..5347c90093a 100644 --- a/spec/ruby/core/kernel/untrusted_spec.rb +++ b/spec/ruby/core/kernel/untrusted_spec.rb @@ -27,4 +27,20 @@ -> { d.untrust }.should_not raise_error(RuntimeError) end end + + ruby_version_is "2.7"..."3.0" do + it "is a no-op" do + o = mock('o') + o.should_not.untrusted? + o.untrust + o.should_not.untrusted? + end + + it "warns in verbose mode" do + -> { + o = mock('o') + o.untrusted? + }.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true) + end + end end diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb index de08cd8cffe..5953a47e81c 100644 --- a/spec/ruby/core/kernel/warn_spec.rb +++ b/spec/ruby/core/kernel/warn_spec.rb @@ -114,6 +114,22 @@ end end + guard -> { Kernel.instance_method(:tap).source_location } do + it "skips &1").lines.should == [ + "#{file}:#{n+0}: warning: use X instead\n", + "#{file}:#{n+1}: warning: use X instead\n", + "#{file}:#{n+2}: warning: use X instead\n", + "#{file}:#{n+4}: warning: use X instead\n", + ] + end + end + ruby_version_is "3.0" do it "accepts :category keyword with a symbol" do -> { @@ -197,4 +213,35 @@ def o.to_sym; :deprecated; end -> { warn(**h) }.should_not complain(verbose: true) -> { warn('foo', **h) }.should complain("foo\n") end + + it "does not call Warning.warn if self is the Warning module" do + # RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here + code = <<-RUBY + def Warning.warn(*args, **kwargs) + raise 'should not be called' + end + Kernel.instance_method(:warn).bind(Warning).call('Kernel#warn spec edge case') + RUBY + out = ruby_exe(code, args: "2>&1", options: "--disable-gems") + out.should == "Kernel#warn spec edge case\n" + $?.should.success? + end + + it "avoids recursion if Warning#warn is redefined and calls super" do + # This works because of the spec above, which is the workaround for it. + # Note that redefining Warning#warn is a mistake which would naturally end in infinite recursion, + # Warning.extend Module.new { def warn } should be used instead. + # RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here + code = <<-RUBY + module Warning + def warn(*args, **kwargs) + super + end + end + warn "avoid infinite recursion" + RUBY + out = ruby_exe(code, args: "2>&1", options: "--disable-gems") + out.should == "avoid infinite recursion\n" + $?.should.success? + end end diff --git a/spec/ruby/core/method/fixtures/classes.rb b/spec/ruby/core/method/fixtures/classes.rb index f3b7ff921cf..be96f65e25b 100644 --- a/spec/ruby/core/method/fixtures/classes.rb +++ b/spec/ruby/core/method/fixtures/classes.rb @@ -50,6 +50,8 @@ def zero; end def one_req(a); end def two_req(a, b); end + def one_req_named(a:); end + def zero_with_block(&blk); end def one_req_with_block(a, &blk); end def two_req_with_block(a, b, &blk); end @@ -59,6 +61,8 @@ def one_req_one_opt(a, b=nil); end def one_req_two_opt(a, b=nil, c=nil); end def two_req_one_opt(a, b, c=nil); end + def one_opt_named(a: nil); end + def one_opt_with_block(a=nil, &blk); end def one_req_one_opt_with_block(a, b=nil, &blk); end def one_req_two_opt_with_block(a, b=nil, c=nil, &blk); end @@ -71,6 +75,8 @@ def one_req_one_opt_with_splat(a, b=nil, *c); end def two_req_one_opt_with_splat(a, b, c=nil, *d); end def one_req_two_opt_with_splat(a, b=nil, c=nil, *d); end + def zero_with_double_splat(**a); end + def zero_with_splat_and_block(*a, &blk); end def one_req_with_splat_and_block(a, *b, &blk); end def two_req_with_splat_and_block(a, b, *c, &blk); end diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb index 0c0edc2f8c6..1fbee870d65 100644 --- a/spec/ruby/core/method/shared/to_s.rb +++ b/spec/ruby/core/method/shared/to_s.rb @@ -4,7 +4,7 @@ describe :method_to_s, shared: true do before :each do @m = MethodSpecs::MySub.new.method :bar - @string = @m.send(@method).sub(/0x\w+/, '0xXXXXXX') + @string = @m.send(@method) end it "returns a String" do @@ -24,6 +24,21 @@ @string.should =~ /\#bar/ end + ruby_version_is "2.7" do + it "returns a String containing method arguments" do + obj = MethodSpecs::Methods.new + obj.method(:zero).send(@method).should.include?("()") + obj.method(:one_req).send(@method).should.include?("(a)") + obj.method(:one_req_named).send(@method).should.include?("(a:)") + obj.method(:zero_with_block).send(@method).should.include?("(&blk)") + obj.method(:one_opt).send(@method).should.include?("(a=...)") + obj.method(:one_opt_named).send(@method).should.include?("(a: ...)") + obj.method(:zero_with_splat).send(@method).should.include?("(*a)") + obj.method(:zero_with_double_splat).send(@method).should.include?("(**a)") + obj.method(:one_req_one_opt_with_splat_and_block).send(@method).should.include?("(a, b=..., *c, &blk)") + end + end + it "returns a String containing the Module the method is defined in" do @string.should =~ /MethodSpecs::MyMod/ end @@ -32,13 +47,21 @@ @string.should =~ /MethodSpecs::MySub/ end + it "returns a String including all details" do + @string.should.start_with? "#\.bar/ + @string = @m.send(@method).sub(/0x\h+/, '0xXXXXXX') + @string.should.start_with? "#.bar" end end diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb index dd81b02c771..051739c57d5 100644 --- a/spec/ruby/core/method/source_location_spec.rb +++ b/spec/ruby/core/method/source_location_spec.rb @@ -86,6 +86,24 @@ def f method.source_location[1].should == line end + it "works for core methods where it returns nil or { + ConstantSpecs::ClassB::CSL_CONST309 = :const309_2 + }.should complain(/already initialized constant/) + ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2] + end + end + + describe "with statically assigned constants" do + it "searches location path the immediate class or module first" do + ConstantSpecs::ClassA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE] + ConstantSpecs::ModuleA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST10_LINE] + ConstantSpecs::ParentA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST10_LINE] + ConstantSpecs::ContainerA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::CS_CONST10_LINE] + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::ChildA::CS_CONST10_LINE] + end + + it "searches location path a module included in the immediate class before the superclass" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST15).should == [@constants_fixture_path, ConstantSpecs::ModuleC::CS_CONST15_LINE] + end + + it "searches location path the superclass before a module included in the superclass" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST11).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST11_LINE] + end + + it "searches location path a module included in the superclass" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST12).should == [@constants_fixture_path, ConstantSpecs::ModuleB::CS_CONST12_LINE] + end + + it "searches location path the superclass chain" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST13).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST13_LINE] + end + + it "returns location path a toplevel constant when the receiver is a Class" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] + end + + it "returns location path a toplevel constant when the receiver is a Module" do + ConstantSpecs.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] + ConstantSpecs::ModuleA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] + end + end + + it "return empty path if constant defined in C code" do + Object.const_source_location(:String).should == [] + end + + it "accepts a String or Symbol name" do + Object.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] + Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + end + + it "returns nil if no constant is defined in the search path" do + ConstantSpecs.const_source_location(:CS_CONSTX).should == nil + end + + it "raises a NameError if the name does not start with a capital letter" do + -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError) + end + + it "raises a NameError if the name starts with a non-alphabetic character" do + -> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError) + -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError) + -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError) + end + + it "raises a NameError if the name contains non-alphabetic characters except '_'" do + Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError) + -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError) + end + + it "calls #to_str to convert the given name to a String" do + name = mock("ClassA") + name.should_receive(:to_str).and_return("ClassA") + ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CLASS_A_LINE] + end + + it "raises a TypeError if conversion to a String by calling #to_str fails" do + name = mock('123') + -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) + + name.should_receive(:to_str).and_return(123) + -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) + end + + it "does not search the singleton class of a Class or Module" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST14).should == nil + ConstantSpecs.const_source_location(:CS_CONST14).should == nil + end + + it "does not search the containing scope" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST20).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST20_LINE] + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST5) == nil + end + + it "returns nil if the constant is defined in the receiver's superclass and the inherit flag is false" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, false).should == nil + end + + it "searches into the receiver superclasses if the inherit flag is true" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, true).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST4_LINE] + end + + it "returns nil when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do + ConstantSpecs::ModuleA.const_source_location(:CS_CONST1, false).should == nil + end + + it "returns nil when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1, false).should == nil + end + + it "accepts a toplevel scope qualifier" do + ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + end + + it "accepts a scoped constant name" do + ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE] + end + + it "raises a NameError if the name includes two successive scope separators" do + -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError) + end + + it "raises a NameError if only '::' is passed" do + -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError) + end + + it "raises a NameError if a Symbol has a toplevel scope qualifier" do + -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError) + end + + it "raises a NameError if a Symbol is a scoped constant name" do + -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError) + end + + it "does search private constants path" do + ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE] + end + + context 'autoload' do + before :all do + ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb" + @line = __LINE__ - 1 + end + + it 'returns the autoload location while not resolved' do + ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line] + end + + it 'returns where the constant was resolved when resolved' do + file = fixture(__FILE__, 'autoload_location.rb') + ConstantSpecs.autoload :CONST_LOCATION, file + line = ConstantSpecs::CONST_LOCATION + ConstantSpecs.const_source_location('CONST_LOCATION').should == [file, line] + end + end + end +end diff --git a/spec/ruby/core/module/constants_spec.rb b/spec/ruby/core/module/constants_spec.rb index 4538e828dd9..beb25c6eaa5 100644 --- a/spec/ruby/core/module/constants_spec.rb +++ b/spec/ruby/core/module/constants_spec.rb @@ -43,31 +43,31 @@ class Module describe "Module#constants" do it "returns an array of Symbol names of all constants defined in the module and all included modules" do ConstantSpecs::ContainerA.constants.sort.should == [ - :CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA + :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA ] end it "returns all constants including inherited when passed true" do ConstantSpecs::ContainerA.constants(true).sort.should == [ - :CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA + :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA ] end it "returns all constants including inherited when passed some object" do ConstantSpecs::ContainerA.constants(Object.new).sort.should == [ - :CS_CONST10, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA + :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST24, :CS_CONST5, :ChildA ] end it "doesn't returns inherited constants when passed false" do ConstantSpecs::ContainerA.constants(false).sort.should == [ - :CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA + :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST5, :ChildA ] end it "doesn't returns inherited constants when passed nil" do ConstantSpecs::ContainerA.constants(nil).sort.should == [ - :CS_CONST10, :CS_CONST23, :CS_CONST5, :ChildA + :CS_CONST10, :CS_CONST10_LINE, :CS_CONST23, :CS_CONST5, :ChildA ] end diff --git a/spec/ruby/core/module/fixtures/autoload_location.rb b/spec/ruby/core/module/fixtures/autoload_location.rb new file mode 100644 index 00000000000..318851b2df0 --- /dev/null +++ b/spec/ruby/core/module/fixtures/autoload_location.rb @@ -0,0 +1,3 @@ +module ConstantSpecs + CONST_LOCATION = __LINE__ +end diff --git a/spec/ruby/core/numeric/shared/step.rb b/spec/ruby/core/numeric/shared/step.rb index fac79b3e63b..6c47cdeecb9 100644 --- a/spec/ruby/core/numeric/shared/step.rb +++ b/spec/ruby/core/numeric/shared/step.rb @@ -261,8 +261,10 @@ step_enum_class = Enumerator::ArithmeticSequence end - it "returns an #{step_enum_class} when step is 0" do - @step.call(1, 2, 0).should be_an_instance_of(step_enum_class) + ruby_version_is ""..."3.0" do + it "returns an #{step_enum_class} when step is 0" do + @step.call(1, 2, 0).should be_an_instance_of(step_enum_class) + end end it "returns an #{step_enum_class} when not passed a block and self > stop" do diff --git a/spec/ruby/core/numeric/step_spec.rb b/spec/ruby/core/numeric/step_spec.rb index e9067864c83..27730002298 100644 --- a/spec/ruby/core/numeric/step_spec.rb +++ b/spec/ruby/core/numeric/step_spec.rb @@ -26,12 +26,14 @@ step_enum_class = Enumerator::ArithmeticSequence end - it "returns an #{step_enum_class} when step is 0" do - 1.step(5, 0).should be_an_instance_of(step_enum_class) - end + ruby_version_is ""..."3.0" do + it "returns an #{step_enum_class} when step is 0" do + 1.step(5, 0).should be_an_instance_of(step_enum_class) + end - it "returns an #{step_enum_class} when step is 0.0" do - 1.step(2, 0.0).should be_an_instance_of(step_enum_class) + it "returns an #{step_enum_class} when step is 0.0" do + 1.step(2, 0.0).should be_an_instance_of(step_enum_class) + end end describe "returned #{step_enum_class}" do @@ -48,7 +50,7 @@ end end - ruby_version_is "2.6" do + ruby_version_is "2.6"..."3.0" do it "is infinity when step is 0" do enum = 1.step(5, 0) enum.size.should == Float::INFINITY @@ -85,18 +87,20 @@ end describe 'with keyword arguments' do - it "doesn't raise an error when step is 0" do - -> { 1.step(to: 5, by: 0) { break } }.should_not raise_error - end + ruby_version_is ""..."3.0" do + it "doesn't raise an error when step is 0" do + -> { 1.step(to: 5, by: 0) { break } }.should_not raise_error + end - it "doesn't raise an error when step is 0.0" do - -> { 1.step(to: 2, by: 0.0) { break } }.should_not raise_error - end + it "doesn't raise an error when step is 0.0" do + -> { 1.step(to: 2, by: 0.0) { break } }.should_not raise_error + end - it "should loop over self when step is 0 or 0.0" do - 1.step(to: 2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0] - 1.step(to: 2, by: 0).take(5).should eql [1, 1, 1, 1, 1] - 1.1.step(to: 2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1] + it "should loop over self when step is 0 or 0.0" do + 1.step(to: 2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0] + 1.step(to: 2, by: 0).take(5).should eql [1, 1, 1, 1, 1] + 1.1.step(to: 2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1] + end end describe "when no block is given" do @@ -106,12 +110,14 @@ 1.step(by: 42).size.should == infinity_value end - it "should return infinity_value when step is 0" do - 1.step(to: 5, by: 0).size.should == infinity_value - end + ruby_version_is ""..."3.0" do + it "should return infinity_value when step is 0" do + 1.step(to: 5, by: 0).size.should == infinity_value + end - it "should return infinity_value when step is 0.0" do - 1.step(to: 2, by: 0.0).size.should == infinity_value + it "should return infinity_value when step is 0.0" do + 1.step(to: 2, by: 0.0).size.should == infinity_value + end end it "should return infinity_value when ascending towards a limit of Float::INFINITY" do @@ -146,12 +152,24 @@ end describe 'with mixed arguments' do - it "doesn't raise an error when step is 0" do - -> { 1.step(5, by: 0) { break } }.should_not raise_error + ruby_version_is ""..."3.0" do + it "doesn't raise an error when step is 0" do + -> { 1.step(5, by: 0) { break } }.should_not raise_error + end + + it "doesn't raise an error when step is 0.0" do + -> { 1.step(2, by: 0.0) { break } }.should_not raise_error + end end - it "doesn't raise an error when step is 0.0" do - -> { 1.step(2, by: 0.0) { break } }.should_not raise_error + ruby_version_is "3.0" do + it " raises an ArgumentError when step is 0" do + -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when step is 0.0" do + -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError) + end end it "raises a ArgumentError when limit and to are defined" do @@ -162,21 +180,25 @@ -> { 1.step(5, 1, by: 5) { break } }.should raise_error(ArgumentError) end - it "should loop over self when step is 0 or 0.0" do - 1.step(2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0] - 1.step(2, by: 0).take(5).should eql [1, 1, 1, 1, 1] - 1.1.step(2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1] + ruby_version_is ""..."3.0" do + it "should loop over self when step is 0 or 0.0" do + 1.step(2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0] + 1.step(2, by: 0).take(5).should eql [1, 1, 1, 1, 1] + 1.1.step(2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1] + end end describe "when no block is given" do describe "returned Enumerator" do describe "size" do - it "should return infinity_value when step is 0" do - 1.step(5, by: 0).size.should == infinity_value - end + ruby_version_is ""..."3.0" do + it "should return infinity_value when step is 0" do + 1.step(5, by: 0).size.should == infinity_value + end - it "should return infinity_value when step is 0.0" do - 1.step(2, by: 0.0).size.should == infinity_value + it "should return infinity_value when step is 0.0" do + 1.step(2, by: 0.0).size.should == infinity_value + end end end end diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb index d25d2a923fb..83cbb399850 100644 --- a/spec/ruby/core/objectspace/define_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb @@ -94,7 +94,7 @@ def finalize(id) ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") end - it "warns if the finalizer was a block in the reciever" do + it "warns if the finalizer was a block in the receiver" do code = <<-RUBY class CapturesSelf def initialize diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb index 7edd11b1e16..7f167a3d9d5 100644 --- a/spec/ruby/core/proc/shared/to_s.rb +++ b/spec/ruby/core/proc/shared/to_s.rb @@ -33,8 +33,13 @@ describe "for a proc created with UnboundMethod#to_proc" do it "returns a description including '(lambda)' and optionally including file and line number" do - def hello; end - method("hello").to_proc.send(@method).should =~ /^#$/ + def hello; end + s = method("hello").to_proc.send(@method) + if s.include? __FILE__ + s.should =~ /^#$/ + else + s.should =~ /^#$/ + end end it "has a binary encoding" do diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb index 2fa93ad8bf3..b61f5ab64e2 100644 --- a/spec/ruby/core/process/constants_spec.rb +++ b/spec/ruby/core/process/constants_spec.rb @@ -60,4 +60,26 @@ Process::RLIMIT_AS.should == 10 end end + + platform_is :windows do + it "does not define RLIMIT constants" do + %i[ + RLIMIT_CPU + RLIMIT_FSIZE + RLIMIT_DATA + RLIMIT_STACK + RLIMIT_CORE + RLIMIT_RSS + RLIMIT_NPROC + RLIMIT_NOFILE + RLIMIT_MEMLOCK + RLIMIT_AS + RLIM_INFINITY + RLIM_SAVED_MAX + RLIM_SAVED_CUR + ].each do |const| + Process.const_defined?(const).should be_false + end + end + end end diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb index 0a2c2f77e75..deb8913b6bc 100644 --- a/spec/ruby/core/process/exec_spec.rb +++ b/spec/ruby/core/process/exec_spec.rb @@ -193,9 +193,11 @@ map_fd_fixture = fixture __FILE__, "map_fd.rb" cmd = <<-EOC f = File.open(#{@name.inspect}, "w+") - child_fd = f.fileno + 1 - File.open(#{@child_fd_file.inspect}, "w") { |io| io.print child_fd } - Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f } + File.open(#{__FILE__.inspect}, "r") do |io| + child_fd = io.fileno + File.open(#{@child_fd_file.inspect}, "w") { |io| io.print child_fd } + Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f } + end EOC ruby_exe(cmd, escape: true) diff --git a/spec/ruby/core/process/getrlimit_spec.rb b/spec/ruby/core/process/getrlimit_spec.rb index f77a61a475e..eb8ddfcf543 100644 --- a/spec/ruby/core/process/getrlimit_spec.rb +++ b/spec/ruby/core/process/getrlimit_spec.rb @@ -11,8 +11,8 @@ Process.getrlimit(:DATA) end -platform_is_not :windows do - describe "Process.getrlimit" do +describe "Process.getrlimit" do + platform_is_not :windows do it "returns a two-element Array of Integers" do result = Process.getrlimit Process::RLIMIT_CORE result.size.should == 2 @@ -88,4 +88,13 @@ end end end -end + + platform_is :windows do + it "is not implemented" do + Process.respond_to?(:getrlimit).should be_false + lambda do + Process.getrlimit(nil) + end.should raise_error NotImplementedError + end + end +end \ No newline at end of file diff --git a/spec/ruby/core/process/setrlimit_spec.rb b/spec/ruby/core/process/setrlimit_spec.rb index 8bc035a4f12..4fe613812da 100644 --- a/spec/ruby/core/process/setrlimit_spec.rb +++ b/spec/ruby/core/process/setrlimit_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' -platform_is_not :windows do - describe "Process.setrlimit" do +describe "Process.setrlimit" do + platform_is_not :windows do context "when passed an Object" do before do @resource = Process::RLIMIT_CORE @@ -229,4 +229,13 @@ end end end + + platform_is :windows do + it "is not implemented" do + Process.respond_to?(:setrlimit).should be_false + lambda do + Process.setrlimit(nil, nil) + end.should raise_error NotImplementedError + end + end end diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb index 37a7ab9152f..40509471ef4 100644 --- a/spec/ruby/core/process/spawn_spec.rb +++ b/spec/ruby/core/process/spawn_spec.rb @@ -536,7 +536,7 @@ def child_pids(pid) File.read(@name).should == "glarkbang" end - platform_is_not :windows do + platform_is_not :windows, :android do it "closes STDERR in the child if :err => :close" do File.open(@name, 'w') do |file| -> do @@ -706,13 +706,15 @@ def child_pids(pid) end it "maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value" do - child_fd = find_unused_fd - args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s]) - pid = Process.spawn(*args, { child_fd => @io }) - Process.waitpid pid - @io.rewind - - @io.read.should == "writing to fd: #{child_fd}" + File.open(__FILE__, "r") do |f| + child_fd = f.fileno + args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s]) + pid = Process.spawn(*args, { child_fd => @io }) + Process.waitpid pid + @io.rewind + + @io.read.should == "writing to fd: #{child_fd}" + end end end end diff --git a/spec/ruby/core/random/default_spec.rb b/spec/ruby/core/random/default_spec.rb index 17551542949..014cc378a90 100644 --- a/spec/ruby/core/random/default_spec.rb +++ b/spec/ruby/core/random/default_spec.rb @@ -1,8 +1,21 @@ require_relative '../../spec_helper' describe "Random::DEFAULT" do - it "returns a Random instance" do - Random::DEFAULT.should be_an_instance_of(Random) + + it "returns a random number generator" do + Random::DEFAULT.should respond_to(:rand) + end + + ruby_version_is ''...'3.0' do + it "returns a Random instance" do + Random::DEFAULT.should be_an_instance_of(Random) + end + end + + ruby_version_is '3.0' do + it "refers to the Random class" do + Random::DEFAULT.should.equal?(Random) + end end it "changes seed on reboot" do diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb index 0ca03f6a35a..b1afa90a417 100644 --- a/spec/ruby/core/range/case_compare_spec.rb +++ b/spec/ruby/core/range/case_compare_spec.rb @@ -25,4 +25,9 @@ (range === RangeSpecs::WithoutSucc.new(2)).should == true end end + + ruby_version_is "2.7" do + it_behaves_like :range_cover_and_include, :=== + it_behaves_like :range_cover, :=== + end end diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb index 29c0e0bfa89..fa881607e93 100644 --- a/spec/ruby/core/range/cover_spec.rb +++ b/spec/ruby/core/range/cover_spec.rb @@ -6,4 +6,5 @@ describe "Range#cover?" do it_behaves_like :range_cover_and_include, :cover? it_behaves_like :range_cover, :cover? + it_behaves_like :range_cover_subrange, :cover? end diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb new file mode 100644 index 00000000000..c3973af13f8 --- /dev/null +++ b/spec/ruby/core/range/minmax_spec.rb @@ -0,0 +1,170 @@ +require_relative '../../spec_helper' + +# These specs use Range.new instead of the literal notation so they parse fine on Ruby < 2.6 +describe 'Range#minmax' do + before(:each) do + @x = mock('x') + @y = mock('y') + + @x.should_receive(:<=>).with(@y).any_number_of_times.and_return(-1) # x < y + @x.should_receive(:<=>).with(@x).any_number_of_times.and_return(0) # x == x + @y.should_receive(:<=>).with(@x).any_number_of_times.and_return(1) # y > x + @y.should_receive(:<=>).with(@y).any_number_of_times.and_return(0) # y == y + end + + describe 'on an inclusive range' do + ruby_version_is '2.6'...'2.7' do + it 'should try to iterate endlessly on an endless range' do + @x.should_receive(:succ).once.and_return(@y) + range = Range.new(@x, nil) + + -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) + end + end + + ruby_version_is '2.7' do + it 'should raise RangeError on an endless range without iterating the range' do + @x.should_not_receive(:succ) + + range = Range.new(@x, nil) + + -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') + end + + it 'raises RangeError or ArgumentError on a beginless range' do + range = Range.new(nil, @x) + + -> { range.minmax }.should raise_error(StandardError) { |e| + if RangeError === e + # error from #min + -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range') + else + # error from #max + -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed') + end + } + end + end + + it 'should return begining of range if beginning and end are equal without iterating the range' do + @x.should_not_receive(:succ) + + (@x..@x).minmax.should == [@x, @x] + end + + it 'should return nil pair if beginning is greater than end without iterating the range' do + @y.should_not_receive(:succ) + + (@y..@x).minmax.should == [nil, nil] + end + + ruby_version_is ''...'2.7' do + it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do + @x.should_receive(:succ).once.and_return(@y) + + (@x..@y).minmax.should == [@x, @y] + end + end + + ruby_version_is '2.7' do + it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do + @x.should_not_receive(:succ) + + (@x..@y).minmax.should == [@x, @y] + end + end + + it 'should return the minimum and maximum values for a numeric range' do + (1..3).minmax.should == [1, 3] + end + + ruby_version_is '2.7' do + it 'should return the minimum and maximum values for a numeric range without iterating the range' do + # We cannot set expectations on integers, + # so we "prevent" iteration by picking a value that would iterate until the spec times out. + range_end = Float::INFINITY + + (1..range_end).minmax.should == [1, range_end] + end + end + + it 'should return the minimum and maximum values according to the provided block by iterating the range' do + @x.should_receive(:succ).once.and_return(@y) + + (@x..@y).minmax { |x, y| - (x <=> y) }.should == [@y, @x] + end + end + + describe 'on an exclusive range' do + ruby_version_is '2.6'...'2.7' do + # Endless ranges introduced in 2.6 + it 'should try to iterate endlessly on an endless range' do + @x.should_receive(:succ).once.and_return(@y) + range = Range.new(@x, nil, true) + + -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) + end + end + + ruby_version_is '2.7' do + it 'should raise RangeError on an endless range' do + @x.should_not_receive(:succ) + range = Range.new(@x, nil, true) + + -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') + end + + it 'should raise RangeError on a beginless range' do + range = Range.new(nil, @x, true) + + -> { range.minmax }.should raise_error(RangeError, + /cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/) + end + end + + ruby_bug "#17014", "2.7.0"..."2.8" do + it 'should return nil pair if beginning and end are equal without iterating the range' do + @x.should_not_receive(:succ) + + (@x...@x).minmax.should == [nil, nil] + end + + it 'should return nil pair if beginning is greater than end without iterating the range' do + @y.should_not_receive(:succ) + + (@y...@x).minmax.should == [nil, nil] + end + + it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do + @x.should_receive(:succ).once.and_return(@y) + + (@x...@y).minmax.should == [@x, @x] + end + end + + it 'should return the minimum and maximum values for a numeric range' do + (1...3).minmax.should == [1, 2] + end + + ruby_version_is '2.7' do + it 'should return the minimum and maximum values for a numeric range without iterating the range' do + # We cannot set expectations on integers, + # so we "prevent" iteration by picking a value that would iterate until the spec times out. + range_end = bignum_value + + (1...range_end).minmax.should == [1, range_end - 1] + end + + it 'raises TypeError if the end value is not an integer' do + range = (0...Float::INFINITY) + -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value') + end + end + + it 'should return the minimum and maximum values according to the provided block by iterating the range' do + @x.should_receive(:succ).once.and_return(@y) + + (@x...@y).minmax { |x, y| - (x <=> y) }.should == [@x, @x] + end + end +end diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb index 33d416fef52..5b09cea4e08 100644 --- a/spec/ruby/core/range/shared/cover.rb +++ b/spec/ruby/core/range/shared/cover.rb @@ -90,7 +90,9 @@ end end end +end +describe :range_cover_subrange, shared: true do ruby_version_is "2.6" do context "range argument" do it "accepts range argument" do diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb index d83868a0fb7..e284551ab31 100644 --- a/spec/ruby/core/range/step_spec.rb +++ b/spec/ruby/core/range/step_spec.rb @@ -297,7 +297,7 @@ it "yields Float values incremented by a Float step" do eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x } - ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])\ + ScratchPad.recorded.should eql([-2.0, -0.5, 1.0]) ScratchPad.record [] eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x } @@ -371,20 +371,41 @@ end describe "when no block is given" do + ruby_version_is "3.0" do + it "raises an ArgumentError if step is 0" do + -> { (-1..1).step(0) }.should raise_error(ArgumentError) + end + end + describe "returned Enumerator" do describe "size" do - it "raises a TypeError if step does not respond to #to_int" do - obj = mock("Range#step non-integer") - enum = (1..2).step(obj) - -> { enum.size }.should raise_error(TypeError) + ruby_version_is ""..."3.0" do + it "raises a TypeError if step does not respond to #to_int" do + obj = mock("Range#step non-integer") + enum = (1..2).step(obj) + -> { enum.size }.should raise_error(TypeError) + end + + it "raises a TypeError if #to_int does not return an Integer" do + obj = mock("Range#step non-integer") + obj.should_receive(:to_int).and_return("1") + enum = (1..2).step(obj) + + -> { enum.size }.should raise_error(TypeError) + end end - it "raises a TypeError if #to_int does not return an Integer" do - obj = mock("Range#step non-integer") - obj.should_receive(:to_int).and_return("1") - enum = (1..2).step(obj) + ruby_version_is "3.0" do + it "raises a TypeError if step does not respond to #to_int" do + obj = mock("Range#step non-integer") + -> { (1..2).step(obj) }.should raise_error(TypeError) + end - -> { enum.size }.should raise_error(TypeError) + it "raises a TypeError if #to_int does not return an Integer" do + obj = mock("Range#step non-integer") + obj.should_receive(:to_int).and_return("1") + -> { (1..2).step(obj) }.should raise_error(TypeError) + end end ruby_version_is ""..."2.6" do @@ -404,7 +425,7 @@ end end - ruby_version_is "2.6" do + ruby_version_is "2.6"..."3.0" do it "returns Float::INFINITY for zero step" do (-1..1).step(0).size.should == Float::INFINITY (-1..1).step(0.0).size.should == Float::INFINITY diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb index e6cf365ac32..21df18a5ae1 100644 --- a/spec/ruby/core/string/capitalize_spec.rb +++ b/spec/ruby/core/string/capitalize_spec.rb @@ -80,9 +80,18 @@ -> { "abc".capitalize(:invalid_option) }.should raise_error(ArgumentError) end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String) + StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb index 8a4be0a81e5..b66015172c2 100644 --- a/spec/ruby/core/string/center_spec.rb +++ b/spec/ruby/core/string/center_spec.rb @@ -91,13 +91,26 @@ -> { "hello".center(0, "") }.should raise_error(ArgumentError) end - it "returns subclass instances when called on subclasses" do - StringSpecs::MyString.new("").center(10).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").center(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + + "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end + end - "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) - "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on subclasses" do + StringSpecs::MyString.new("").center(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + + "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end end ruby_version_is ''...'2.7' do diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb index b3f64d71189..3d6207f876a 100644 --- a/spec/ruby/core/string/chomp_spec.rb +++ b/spec/ruby/core/string/chomp_spec.rb @@ -46,15 +46,28 @@ end end - it "returns subclass instances when called on a subclass" do - str = StringSpecs::MyString.new("hello\n").chomp - str.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + str = StringSpecs::MyString.new("hello\n").chomp + str.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + str = StringSpecs::MyString.new("hello\n").chomp + str.should be_an_instance_of(String) + end end it "removes trailing characters that match $/ when it has been assigned a value" do $/ = "cdef" "abcdef".chomp.should == "ab" end + + it "removes one trailing newline for string with invalid encoding" do + "\xa0\xa1\n".chomp.should == "\xa0\xa1" + end end describe "when passed nil" do @@ -108,6 +121,10 @@ it "returns an empty String when self is empty" do "".chomp("").should == "" end + + it "removes one trailing newline for string with invalid encoding" do + "\xa0\xa1\n".chomp("").should == "\xa0\xa1" + end end describe "when passed '\\n'" do diff --git a/spec/ruby/core/string/chop_spec.rb b/spec/ruby/core/string/chop_spec.rb index 582d3c58c5c..9b4e7363c64 100644 --- a/spec/ruby/core/string/chop_spec.rb +++ b/spec/ruby/core/string/chop_spec.rb @@ -61,8 +61,16 @@ end end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb index bd5b56a312b..8469791f74f 100644 --- a/spec/ruby/core/string/delete_prefix_spec.rb +++ b/spec/ruby/core/string/delete_prefix_spec.rb @@ -41,9 +41,18 @@ 'hello'.delete_prefix(o).should == 'o' end - it "returns a subclass instance when called on a subclass instance" do - s = StringSpecs::MyString.new('hello') - s.delete_prefix('hell').should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_prefix('hell').should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_prefix('hell').should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb index b6e54f8386b..ebca0b7dae3 100644 --- a/spec/ruby/core/string/delete_spec.rb +++ b/spec/ruby/core/string/delete_spec.rb @@ -93,8 +93,16 @@ -> { "hello world".delete(mock('x')) }.should raise_error(TypeError) end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb index dbb5f9df9e5..12d0ee175e6 100644 --- a/spec/ruby/core/string/delete_suffix_spec.rb +++ b/spec/ruby/core/string/delete_suffix_spec.rb @@ -41,9 +41,18 @@ 'hello'.delete_suffix(o).should == 'h' end - it "returns a subclass instance when called on a subclass instance" do - s = StringSpecs::MyString.new('hello') - s.delete_suffix('ello').should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_suffix('ello').should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_suffix('ello').should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb index 8c840bdcc4e..4427c9df108 100644 --- a/spec/ruby/core/string/downcase_spec.rb +++ b/spec/ruby/core/string/downcase_spec.rb @@ -76,8 +76,16 @@ end end - it "returns a subclass instance for subclasses" do - StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns a subclass instance for subclasses" do + StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance for subclasses" do + StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb index ebdd0167aa5..817dec6c4db 100644 --- a/spec/ruby/core/string/dump_spec.rb +++ b/spec/ruby/core/string/dump_spec.rb @@ -19,8 +19,16 @@ "foo".freeze.dump.should_not.frozen? end - it "returns a subclass instance" do - StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns a subclass instance" do + StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance" do + StringSpecs::MyString.new.dump.should be_an_instance_of(String) + end end it "wraps string with \"" do diff --git a/spec/ruby/core/string/fixtures/classes.rb b/spec/ruby/core/string/fixtures/classes.rb index 1cc7600abb4..26fcd51b5d5 100644 --- a/spec/ruby/core/string/fixtures/classes.rb +++ b/spec/ruby/core/string/fixtures/classes.rb @@ -46,4 +46,15 @@ def initialize(str) self.replace(str) end end + + class SpecialVarProcessor + def process(match) + if $~ != nil + str = $~[0] + else + str = "unset" + end + "<#{str}>" + end + end end diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb index 23e0ad2260f..6789199ff36 100644 --- a/spec/ruby/core/string/gsub_spec.rb +++ b/spec/ruby/core/string/gsub_spec.rb @@ -236,11 +236,22 @@ def replacement.to_str() "hello_replacement" end -> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError) end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String) + StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String) + end end # Note: $~ cannot be tested because mspec messes with it @@ -464,6 +475,11 @@ def replacement.to_str() "hello_replacement" end offsets.should == [[1, 2], [4, 5]] end + it "does not set $~ for procs created from methods" do + str = "hello" + str.gsub("l", &StringSpecs::SpecialVarProcessor.new.method(:process)).should == "heo" + end + it "restores $~ after leaving the block" do [/./, "l"].each do |pattern| old_md = nil diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb index 481ef77ca85..0c3b2a2f446 100644 --- a/spec/ruby/core/string/ljust_spec.rb +++ b/spec/ruby/core/string/ljust_spec.rb @@ -74,13 +74,26 @@ -> { "hello".ljust(10, '') }.should raise_error(ArgumentError) end - it "returns subclass instances when called on subclasses" do - StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + + "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end + end - "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) - "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on subclasses" do + StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + + "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end end ruby_version_is ''...'2.7' do diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb index bf39f4fdb9b..f51aacff446 100644 --- a/spec/ruby/core/string/rjust_spec.rb +++ b/spec/ruby/core/string/rjust_spec.rb @@ -74,13 +74,26 @@ -> { "hello".rjust(10, '') }.should raise_error(ArgumentError) end - it "returns subclass instances when called on subclasses" do - StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + + "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end + end - "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) - "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on subclasses" do + StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + + "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end end ruby_version_is ''...'2.7' do diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb index 156565ff138..f9c910596a4 100644 --- a/spec/ruby/core/string/shared/each_line.rb +++ b/spec/ruby/core/string/shared/each_line.rb @@ -93,10 +93,20 @@ end end - it "yields subclass instances for subclasses" do - a = [] - StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class } - a.should == [StringSpecs::MyString, StringSpecs::MyString] + ruby_version_is ''...'3.0' do + it "yields subclass instances for subclasses" do + a = [] + StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class } + a.should == [StringSpecs::MyString, StringSpecs::MyString] + end + end + + ruby_version_is '3.0' do + it "yields String instances for subclasses" do + a = [] + StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class } + a.should == [String, String] + end end it "returns self" do diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb index 6b6f37217a5..69997b7c1da 100644 --- a/spec/ruby/core/string/shared/slice.rb +++ b/spec/ruby/core/string/shared/slice.rb @@ -163,11 +163,22 @@ -> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError) end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, 0,0).should be_an_instance_of(StringSpecs::MyString) - s.send(@method, 0,4).should be_an_instance_of(StringSpecs::MyString) - s.send(@method, 1,4).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, 0,0).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 0,4).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 1,4).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, 0,0).should be_an_instance_of(String) + s.send(@method, 0,4).should be_an_instance_of(String) + s.send(@method, 1,4).should be_an_instance_of(String) + end end it "handles repeated application" do @@ -252,11 +263,22 @@ end end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, 0...0).should be_an_instance_of(StringSpecs::MyString) - s.send(@method, 0..4).should be_an_instance_of(StringSpecs::MyString) - s.send(@method, 1..4).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, 0...0).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 0..4).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 1..4).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, 0...0).should be_an_instance_of(String) + s.send(@method, 0..4).should be_an_instance_of(String) + s.send(@method, 1..4).should be_an_instance_of(String) + end end it "calls to_int on range arguments" do @@ -348,10 +370,20 @@ end end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, //).should be_an_instance_of(StringSpecs::MyString) - s.send(@method, /../).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, //).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, /../).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, //).should be_an_instance_of(String) + s.send(@method, /../).should be_an_instance_of(String) + end end it "sets $~ to MatchData when there is a match and nil when there's none" do @@ -436,10 +468,20 @@ -> { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError) end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, /(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString) - s.send(@method, /(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, /(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String) + s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String) + end end it "sets $~ to MatchData when there is a match and nil when there's none" do @@ -493,11 +535,22 @@ -> { "hello".send(@method, o) }.should raise_error(TypeError) end - it "returns a subclass instance when given a subclass instance" do - s = StringSpecs::MyString.new("el") - r = "hello".send(@method, s) - r.should == "el" - r.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".send(@method, s) + r.should == "el" + r.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".send(@method, s) + r.should == "el" + r.should be_an_instance_of(String) + end end end @@ -567,9 +620,18 @@ -> { "hello".send(@method, /(?)/, '') }.should raise_error(IndexError) end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, /(?.)/, 'q').should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(?.)/, 'q').should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(?.)/, 'q').should be_an_instance_of(String) + end end it "sets $~ to MatchData when there is a match and nil when there's none" do diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb index 7ca488dd882..25602103b67 100644 --- a/spec/ruby/core/string/shared/succ.rb +++ b/spec/ruby/core/string/shared/succ.rb @@ -59,10 +59,20 @@ "\xFF\xFF".send(@method).should == "\x01\x00\x00" end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String) + StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String) + StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String) + end end ruby_version_is ''...'2.7' do diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb index bd0a63971b8..83b475c8b5a 100644 --- a/spec/ruby/core/string/slice_spec.rb +++ b/spec/ruby/core/string/slice_spec.rb @@ -142,12 +142,21 @@ def obj.method_missing(name, *) name == :to_int ? 2 : super; end "hello".slice!(obj, obj).should == "ll" end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(0, 0).should be_an_instance_of(StringSpecs::MyString) - s.slice!(0, 4).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0, 0).should be_an_instance_of(StringSpecs::MyString) + s.slice!(0, 4).should be_an_instance_of(StringSpecs::MyString) + end end + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0, 0).should be_an_instance_of(String) + s.slice!(0, 4).should be_an_instance_of(String) + end + end it "returns the substring given by the character offsets" do "hellö there".slice!(1,0).should == "" @@ -196,10 +205,20 @@ def obj.method_missing(name, *) name == :to_int ? 2 : super; end end end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(0...0).should be_an_instance_of(StringSpecs::MyString) - s.slice!(0..4).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0...0).should be_an_instance_of(StringSpecs::MyString) + s.slice!(0..4).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0...0).should be_an_instance_of(String) + s.slice!(0..4).should be_an_instance_of(String) + end end it "calls to_int on range arguments" do @@ -299,10 +318,20 @@ def to.method_missing(name) name == :to_int ? -2 : super; end end end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(//).should be_an_instance_of(StringSpecs::MyString) - s.slice!(/../).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(//).should be_an_instance_of(StringSpecs::MyString) + s.slice!(/../).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(//).should be_an_instance_of(String) + s.slice!(/../).should be_an_instance_of(String) + end end it "returns the matching portion of self with a multi byte character" do @@ -383,10 +412,20 @@ def to.method_missing(name) name == :to_int ? -2 : super; end "har".slice!(/(.)(.)(.)/, obj).should == "a" end - it "returns subclass instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(/(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString) - s.slice!(/(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(/(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString) + s.slice!(/(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(/(.)(.)/, 0).should be_an_instance_of(String) + s.slice!(/(.)(.)/, 1).should be_an_instance_of(String) + end end it "returns the encoding aware capture for the given index" do @@ -461,11 +500,22 @@ def to.method_missing(name) name == :to_int ? -2 : super; end -> { "hello".slice!(o) }.should raise_error(TypeError) end - it "returns a subclass instance when given a subclass instance" do - s = StringSpecs::MyString.new("el") - r = "hello".slice!(s) - r.should == "el" - r.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".slice!(s) + r.should == "el" + r.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".slice!(s) + r.should == "el" + r.should be_an_instance_of(String) + end end it "raises a FrozenError if self is frozen" do diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb index 7ac8d7815c7..c5441e3a492 100644 --- a/spec/ruby/core/string/split_spec.rb +++ b/spec/ruby/core/string/split_spec.rb @@ -159,28 +159,48 @@ "foo".split("bar", 3).should == ["foo"] end - it "returns subclass instances based on self" do - ["", "x.y.z.", " x y "].each do |str| - ["", ".", " "].each do |pat| - [-1, 0, 1, 2].each do |limit| - StringSpecs::MyString.new(str).split(pat, limit).each do |x| - x.should be_an_instance_of(StringSpecs::MyString) - end + ruby_version_is ''...'3.0' do + it "returns subclass instances based on self" do + ["", "x.y.z.", " x y "].each do |str| + ["", ".", " "].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(StringSpecs::MyString) + end - str.split(StringSpecs::MyString.new(pat), limit).each do |x| - x.should be_an_instance_of(String) + str.split(StringSpecs::MyString.new(pat), limit).each do |x| + x.should be_an_instance_of(String) + end end end end end + + it "does not call constructor on created subclass instances" do + # can't call should_not_receive on an object that doesn't yet exist + # so failure here is signalled by exception, not expectation failure + + s = StringSpecs::StringWithRaisingConstructor.new('silly:string') + s.split(':').first.should == 'silly' + end end - it "does not call constructor on created subclass instances" do - # can't call should_not_receive on an object that doesn't yet exist - # so failure here is signalled by exception, not expectation failure + ruby_version_is '3.0' do + it "returns String instances based on self" do + ["", "x.y.z.", " x y "].each do |str| + ["", ".", " "].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(String) + end - s = StringSpecs::StringWithRaisingConstructor.new('silly:string') - s.split(':').first.should == 'silly' + str.split(StringSpecs::MyString.new(pat), limit).each do |x| + x.should be_an_instance_of(String) + end + end + end + end + end end ruby_version_is ''...'2.7' do @@ -355,24 +375,40 @@ "foo".split(/bar/, 3).should == ["foo"] end - it "returns subclass instances based on self" do - ["", "x:y:z:", " x y "].each do |str| - [//, /:/, /\s+/].each do |pat| - [-1, 0, 1, 2].each do |limit| - StringSpecs::MyString.new(str).split(pat, limit).each do |x| - x.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances based on self" do + ["", "x:y:z:", " x y "].each do |str| + [//, /:/, /\s+/].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(StringSpecs::MyString) + end end end end end - end - it "does not call constructor on created subclass instances" do - # can't call should_not_receive on an object that doesn't yet exist - # so failure here is signalled by exception, not expectation failure + it "does not call constructor on created subclass instances" do + # can't call should_not_receive on an object that doesn't yet exist + # so failure here is signalled by exception, not expectation failure + + s = StringSpecs::StringWithRaisingConstructor.new('silly:string') + s.split(/:/).first.should == 'silly' + end + end - s = StringSpecs::StringWithRaisingConstructor.new('silly:string') - s.split(/:/).first.should == 'silly' + ruby_version_is '3.0' do + it "returns String instances based on self" do + ["", "x:y:z:", " x y "].each do |str| + [//, /:/, /\s+/].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(String) + end + end + end + end + end end ruby_version_is ''...'2.7' do @@ -493,16 +529,32 @@ end describe "for a String subclass" do - it "yields instances of the same subclass" do - a = [] - StringSpecs::MyString.new("a|b").split("|") { |str| a << str } - first, last = a + ruby_version_is ''...'3.0' do + it "yields instances of the same subclass" do + a = [] + StringSpecs::MyString.new("a|b").split("|") { |str| a << str } + first, last = a + + first.should be_an_instance_of(StringSpecs::MyString) + first.should == "a" - first.should be_an_instance_of(StringSpecs::MyString) - first.should == "a" + last.should be_an_instance_of(StringSpecs::MyString) + last.should == "b" + end + end + + ruby_version_is '3.0' do + it "yields instances of String" do + a = [] + StringSpecs::MyString.new("a|b").split("|") { |str| a << str } + first, last = a - last.should be_an_instance_of(StringSpecs::MyString) - last.should == "b" + first.should be_an_instance_of(String) + first.should == "a" + + last.should be_an_instance_of(String) + last.should == "b" + end end end end diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb index 5a7fbb59def..6f75402c9cf 100644 --- a/spec/ruby/core/string/squeeze_spec.rb +++ b/spec/ruby/core/string/squeeze_spec.rb @@ -80,8 +80,16 @@ -> { "hello world".squeeze(mock('x')) }.should raise_error(TypeError) end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb index 80cf8622d54..5ae9a4bbf3f 100644 --- a/spec/ruby/core/string/sub_spec.rb +++ b/spec/ruby/core/string/sub_spec.rb @@ -192,11 +192,22 @@ -> { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError) end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String) + StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String) + end end it "sets $~ to MatchData of match and nil when there's none" do diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb index 0b50cc35c48..32b358607e3 100644 --- a/spec/ruby/core/string/swapcase_spec.rb +++ b/spec/ruby/core/string/swapcase_spec.rb @@ -73,9 +73,18 @@ -> { "abc".swapcase(:invalid_option) }.should raise_error(ArgumentError) end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("").swapcase.should be_an_instance_of(StringSpecs::MyString) - StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").swapcase.should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String) + StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb index cdf5667ea37..c6ad12139e2 100644 --- a/spec/ruby/core/string/tr_s_spec.rb +++ b/spec/ruby/core/string/tr_s_spec.rb @@ -45,8 +45,16 @@ "bla".tr_s(from_str, to_str).should == "BlA" end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String) + end end ruby_version_is ''...'2.7' do diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb index 212d06f6790..06be1e66414 100644 --- a/spec/ruby/core/string/tr_spec.rb +++ b/spec/ruby/core/string/tr_spec.rb @@ -57,8 +57,16 @@ "bla".tr(from_str, to_str).should == "BlA" end - it "returns subclass instances when called on a subclass" do - StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns Stringinstances when called on a subclass" do + StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String) + end end ruby_version_is ''...'2.7' do diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb index 166ae588694..011c75f5c47 100644 --- a/spec/ruby/core/string/unpack/w_spec.rb +++ b/spec/ruby/core/string/unpack/w_spec.rb @@ -23,3 +23,13 @@ "\x01\x02\x03".unpack("w w").should == [1, 2] end end + +describe "String#unpack with directive 'w*'" do + + it "decodes BER-compressed integers" do + "\x01\x02\x03\x04".unpack("w*").should == [1, 2, 3, 4] + "\x00\xCE\x0F\x84\x80\x80\x80\x80\x80\x80\x80\x80\x00\x01\x00".unpack("w*").should == [0, 9999, 2**65, 1, 0] + "\x81\x80\x80\x80\x80\x80\x80\x80\x80\x00\x90\x80\x80\x80\x80\x80\x80\x80\x03\x01\x02".unpack("w*").should == [2**63, (2**60 + 3), 1, 2] + end + +end diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb index 13ebd09a950..6cf44b47035 100644 --- a/spec/ruby/core/string/upcase_spec.rb +++ b/spec/ruby/core/string/upcase_spec.rb @@ -73,8 +73,16 @@ end end - it "returns a subclass instance for subclasses" do - StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(StringSpecs::MyString) + ruby_version_is ''...'3.0' do + it "returns a subclass instance for subclasses" do + StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance for subclasses" do + StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/valid_encoding_spec.rb b/spec/ruby/core/string/valid_encoding_spec.rb index 09916df0797..d5bf31710f7 100644 --- a/spec/ruby/core/string/valid_encoding_spec.rb +++ b/spec/ruby/core/string/valid_encoding_spec.rb @@ -13,7 +13,7 @@ end it "returns true for all encodings self is valid in" do - str = "\u{6754}" + str = "\xE6\x9D\x94" str.force_encoding('BINARY').valid_encoding?.should be_true str.force_encoding('UTF-8').valid_encoding?.should be_true str.force_encoding('US-ASCII').valid_encoding?.should be_false @@ -100,6 +100,14 @@ str.force_encoding('UTF8-MAC').valid_encoding?.should be_true end + ruby_version_is '3.0' do + it "returns true for IBM720 encoding self is valid in" do + str = "\xE6\x9D\x94" + str.force_encoding('IBM720').valid_encoding?.should be_true + str.force_encoding('CP720').valid_encoding?.should be_true + end + end + it "returns false if self is valid in one encoding, but invalid in the one it's tagged with" do str = "\u{8765}" str.valid_encoding?.should be_true diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb index 90839baa0fa..b0ae28beee2 100644 --- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb @@ -36,6 +36,19 @@ end end + context "when used in a core method" do + it "returns nil" do + location = nil + tap { location = caller_locations(1, 1)[0] } + location.label.should == "tap" + if location.path.start_with?(" { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/) + end + end +end diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb new file mode 100644 index 00000000000..ecf75bf85c9 --- /dev/null +++ b/spec/ruby/core/warning/element_set_spec.rb @@ -0,0 +1,31 @@ +require_relative '../../spec_helper' + +ruby_version_is '2.7' do + describe "Warning.[]=" do + it "emits and suppresses warnings for :deprecated" do + ruby_exe('Warning[:deprecated] = true; $; = ""', args: "2>&1").should =~ /is deprecated/ + ruby_exe('Warning[:deprecated] = false; $; = ""', args: "2>&1").should == "" + end + + describe ":experimental" do + before do + ruby_version_is ""..."3.0" do + @src = 'case 0; in a; end' + end + + ruby_version_is "3.0" do + @src = '1 => a' + end + end + + it "emits and suppresses warnings for :experimental" do + ruby_exe("Warning[:experimental] = true; eval('#{@src}')", args: "2>&1").should =~ /is experimental/ + ruby_exe("Warning[:experimental] = false; eval('#{@src}')", args: "2>&1").should == "" + end + end + + it "raises for unknown category" do + -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/) + end + end +end diff --git a/spec/ruby/default.mspec b/spec/ruby/default.mspec index 6fd6d2bf9c2..a0dc69c03d3 100644 --- a/spec/ruby/default.mspec +++ b/spec/ruby/default.mspec @@ -45,5 +45,6 @@ class MSpecScript set :toplevel_constants_excludes, [ /\wSpecs?$/, /^CS_CONST/, + /^CSL_CONST/, ] end diff --git a/spec/ruby/fixtures/code_loading.rb b/spec/ruby/fixtures/code_loading.rb index d6cf0edb478..decd56a3582 100644 --- a/spec/ruby/fixtures/code_loading.rb +++ b/spec/ruby/fixtures/code_loading.rb @@ -12,7 +12,22 @@ def load(name, wrap=false) end end + def self.preload_rubygems + # Require RubyGems eagerly, to ensure #require is already the RubyGems + # version and RubyGems is only loaded once, before starting #require/#autoload specs + # which snapshot $LOADED_FEATURES and could cause RubyGems to load twice. + # #require specs also snapshot #require, and could end up redefining #require as the original core Kernel#require. + @rubygems ||= begin + require "rubygems" + true + rescue LoadError + true + end + end + def self.spec_setup + preload_rubygems + @saved_loaded_features = $LOADED_FEATURES.clone @saved_load_path = $LOAD_PATH.clone ScratchPad.record [] diff --git a/spec/ruby/fixtures/constants.rb b/spec/ruby/fixtures/constants.rb index e5b20596ef1..37271ddcc8a 100644 --- a/spec/ruby/fixtures/constants.rb +++ b/spec/ruby/fixtures/constants.rb @@ -1,7 +1,7 @@ # Contains all static code examples of all constants behavior in language and # library specs. The specs include language/constants_spec.rb and the specs -# for Module#const_defined?, Module#const_get, Module#const_set, -# Module#remove_const, Module#const_missing and Module#constants. +# for Module#const_defined?, Module#const_get, Module#const_set, Module#remove_const, +# Module#const_source_location, Module#const_missing and Module#constants. # # Rather than defining a class structure for each example, a canonical set of # classes is used along with numerous constants, in most cases, a unique @@ -28,14 +28,17 @@ # for completeness. No other constant of this name should be defined in the # specs. CS_CONST1 = :const1 # only defined here +CS_CONST1_LINE = __LINE__ - 1 module ConstantSpecs # Included at toplevel module ModuleA CS_CONST10 = :const10_1 + CS_CONST10_LINE = __LINE__ - 1 CS_CONST12 = :const12_2 CS_CONST13 = :const13 + CS_CONST13_LINE = __LINE__ - 1 CS_CONST21 = :const21_2 end @@ -44,12 +47,14 @@ module ModuleB CS_CONST10 = :const10_9 CS_CONST11 = :const11_2 CS_CONST12 = :const12_1 + CS_CONST12_LINE = __LINE__ - 1 end # Included in ChildA module ModuleC CS_CONST10 = :const10_4 CS_CONST15 = :const15_1 + CS_CONST15_LINE = __LINE__ - 1 end # Included in ChildA metaclass @@ -75,7 +80,9 @@ module ModuleD # are run. class ClassA + CS_CLASS_A_LINE = __LINE__ - 1 CS_CONST10 = :const10_10 + CS_CONST10_LINE = __LINE__ - 1 CS_CONST16 = :const16 CS_CONST17 = :const17_2 CS_CONST22 = :const22_1 @@ -97,10 +104,14 @@ class ParentA include ModuleB CS_CONST4 = :const4 + CS_CONST4_LINE = __LINE__ - 1 CS_CONST10 = :const10_5 + CS_CONST10_LINE = __LINE__ - 1 CS_CONST11 = :const11_1 + CS_CONST11_LINE = __LINE__ - 1 CS_CONST15 = :const15_2 CS_CONST20 = :const20_2 + CS_CONST20_LINE = __LINE__ - 1 CS_CONST21 = :const21_1 CS_CONST22 = :const22_2 @@ -118,6 +129,7 @@ class ContainerA CS_CONST5 = :const5 CS_CONST10 = :const10_2 + CS_CONST10_LINE = __LINE__ - 1 CS_CONST23 = :const23 class ChildA < ParentA @@ -135,6 +147,7 @@ def const19; CS_CONST19; end CS_CONST6 = :const6 CS_CONST10 = :const10_3 + CS_CONST10_LINE = __LINE__ - 1 CS_CONST19 = :const19_2 def self.const10; CS_CONST10; end @@ -282,6 +295,7 @@ class ClassD < ClassC end CS_PRIVATE = :cs_private + CS_PRIVATE_LINE = __LINE__ - 1 private_constant :CS_PRIVATE end diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb index 45a8ec5f9a3..b2a3cc84c48 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -873,7 +873,7 @@ def m(a) yield a end end.call(1, 2, 3).should == [[], 1, 2, 3] end - it "are required" do + it "are required for a lambda" do -> { -> *a, b do [a, b] @@ -881,6 +881,12 @@ def m(a) yield a end }.should raise_error(ArgumentError) end + it "are assigned to nil when not enough arguments are given to a proc" do + proc do |a, *b, c| + [a, b, c] + end.call.should == [nil, [], nil] + end + describe "with required args" do it "gathers remaining args in the splat" do diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb index 1475e20f750..410cb9afb13 100644 --- a/spec/ruby/language/case_spec.rb +++ b/spec/ruby/language/case_spec.rb @@ -424,4 +424,13 @@ def ===(o) :called end.should == :called end + + # Homogeneous cases are often optimized to avoid === using a jump table, and should be tested separately. + # See https://github.com/jruby/jruby/issues/6440 + it "handles homogeneous cases" do + case + when 1; 'foo' + when 2; 'bar' + end.should == 'foo' + end end diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb index 4ff6e651816..83db164e1a9 100644 --- a/spec/ruby/language/class_spec.rb +++ b/spec/ruby/language/class_spec.rb @@ -285,6 +285,16 @@ def xyz }.should raise_error(TypeError) end + it "raises a TypeError when trying to extend non-Class" do + error_msg = /superclass must be a.* Class/ + -> { class TestClass < ""; end }.should raise_error(TypeError, error_msg) + -> { class TestClass < 1; end }.should raise_error(TypeError, error_msg) + -> { class TestClass < :symbol; end }.should raise_error(TypeError, error_msg) + -> { class TestClass < mock('o'); end }.should raise_error(TypeError, error_msg) + -> { class TestClass < Module.new; end }.should raise_error(TypeError, error_msg) + -> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg) + end + ruby_version_is ""..."3.0" do it "allows accessing the block of the original scope" do suppress_warning do diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb index 6a024cae236..218f1e49707 100644 --- a/spec/ruby/language/fixtures/super.rb +++ b/spec/ruby/language/fixtures/super.rb @@ -455,6 +455,52 @@ def m_modified(a, b, *args) end end + module ZSuperWithRestAndPost + class A + def m(*args, a, b) + args + end + + def m_modified(*args, a, b) + args + end + end + + class B < A + def m(*args, a, b) + super + end + + def m_modified(*args, a, b) + args[1] = 14 + super + end + end + end + + module ZSuperWithRestOthersAndPost + class A + def m(a, *args, b) + args + end + + def m_modified(a, *args, b) + args + end + end + + class B < A + def m(a, *args, b) + super + end + + def m_modified(a, *args, b) + args[1] = 14 + super + end + end + end + module ZSuperWithRestReassigned class A def a(*args) diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb index 630c9d2364b..d6600ddb4a0 100644 --- a/spec/ruby/language/hash_spec.rb +++ b/spec/ruby/language/hash_spec.rb @@ -149,6 +149,12 @@ def h.to_hash; {:b => 2, :c => 3}; end -> { {**obj} }.should raise_error(TypeError) end + it "raises a TypeError if the object does not respond to #to_hash" do + obj = 42 + -> { {**obj} }.should raise_error(TypeError) + -> { {a: 1, **obj} }.should raise_error(TypeError) + end + it "does not change encoding of literal string keys during creation" do binary_hash = HashStringsBinary.literal_hash utf8_hash = HashStringsUTF8.literal_hash diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb index 1ec21a2ec0a..95df8457e4d 100644 --- a/spec/ruby/language/heredoc_spec.rb +++ b/spec/ruby/language/heredoc_spec.rb @@ -59,6 +59,22 @@ s.encoding.should == Encoding::US_ASCII end + ruby_version_is "2.7" do + it 'raises SyntaxError if quoted HEREDOC identifier is ending not on same line' do + -> { + eval %{<<"HERE\n"\nraises syntax error\nHERE} + }.should raise_error(SyntaxError) + end + end + + ruby_version_is ""..."2.7" do + it 'prints a warning if quoted HEREDOC identifier is ending not on same line' do + -> { + eval %{<<"HERE\n"\nit warns\nHERE} + }.should complain(/here document identifier ends with a newline/) + end + end + it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do require_relative 'fixtures/squiggly_heredoc' SquigglyHeredocSpecs.message.should == "character density, n.:\n The number of very weird people in the office.\n" diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb index dd4ea515725..462a182b3d3 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -596,10 +596,21 @@ def m(**k) k end m(a: 1, b: 2).should == { a: 1, b: 2 } m(*[]).should == {} m(**{}).should == {} - m(**{a: 1, b: 2}, **{a: 4, c: 7}).should == { a: 4, b: 2, c: 7 } + suppress_warning { + eval "m(**{a: 1, b: 2}, **{a: 4, c: 7})" + }.should == { a: 4, b: 2, c: 7 } -> { m(2) }.should raise_error(ArgumentError) end + ruby_version_is "2.7" do + evaluate <<-ruby do + def m(**k); k end; + ruby + + m("a" => 1).should == { "a" => 1 } + end + end + evaluate <<-ruby do def m(&b) b end ruby @@ -1626,6 +1637,20 @@ def m(a, b=1, *c, d, e:, f: 2, g:, **k, &l) result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l] end + ruby_version_is "2.7" do + evaluate <<-ruby do + def m(a, **nil); a end; + ruby + + m({a: 1}).should == {a: 1} + m({"a" => 1}).should == {"a" => 1} + + -> { m(a: 1) }.should raise_error(ArgumentError) + -> { m(**{a: 1}) }.should raise_error(ArgumentError) + -> { m("a" => 1) }.should raise_error(ArgumentError) + end + end + ruby_version_is ''...'3.0' do evaluate <<-ruby do def m(a, b = nil, c = nil, d, e: nil, **f) @@ -1665,6 +1690,32 @@ def m(a, b = nil, c = nil, d, e: nil, **f) end end + ruby_version_is '2.7' do + context 'when passing an empty keyword splat to a method that does not accept keywords' do + evaluate <<-ruby do + def m(*a); a; end + ruby + + h = {} + m(**h).should == [] + end + end + end + + ruby_version_is '2.7'...'3.0' do + context 'when passing an empty keyword splat to a method that does not accept keywords' do + evaluate <<-ruby do + def m(a); a; end + ruby + h = {} + + -> do + m(**h).should == {} + end.should complain(/warning: Passing the keyword argument as the last hash parameter is deprecated/) + end + end + end + ruby_version_is ''...'3.0' do context "assigns keyword arguments from a passed Hash without modifying it" do evaluate <<-ruby do @@ -1683,6 +1734,18 @@ def m(a: nil); a; end end ruby_version_is '3.0' do + context 'when passing an empty keyword splat to a method that does not accept keywords' do + evaluate <<-ruby do + def m(a); a; end + ruby + h = {} + + -> do + m(**h).should == {} + end.should raise_error(ArgumentError) + end + end + context "raises ArgumentError if passing hash as keyword arguments" do evaluate <<-ruby do def m(a: nil); a; end diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb index 91ad23bf324..1596b2b8d28 100644 --- a/spec/ruby/language/pattern_matching_spec.rb +++ b/spec/ruby/language/pattern_matching_spec.rb @@ -9,20 +9,24 @@ ScratchPad.record [] end - it "can be standalone in operator that deconstructs value" do - eval(<<-RUBY).should == [0, 1] - [0, 1] in [a, b] - [a, b] - RUBY + ruby_version_is "3.0" do + it "can be standalone assoc operator that deconstructs value" do + suppress_warning do + eval(<<-RUBY).should == [0, 1] + [0, 1] => [a, b] + [a, b] + RUBY + end + end end it "extends case expression with case/in construction" do eval(<<~RUBY).should == :bar case [0, 1] - in [0] - :foo - in [0, 1] - :bar + in [0] + :foo + in [0, 1] + :bar end RUBY end @@ -30,27 +34,33 @@ it "allows using then operator" do eval(<<~RUBY).should == :bar case [0, 1] - in [0] then :foo - in [0, 1] then :bar + in [0] then :foo + in [0, 1] then :bar end RUBY end - it "warns about pattern matching is experimental feature" do - -> { - eval <<~RUBY - case 0 - in 0 - end - RUBY - }.should complain(/warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!/) + describe "warning" do + before do + ruby_version_is ""..."3.0" do + @src = 'case 0; in a; end' + end + + ruby_version_is "3.0" do + @src = '1 => a' + end + end + + it "warns about pattern matching is experimental feature" do + -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i) + end end it "binds variables" do eval(<<~RUBY).should == 1 case [0, 1] - in [0, a] - a + in [0, a] + a end RUBY end @@ -59,8 +69,8 @@ -> { eval <<~RUBY case [] - when 1 == 1 - in [] + when 1 == 1 + in [] end RUBY }.should raise_error(SyntaxError, /syntax error, unexpected `in'/) @@ -68,8 +78,8 @@ -> { eval <<~RUBY case [] - in [] - when 1 == 1 + in [] + when 1 == 1 end RUBY }.should raise_error(SyntaxError, /syntax error, unexpected `when'/) @@ -78,12 +88,12 @@ it "checks patterns until the first matching" do eval(<<~RUBY).should == :bar case [0, 1] - in [0] - :foo - in [0, 1] - :bar - in [0, 1] - :baz + in [0] + :foo + in [0, 1] + :bar + in [0, 1] + :baz end RUBY end @@ -91,10 +101,10 @@ it "executes else clause if no pattern matches" do eval(<<~RUBY).should == false case [0, 1] - in [0] - true - else - false + in [0] + true + else + false end RUBY end @@ -103,7 +113,7 @@ -> { eval <<~RUBY case [0, 1] - in [0] + in [0] end RUBY }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) @@ -113,8 +123,8 @@ -> { eval <<~RUBY case 0 - in 1 + 1 - true + in 1 + 1 + true end RUBY }.should raise_error(SyntaxError, /unexpected/) @@ -124,8 +134,8 @@ it "supports if guard" do eval(<<~RUBY).should == false case 0 - in 0 if false - true + in 0 if false + true else false end @@ -133,8 +143,8 @@ eval(<<~RUBY).should == true case 0 - in 0 if true - true + in 0 if true + true else false end @@ -144,8 +154,8 @@ it "supports unless guard" do eval(<<~RUBY).should == false case 0 - in 0 unless true - true + in 0 unless true + true else false end @@ -153,8 +163,8 @@ eval(<<~RUBY).should == true case 0 - in 0 unless false - true + in 0 unless false + true else false end @@ -164,8 +174,8 @@ it "makes bound variables visible in guard" do eval(<<~RUBY).should == true case [0, 1] - in [a, 1] if a >= 0 - true + in [a, 1] if a >= 0 + true end RUBY end @@ -173,7 +183,7 @@ it "does not evaluate guard if pattern does not match" do eval <<~RUBY case 0 - in 1 if (ScratchPad << :foo) || true + in 1 if (ScratchPad << :foo) || true else end RUBY @@ -184,10 +194,10 @@ it "takes guards into account when there are several matching patterns" do eval(<<~RUBY).should == :bar case 0 - in 0 if false - :foo - in 0 if true - :bar + in 0 if false + :foo + in 0 if true + :bar end RUBY end @@ -195,8 +205,8 @@ it "executes else clause if no guarded pattern matches" do eval(<<~RUBY).should == false case 0 - in 0 if false - true + in 0 if false + true else false end @@ -207,7 +217,7 @@ -> { eval <<~RUBY case [0, 1] - in [0, 1] if false + in [0, 1] if false end RUBY }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) @@ -218,36 +228,36 @@ it "matches an object such that pattern === object" do eval(<<~RUBY).should == true case 0 - in 0 - true + in 0 + true end RUBY eval(<<~RUBY).should == true case 0 - in (-1..1) - true + in (-1..1) + true end RUBY eval(<<~RUBY).should == true case 0 - in Integer - true + in Integer + true end RUBY eval(<<~RUBY).should == true case "0" - in /0/ - true + in /0/ + true end RUBY eval(<<~RUBY).should == true case "0" - in ->(s) { s == "0" } - true + in ->(s) { s == "0" } + true end RUBY end @@ -257,8 +267,8 @@ eval(<<~RUBY).should == true case "x" - in "#{x + ""}" - true + in "#{x + ""}" + true end RUBY end @@ -268,8 +278,8 @@ it "matches a value and binds variable name to this value" do eval(<<~RUBY).should == 0 case 0 - in a - a + in a + a end RUBY end @@ -277,7 +287,7 @@ it "makes bounded variable visible outside a case statement scope" do eval(<<~RUBY).should == 0 case 0 - in a + in a end a @@ -287,9 +297,9 @@ it "create local variables even if a pattern doesn't match" do eval(<<~RUBY).should == [0, nil, nil] case 0 - in a - in b - in c + in a + in b + in c end [a, b, c] @@ -299,33 +309,33 @@ it "allow using _ name to drop values" do eval(<<~RUBY).should == 0 case [0, 1] - in [a, _] - a + in [a, _] + a end RUBY end it "supports using _ in a pattern several times" do - eval(<<~RUBY).should == 2 + eval(<<~RUBY).should == true case [0, 1, 2] - in [0, _, _] - _ + in [0, _, _] + true end RUBY end it "supports using any name with _ at the beginning in a pattern several times" do - eval(<<~RUBY).should == 2 + eval(<<~RUBY).should == true case [0, 1, 2] - in [0, _x, _x] - _x + in [0, _x, _x] + true end RUBY - eval(<<~RUBY).should == 2 + eval(<<~RUBY).should == true case {a: 0, b: 1, c: 2} - in {a: 0, b: _x, c: _x} - _x + in {a: 0, b: _x, c: _x} + true end RUBY end @@ -334,7 +344,7 @@ -> { eval <<~RUBY case [0] - in [a, a] + in [a, a] end RUBY }.should raise_error(SyntaxError, /duplicated variable name/) @@ -345,8 +355,8 @@ eval(<<~RUBY).should == true case 0 - in ^a - true + in ^a + true end RUBY end @@ -354,15 +364,15 @@ it "allows applying ^ operator to bound variables" do eval(<<~RUBY).should == 1 case [1, 1] - in [n, ^n] - n + in [n, ^n] + n end RUBY eval(<<~RUBY).should == false case [1, 2] - in [n, ^n] - true + in [n, ^n] + true else false end @@ -373,8 +383,8 @@ -> { eval <<~RUBY case [1, 2] - in [^n, n] - true + in [^n, n] + true else false end @@ -387,8 +397,8 @@ it "matches if any of patterns matches" do eval(<<~RUBY).should == true case 0 - in 0 | 1 | 2 - true + in 0 | 1 | 2 + true end RUBY end @@ -397,7 +407,7 @@ -> { eval <<~RUBY case [0, 1] - in [0, 0] | [0, a] + in [0, 0] | [0, a] end RUBY }.should raise_error(SyntaxError, /illegal variable in alternative pattern/) @@ -406,10 +416,10 @@ it "support underscore prefixed variables in alternation" do eval(<<~RUBY).should == true case [0, 1] - in [1, _] - false - in [0, 0] | [0, _a] - true + in [1, _] + false + in [0, 0] | [0, _a] + true end RUBY end @@ -419,8 +429,8 @@ it "binds a variable to a value if pattern matches" do eval(<<~RUBY).should == 0 case 0 - in Integer => n - n + in Integer => n + n end RUBY end @@ -428,8 +438,8 @@ it "can be used as a nested pattern" do eval(<<~RUBY).should == [2, 3] case [1, [2, 3]] - in [1, Array => ary] - ary + in [1, Array => ary] + ary end RUBY end @@ -439,8 +449,8 @@ it "supports form Constant(pat, pat, ...)" do eval(<<~RUBY).should == true case [0, 1, 2] - in Array(0, 1, 2) - true + in Array(0, 1, 2) + true end RUBY end @@ -448,8 +458,8 @@ it "supports form Constant[pat, pat, ...]" do eval(<<~RUBY).should == true case [0, 1, 2] - in Array[0, 1, 2] - true + in Array[0, 1, 2] + true end RUBY end @@ -457,8 +467,8 @@ it "supports form [pat, pat, ...]" do eval(<<~RUBY).should == true case [0, 1, 2] - in [0, 1, 2] - true + in [0, 1, 2] + true end RUBY end @@ -466,22 +476,22 @@ it "supports form pat, pat, ..." do eval(<<~RUBY).should == true case [0, 1, 2] - in 0, 1, 2 - true + in 0, 1, 2 + true end RUBY eval(<<~RUBY).should == 1 case [0, 1, 2] - in 0, a, 2 - a + in 0, a, 2 + a end RUBY eval(<<~RUBY).should == [1, 2] case [0, 1, 2] - in 0, *rest - rest + in 0, *rest + rest end RUBY end @@ -492,8 +502,8 @@ def obj.deconstruct; [0, 1] end eval(<<~RUBY).should == true case obj - in [Integer, Integer] - true + in [Integer, Integer] + true end RUBY end @@ -501,8 +511,8 @@ def obj.deconstruct; [0, 1] end it "does not match object if Constant === object returns false" do eval(<<~RUBY).should == false case [0, 1, 2] - in String[0, 1, 2] - true + in String[0, 1, 2] + true else false end @@ -514,8 +524,8 @@ def obj.deconstruct; [0, 1] end eval(<<~RUBY).should == false case obj - in Object[] - true + in Object[] + true else false end @@ -529,7 +539,7 @@ def obj.deconstruct; "" end -> { eval <<~RUBY case obj - in Object[] + in Object[] else end RUBY @@ -542,8 +552,8 @@ def obj.deconstruct; [1] end eval(<<~RUBY).should == false case obj - in Object[0] - true + in Object[0] + true else false end @@ -553,30 +563,17 @@ def obj.deconstruct; [1] end it "binds variables" do eval(<<~RUBY).should == [0, 1, 2] case [0, 1, 2] - in [a, b, c] - [a, b, c] + in [a, b, c] + [a, b, c] end RUBY end - it "binds variable even if patter matches only partially" do - a = nil - - eval(<<~RUBY).should == 0 - case [0, 1, 2] - in [a, 1, 3] - else - end - - a - RUBY - end - it "supports splat operator *rest" do eval(<<~RUBY).should == [1, 2] case [0, 1, 2] - in [0, *rest] - rest + in [0, *rest] + rest end RUBY end @@ -584,8 +581,8 @@ def obj.deconstruct; [1] end it "does not match partially by default" do eval(<<~RUBY).should == false case [0, 1, 2, 3] - in [1, 2] - true + in [1, 2] + true else false end @@ -595,15 +592,15 @@ def obj.deconstruct; [1] end it "does match partially from the array beginning if list + , syntax used" do eval(<<~RUBY).should == true case [0, 1, 2, 3] - in [0, 1,] - true + in [0, 1,] + true end RUBY eval(<<~RUBY).should == true case [0, 1, 2, 3] - in 0, 1,; - true + in 0, 1,; + true end RUBY end @@ -611,8 +608,8 @@ def obj.deconstruct; [1] end it "matches [] with []" do eval(<<~RUBY).should == true case [] - in [] - true + in [] + true end RUBY end @@ -620,8 +617,8 @@ def obj.deconstruct; [1] end it "matches anything with *" do eval(<<~RUBY).should == true case [0, 1] - in *; - true + in *; + true end RUBY end @@ -631,8 +628,8 @@ def obj.deconstruct; [1] end it "supports form Constant(id: pat, id: pat, ...)" do eval(<<~RUBY).should == true case {a: 0, b: 1} - in Hash(a: 0, b: 1) - true + in Hash(a: 0, b: 1) + true end RUBY end @@ -640,8 +637,8 @@ def obj.deconstruct; [1] end it "supports form Constant[id: pat, id: pat, ...]" do eval(<<~RUBY).should == true case {a: 0, b: 1} - in Hash[a: 0, b: 1] - true + in Hash[a: 0, b: 1] + true end RUBY end @@ -649,8 +646,8 @@ def obj.deconstruct; [1] end it "supports form {id: pat, id: pat, ...}" do eval(<<~RUBY).should == true case {a: 0, b: 1} - in {a: 0, b: 1} - true + in {a: 0, b: 1} + true end RUBY end @@ -658,22 +655,22 @@ def obj.deconstruct; [1] end it "supports form id: pat, id: pat, ..." do eval(<<~RUBY).should == true case {a: 0, b: 1} - in a: 0, b: 1 - true + in a: 0, b: 1 + true end RUBY eval(<<~RUBY).should == [0, 1] case {a: 0, b: 1} - in a: a, b: b - [a, b] + in a: a, b: b + [a, b] end RUBY eval(<<~RUBY).should == { b: 1, c: 2 } case {a: 0, b: 1, c: 2} - in a: 0, **rest - rest + in a: 0, **rest + rest end RUBY end @@ -681,40 +678,40 @@ def obj.deconstruct; [1] end it "supports a: which means a: a" do eval(<<~RUBY).should == [0, 1] case {a: 0, b: 1} - in Hash(a:, b:) - [a, b] + in Hash(a:, b:) + [a, b] end RUBY a = b = nil eval(<<~RUBY).should == [0, 1] case {a: 0, b: 1} - in Hash[a:, b:] - [a, b] + in Hash[a:, b:] + [a, b] end RUBY a = b = nil eval(<<~RUBY).should == [0, 1] case {a: 0, b: 1} - in {a:, b:} - [a, b] + in {a:, b:} + [a, b] end RUBY a = nil eval(<<~RUBY).should == [0, {b: 1, c: 2}] case {a: 0, b: 1, c: 2} - in {a:, **rest} - [a, rest] + in {a:, **rest} + [a, rest] end RUBY a = b = nil eval(<<~RUBY).should == [0, 1] case {a: 0, b: 1} - in a:, b: - [a, b] + in a:, b: + [a, b] end RUBY end @@ -722,8 +719,8 @@ def obj.deconstruct; [1] end it "can mix key (a:) and key-value (a: b) declarations" do eval(<<~RUBY).should == [0, 1] case {a: 0, b: 1} - in Hash(a:, b: x) - [a, x] + in Hash(a:, b: x) + [a, x] end RUBY end @@ -731,8 +728,8 @@ def obj.deconstruct; [1] end it "supports 'string': key literal" do eval(<<~RUBY).should == true case {a: 0} - in {"a": 0} - true + in {"a": 0} + true end RUBY end @@ -741,7 +738,7 @@ def obj.deconstruct; [1] end -> { eval <<~RUBY case {a: 1} - in {"a" => 1} + in {"a" => 1} end RUBY }.should raise_error(SyntaxError, /unexpected/) @@ -753,7 +750,7 @@ def obj.deconstruct; [1] end -> { eval <<~'RUBY' case {a: 1} - in {"#{x}": 1} + in {"#{x}": 1} end RUBY }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/) @@ -763,7 +760,7 @@ def obj.deconstruct; [1] end -> { eval <<~RUBY case {a: 1} - in {a: 1, b: 2, a: 3} + in {a: 1, b: 2, a: 3} end RUBY }.should raise_error(SyntaxError, /duplicated key name/) @@ -775,8 +772,8 @@ def obj.deconstruct_keys(*); {a: 1} end eval(<<~RUBY).should == true case obj - in {a: 1} - true + in {a: 1} + true end RUBY end @@ -784,8 +781,8 @@ def obj.deconstruct_keys(*); {a: 1} end it "does not match object if Constant === object returns false" do eval(<<~RUBY).should == false case {a: 1} - in String[a: 1] - true + in String[a: 1] + true else false end @@ -797,8 +794,8 @@ def obj.deconstruct_keys(*); {a: 1} end eval(<<~RUBY).should == false case obj - in Object[a: 1] - true + in Object[a: 1] + true else false end @@ -812,7 +809,7 @@ def obj.deconstruct_keys(*); "" end -> { eval <<~RUBY case obj - in Object[a: 1] + in Object[a: 1] end RUBY }.should raise_error(TypeError, /deconstruct_keys must return Hash/) @@ -824,8 +821,8 @@ def obj.deconstruct_keys(*); {"a" => 1} end eval(<<~RUBY).should == false case obj - in Object[a: 1] - true + in Object[a: 1] + true else false end @@ -838,8 +835,8 @@ def obj.deconstruct_keys(*); {a: 1} end eval(<<~RUBY).should == false case obj - in Object[a: 2] - true + in Object[a: 2] + true else false end @@ -856,11 +853,11 @@ def obj.deconstruct_keys(*args) eval <<~RUBY case obj - in Object[a: 1, b: 2, c: 3] + in Object[a: 1, b: 2, c: 3] end RUBY - ScratchPad.recorded.should == [[[:a, :b, :c]]] + ScratchPad.recorded.sort.should == [[[:a, :b, :c]]] end it "passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" do @@ -873,11 +870,11 @@ def obj.deconstruct_keys(*args) eval <<~RUBY case obj - in Object[a: 1, b: 2, **] + in Object[a: 1, b: 2, **] end RUBY - ScratchPad.recorded.should == [[[:a, :b]]] + ScratchPad.recorded.sort.should == [[[:a, :b]]] end it "passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" do @@ -890,7 +887,7 @@ def obj.deconstruct_keys(*args) eval <<~RUBY case obj - in Object[a: 1, **rest] + in Object[a: 1, **rest] end RUBY @@ -900,30 +897,17 @@ def obj.deconstruct_keys(*args) it "binds variables" do eval(<<~RUBY).should == [0, 1, 2] case {a: 0, b: 1, c: 2} - in {a: x, b: y, c: z} - [x, y, z] - end - RUBY - end - - it "binds variable even if pattern matches only partially" do - x = nil - - eval(<<~RUBY).should == 0 - case {a: 0, b: 1} - in {a: x, b: 2} - else + in {a: x, b: y, c: z} + [x, y, z] end - - x RUBY end it "supports double splat operator **rest" do eval(<<~RUBY).should == {b: 1, c: 2} case {a: 0, b: 1, c: 2} - in {a: 0, **rest} - rest + in {a: 0, **rest} + rest end RUBY end @@ -931,15 +915,15 @@ def obj.deconstruct_keys(*args) it "treats **nil like there should not be any other keys in a matched Hash" do eval(<<~RUBY).should == true case {a: 1, b: 2} - in {a: 1, b: 2, **nil} - true + in {a: 1, b: 2, **nil} + true end RUBY eval(<<~RUBY).should == false case {a: 1, b: 2} - in {a: 1, **nil} - true + in {a: 1, **nil} + true else false end @@ -949,8 +933,8 @@ def obj.deconstruct_keys(*args) it "can match partially" do eval(<<~RUBY).should == true case {a: 1, b: 2} - in {a: 1} - true + in {a: 1} + true end RUBY end @@ -958,8 +942,8 @@ def obj.deconstruct_keys(*args) it "matches {} with {}" do eval(<<~RUBY).should == true case {} - in {} - true + in {} + true end RUBY end @@ -967,8 +951,8 @@ def obj.deconstruct_keys(*args) it "matches anything with **" do eval(<<~RUBY).should == true case {a: 1} - in **; - true + in **; + true end RUBY end @@ -990,8 +974,8 @@ def deconstruct result = eval(<<~RUBY) case [] - in [0] - true + in [0] + true end RUBY end @@ -1014,8 +998,8 @@ def deconstruct_keys(_) result = eval(<<~RUBY) case {} - in a: 0 - true + in a: 0 + true end RUBY end @@ -1038,8 +1022,8 @@ def ===(obj) result = eval(<<~RUBY) case {} - in Array - true + in Array + true end RUBY end diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb index 5ce4e77906c..65fcb1e2ac9 100644 --- a/spec/ruby/language/predefined_spec.rb +++ b/spec/ruby/language/predefined_spec.rb @@ -933,6 +933,14 @@ def obj.foo2; yield; end end describe "Global variable $VERBOSE" do + before :each do + @verbose = $VERBOSE + end + + after :each do + $VERBOSE = @verbose + end + it "converts truthy values to true" do [true, 1, 0, [], ""].each do |true_value| $VERBOSE = true_value @@ -1246,3 +1254,25 @@ def obj.foo2; yield; end end end end + +ruby_version_is "2.7" do + describe "$LOAD_PATH.resolve_feature_path" do + it "returns what will be loaded without actual loading, .rb file" do + extension, path = $LOAD_PATH.resolve_feature_path('set') + extension.should == :rb + path.should.end_with?('/set.rb') + end + + it "returns what will be loaded without actual loading, .so file" do + require 'rbconfig' + + extension, path = $LOAD_PATH.resolve_feature_path('etc') + extension.should == :so + path.should.end_with?("/etc.#{RbConfig::CONFIG['DLEXT']}") + end + + it "raises LoadError if feature cannot be found" do + -> { $LOAD_PATH.resolve_feature_path('noop') }.should raise_error(LoadError) + end + end +end diff --git a/spec/ruby/language/regexp/character_classes_spec.rb b/spec/ruby/language/regexp/character_classes_spec.rb index 5f4221e213f..0cf1e9b6f46 100644 --- a/spec/ruby/language/regexp/character_classes_spec.rb +++ b/spec/ruby/language/regexp/character_classes_spec.rb @@ -609,6 +609,12 @@ "루비(Ruby)".match(/\p{Hangul}+/u).to_a.should == ["루비"] end + ruby_bug "#17340", ''...'3.0' do + it "raises a RegexpError for an unterminated unicode property" do + -> { Regexp.new('\p{') }.should raise_error(RegexpError) + end + end + it "supports \\X (unicode 9.0 with UTR #51 workarounds)" do # simple emoji without any fancy modifier or ZWJ /\X/.match("\u{1F98A}").to_a.should == ["🦊"] diff --git a/spec/ruby/language/safe_spec.rb b/spec/ruby/language/safe_spec.rb index 53ab4f95610..f3a7efc9537 100644 --- a/spec/ruby/language/safe_spec.rb +++ b/spec/ruby/language/safe_spec.rb @@ -135,4 +135,18 @@ }.call end end + + ruby_version_is "2.7"..."3.0" do + it "warn when access" do + -> { + $SAFE + }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/) + end + + it "warn when set" do + -> { + $SAFE = 1 + }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/) + end + end end diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb index df735018af3..705d9f35485 100644 --- a/spec/ruby/language/singleton_class_spec.rb +++ b/spec/ruby/language/singleton_class_spec.rb @@ -157,6 +157,23 @@ class << @object end end +describe "Defining yield in singleton class" do + ruby_version_is "2.7"..."3.0" do + it 'emits a deprecation warning' do + code = <<~RUBY + def m + class << Object.new + yield + end + end + m { :ok } + RUBY + + -> { eval(code) }.should complain(/warning: `yield' in class syntax will not be supported from Ruby 3.0/) + end + end +end + describe "Defining instance methods on a singleton class" do before :each do @k = ClassSpecs::K.new diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb index 3e94155bf30..1ac5c5e1bee 100644 --- a/spec/ruby/language/super_spec.rb +++ b/spec/ruby/language/super_spec.rb @@ -293,6 +293,21 @@ def obj.foobar(array) it "without explicit arguments passes arguments and rest arguments" do SuperSpecs::ZSuperWithRestAndOthers::B.new.m(1, 2, 3, 4, 5).should == [3, 4, 5] + SuperSpecs::ZSuperWithRestAndOthers::B.new.m(1, 2).should == [] + end + + it "without explicit arguments passes arguments, rest arguments, and post arguments" do + SuperSpecs::ZSuperWithRestAndPost::B.new.m(1, 2, 3, 4, 5).should == [1, 2, 3] + SuperSpecs::ZSuperWithRestOthersAndPost::B.new.m(1, 2, 3, 4, 5).should == [2, 3, 4] + SuperSpecs::ZSuperWithRestAndPost::B.new.m(1, 2).should == [] + SuperSpecs::ZSuperWithRestOthersAndPost::B.new.m(1, 2).should == [] + end + + it "without explicit arguments passes arguments, rest arguments including modifications, and post arguments" do + SuperSpecs::ZSuperWithRestAndPost::B.new.m_modified(1, 2, 3, 4, 5).should == [1, 14, 3] + SuperSpecs::ZSuperWithRestOthersAndPost::B.new.m_modified(1, 2, 3, 4, 5).should == [2, 14, 4] + SuperSpecs::ZSuperWithRestAndPost::B.new.m_modified(1, 2).should == [nil, 14] + SuperSpecs::ZSuperWithRestOthersAndPost::B.new.m_modified(1, 2).should == [nil, 14] end it "without explicit arguments passes arguments and rest arguments including any modifications" do diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb index 8b67289df4d..ce072baa2c4 100644 --- a/spec/ruby/language/variables_spec.rb +++ b/spec/ruby/language/variables_spec.rb @@ -796,3 +796,32 @@ module VariableSpecs end end end + +describe 'Allowed characters' do + ruby_version_is "2.6" do + # new feature in 2.6 -- https://bugs.ruby-lang.org/issues/13770 + it 'does not allow non-ASCII upcased characters at the beginning' do + -> do + eval <<-CODE + def test + ἍBB = 1 + end + CODE + end.should raise_error(SyntaxError, /dynamic constant assignment/) + end + end + + it 'allows non-ASCII lowercased characters at the beginning' do + result = nil + + eval <<-CODE + def test + μ = 1 + end + + result = test + CODE + + result.should == 1 + end +end diff --git a/spec/ruby/library/fiber/current_spec.rb b/spec/ruby/library/fiber/current_spec.rb index 52dff3dea1a..e67d7d050af 100644 --- a/spec/ruby/library/fiber/current_spec.rb +++ b/spec/ruby/library/fiber/current_spec.rb @@ -42,10 +42,22 @@ fiber3 = Fiber.new do states << :fiber3 fiber2.transfer - flunk + ruby_version_is '3.0' do + states << :fiber3_terminated + end + ruby_version_is '' ... '3.0' do + flunk + end end fiber3.resume - states.should == [:fiber3, :fiber2, :fiber] + + ruby_version_is "" ... "3.0" do + states.should == [:fiber3, :fiber2, :fiber] + end + + ruby_version_is "3.0" do + states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated] + end end end diff --git a/spec/ruby/library/fiber/resume_spec.rb b/spec/ruby/library/fiber/resume_spec.rb index dae717c8a19..39d14bdda0d 100644 --- a/spec/ruby/library/fiber/resume_spec.rb +++ b/spec/ruby/library/fiber/resume_spec.rb @@ -3,10 +3,21 @@ require 'fiber' describe "Fiber#resume" do - it "raises a FiberError if the Fiber has transferred control to another Fiber" do - fiber1 = Fiber.new { true } - fiber2 = Fiber.new { fiber1.transfer; Fiber.yield } - fiber2.resume - -> { fiber2.resume }.should raise_error(FiberError) + ruby_version_is '' ... '3.0' do + it "raises a FiberError if the Fiber has transferred control to another Fiber" do + fiber1 = Fiber.new { true } + fiber2 = Fiber.new { fiber1.transfer; Fiber.yield } + fiber2.resume + -> { fiber2.resume }.should raise_error(FiberError) + end + end + + ruby_version_is '3.0' do + it "can work with Fiber#transfer" do + fiber1 = Fiber.new { true } + fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise } + fiber2.resume.should == 10 + fiber2.resume.should == 20 + end end end diff --git a/spec/ruby/library/fiber/transfer_spec.rb b/spec/ruby/library/fiber/transfer_spec.rb index d13053666c2..7af548da1ad 100644 --- a/spec/ruby/library/fiber/transfer_spec.rb +++ b/spec/ruby/library/fiber/transfer_spec.rb @@ -11,7 +11,13 @@ it "transfers control from one Fiber to another when called from a Fiber" do fiber1 = Fiber.new { :fiber1 } fiber2 = Fiber.new { fiber1.transfer; :fiber2 } - fiber2.resume.should == :fiber1 + + ruby_version_is '' ... '3.0' do + fiber2.resume.should == :fiber1 + end + ruby_version_is '3.0' do + fiber2.resume.should == :fiber2 + end end it "returns to the root Fiber when finished" do @@ -34,12 +40,24 @@ states.should == [:start, :end] end - it "can transfer control to a Fiber that has transferred to another Fiber" do - states = [] - fiber1 = Fiber.new { states << :fiber1 } - fiber2 = Fiber.new { states << :fiber2_start; fiber1.transfer; states << :fiber2_end} - fiber2.resume.should == [:fiber2_start, :fiber1] - fiber2.transfer.should == [:fiber2_start, :fiber1, :fiber2_end] + ruby_version_is '' ... '3.0' do + it "can transfer control to a Fiber that has transferred to another Fiber" do + states = [] + fiber1 = Fiber.new { states << :fiber1 } + fiber2 = Fiber.new { states << :fiber2_start; fiber1.transfer; states << :fiber2_end} + fiber2.resume.should == [:fiber2_start, :fiber1] + fiber2.transfer.should == [:fiber2_start, :fiber1, :fiber2_end] + end + end + + ruby_version_is '3.0' do + it "can not transfer control to a Fiber that has suspended by Fiber.yield" do + states = [] + fiber1 = Fiber.new { states << :fiber1 } + fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end} + fiber2.resume.should == [:fiber2_start, :fiber1] + -> { fiber2.transfer }.should raise_error(FiberError) + end end it "raises a FiberError when transferring to a Fiber which resumes itself" do @@ -83,4 +101,28 @@ thread.join states.should == [0, 1, 2, 3] end + + ruby_version_is "" ... "3.0" do + it "runs until Fiber.yield" do + obj = mock('obj') + obj.should_not_receive(:do) + fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do } + fiber.transfer + end + + it "resumes from the last call to Fiber.yield on subsequent invocations" do + fiber = Fiber.new { Fiber.yield :first; :second } + fiber.transfer.should == :first + fiber.transfer.should == :second + end + + it "sets the block parameters to its arguments on the first invocation" do + first = mock('first') + first.should_receive(:arg).with(:first).twice + + fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; } + fiber.transfer :first + fiber.transfer :second + end + end end diff --git a/spec/ruby/library/net/http/http/send_request_spec.rb b/spec/ruby/library/net/http/http/send_request_spec.rb index 03fd32e4708..47b3eef5b95 100644 --- a/spec/ruby/library/net/http/http/send_request_spec.rb +++ b/spec/ruby/library/net/http/http/send_request_spec.rb @@ -26,7 +26,7 @@ response = @http.send_request("HEAD", "/request") response.body.should be_nil - @methods.each do |method| + (@methods - %w[POST PUT]).each do |method| response = @http.send_request(method, "/request") response.body.should == "Request type: #{method}" end diff --git a/spec/ruby/library/openstruct/marshal_load_spec.rb b/spec/ruby/library/openstruct/marshal_load_spec.rb index e07c4cef057..342e5e68cda 100644 --- a/spec/ruby/library/openstruct/marshal_load_spec.rb +++ b/spec/ruby/library/openstruct/marshal_load_spec.rb @@ -4,7 +4,7 @@ describe "OpenStruct#marshal_load when passed [Hash]" do it "defines methods based on the passed Hash" do os = OpenStruct.new - os.marshal_load(age: 20, name: "John") + os.send :marshal_load, age: 20, name: "John" os.age.should eql(20) os.name.should == "John" diff --git a/spec/ruby/library/pathname/glob_spec.rb b/spec/ruby/library/pathname/glob_spec.rb new file mode 100644 index 00000000000..f6dfd6cd588 --- /dev/null +++ b/spec/ruby/library/pathname/glob_spec.rb @@ -0,0 +1,57 @@ +require_relative '../../spec_helper' +require 'pathname' + +describe 'Pathname.glob' do + before :all do + @dir = tmp('pathname_glob') + '/' + @file_1 = @dir + 'lib/ipaddr.rb' + @file_2 = @dir + 'lib/irb.rb' + @file_3 = @dir + 'lib/.hidden.rb' + + touch @file_1 + touch @file_2 + touch @file_3 + end + + after :all do + rm_r @dir[0...-1] + end + + it 'returns [] for no match' do + Pathname.glob(@dir + 'lib/*.js').should == [] + end + + it 'returns matching file paths' do + Pathname.glob(@dir + 'lib/*i*.rb').sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort + end + + it 'returns matching file paths when a flag is provided' do + expected = [Pathname.new(@file_1), Pathname.new(@file_2), Pathname.new(@file_3)].sort + Pathname.glob(@dir + 'lib/*i*.rb', File::FNM_DOTMATCH).sort.should == expected + end + + it 'returns matching file paths when supplied :base keyword argument' do + Pathname.glob('*i*.rb', base: @dir + 'lib').sort.should == [Pathname.new('ipaddr.rb'), Pathname.new('irb.rb')].sort + end + + it "raises an ArgumentError when supplied a keyword argument other than :base" do + -> { + Pathname.glob('*i*.rb', foo: @dir + 'lib') + }.should raise_error(ArgumentError, /unknown keyword: :?foo/) + end + + ruby_version_is ''...'2.7' do + it 'raises an ArgumentError when supplied a flag and :base keyword argument' do + -> { + Pathname.glob(@dir + 'lib/*i*.rb', File::FNM_DOTMATCH, base: 'lib') + }.should raise_error(ArgumentError, 'wrong number of arguments (given 3, expected 1..2)') + end + end + + ruby_version_is "2.7" do + it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do + expected = [Pathname.new('ipaddr.rb'), Pathname.new('irb.rb'), Pathname.new('.hidden.rb')].sort + Pathname.glob('*i*.rb', File::FNM_DOTMATCH, base: @dir + 'lib').sort.should == expected + end + end +end diff --git a/spec/ruby/library/pathname/pathname_spec.rb b/spec/ruby/library/pathname/pathname_spec.rb new file mode 100644 index 00000000000..7d63fe86e30 --- /dev/null +++ b/spec/ruby/library/pathname/pathname_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../spec_helper' +require 'pathname' + +describe "Kernel#Pathname" do + it "is a private instance method" do + Kernel.should have_private_instance_method(:Pathname) + end + + it "is also a public method" do + Kernel.should have_method(:Pathname) + end + + ruby_version_is ''...'2.7' do + it "returns a new pathname when called with a pathname argument" do + path = Pathname('foo') + new_path = Pathname(path) + + path.should_not.equal?(new_path) + end + end + + ruby_version_is '2.7' do + it "returns same argument when called with a pathname argument" do + path = Pathname('foo') + new_path = Pathname(path) + + path.should.equal?(new_path) + end + end +end diff --git a/spec/ruby/library/socket/socket/listen_spec.rb b/spec/ruby/library/socket/socket/listen_spec.rb index 5de70d6db0a..4d2aedab191 100644 --- a/spec/ruby/library/socket/socket/listen_spec.rb +++ b/spec/ruby/library/socket/socket/listen_spec.rb @@ -34,8 +34,10 @@ @server.close end - it 'raises Errno::EOPNOTSUPP' do - -> { @server.listen(1) }.should raise_error(Errno::EOPNOTSUPP) + it 'raises Errno::EOPNOTSUPP or Errno::EACCES' do + -> { @server.listen(1) }.should raise_error { |e| + [Errno::EOPNOTSUPP, Errno::EACCES].should.include?(e.class) + } end end diff --git a/spec/ruby/library/yaml/dump_spec.rb b/spec/ruby/library/yaml/dump_spec.rb index 894d05caec6..3107a8f51d3 100644 --- a/spec/ruby/library/yaml/dump_spec.rb +++ b/spec/ruby/library/yaml/dump_spec.rb @@ -39,13 +39,10 @@ os = OpenStruct.new("age" => 20, "name" => "John") yaml_dump = YAML.dump(os) - if OpenStruct::VERSION.split('.').map(&:to_i).<=>([0,3,0]) >= 0 - expected = "--- !ruby/object:OpenStruct\nage: 20\nname: John\n" - else - expected = "--- !ruby/object:OpenStruct\ntable:\n :age: 20\n :name: John\n" - end - - yaml_dump.should match_yaml(expected) + [ + "--- !ruby/object:OpenStruct\nage: 20\nname: John\n", + "--- !ruby/object:OpenStruct\ntable:\n :age: 20\n :name: John\n", + ].should.include?(yaml_dump) end it "dumps a File without any state" do diff --git a/spec/ruby/optional/capi/exception_spec.rb b/spec/ruby/optional/capi/exception_spec.rb index 62d7d3706e1..9e82e5c7dd4 100644 --- a/spec/ruby/optional/capi/exception_spec.rb +++ b/spec/ruby/optional/capi/exception_spec.rb @@ -55,4 +55,49 @@ -> { @s.rb_set_errinfo("error") }.should raise_error(TypeError) end end + + describe "rb_make_exception" do + it "returns a RuntimeError when given a String argument" do + e = @s.rb_make_exception(["Message"]) + e.class.should == RuntimeError + e.message.should == "Message" + end + + it "returns the exception when given an Exception argument" do + exc = Exception.new + e = @s.rb_make_exception([exc]) + e.should == exc + end + + it "returns the exception with the given class and message" do + e = @s.rb_make_exception([Exception, "Message"]) + e.class.should == Exception + e.message.should == "Message" + end + + it "returns the exception with the given class, message, and backtrace" do + e = @s.rb_make_exception([Exception, "Message", ["backtrace 1"]]) + e.class.should == Exception + e.message.should == "Message" + e.backtrace.should == ["backtrace 1"] + end + + it "raises a TypeError for incorrect types" do + -> { @s.rb_make_exception([nil]) }.should raise_error(TypeError) + -> { @s.rb_make_exception([Object.new]) }.should raise_error(TypeError) + obj = Object.new + def obj.exception + "not exception type" + end + -> { @s.rb_make_exception([obj]) }.should raise_error(TypeError) + end + + it "raises an ArgumentError for too many arguments" do + -> { @s.rb_make_exception([Exception, "Message", ["backtrace 1"], "extra"]) }.should raise_error(ArgumentError) + end + + it "returns nil for empty arguments" do + @s.rb_make_exception([]).should == nil + end + end end diff --git a/spec/ruby/optional/capi/ext/exception_spec.c b/spec/ruby/optional/capi/ext/exception_spec.c index cdd86b183e5..7250792b700 100644 --- a/spec/ruby/optional/capi/ext/exception_spec.c +++ b/spec/ruby/optional/capi/ext/exception_spec.c @@ -32,6 +32,13 @@ VALUE exception_spec_rb_set_errinfo(VALUE self, VALUE exc) { return Qnil; } + +VALUE exception_spec_rb_make_exception(VALUE self, VALUE ary) { + int argc = RARRAY_LENINT(ary); + VALUE *argv = RARRAY_PTR(ary); + return rb_make_exception(argc, argv); +} + void Init_exception_spec(void) { VALUE cls = rb_define_class("CApiExceptionSpecs", rb_cObject); rb_define_method(cls, "rb_exc_new", exception_spec_rb_exc_new, 1); @@ -39,6 +46,7 @@ void Init_exception_spec(void) { rb_define_method(cls, "rb_exc_new3", exception_spec_rb_exc_new3, 1); rb_define_method(cls, "rb_exc_raise", exception_spec_rb_exc_raise, 1); rb_define_method(cls, "rb_set_errinfo", exception_spec_rb_set_errinfo, 1); + rb_define_method(cls, "rb_make_exception", exception_spec_rb_make_exception, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c index 59613c110ff..73e68040137 100644 --- a/spec/ruby/optional/capi/ext/io_spec.c +++ b/spec/ruby/optional/capi/ext/io_spec.c @@ -203,7 +203,9 @@ VALUE io_spec_rb_io_close(VALUE self, VALUE io) { VALUE io_spec_rb_io_set_nonblock(VALUE self, VALUE io) { rb_io_t* fp; +#ifdef F_GETFL int flags; +#endif GetOpenFile(io, fp); rb_io_set_nonblock(fp); #ifdef F_GETFL diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c index 743828b5236..21f98dec525 100644 --- a/spec/ruby/optional/capi/ext/thread_spec.c +++ b/spec/ruby/optional/capi/ext/thread_spec.c @@ -19,7 +19,9 @@ static VALUE thread_spec_rb_thread_alone(VALUE self) { return rb_thread_alone() ? Qtrue : Qfalse; } +#if defined(__GNUC__) #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif /* This is unblocked by unblock_func(). */ static void* blocking_gvl_func(void* data) { diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index 44cf311895a..7539e0c01c9 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -396,12 +396,20 @@ def proc_caller proc = -> x { x } arg_error_proc = -> *_ { raise ArgumentError, '' } run_error_proc = -> *_ { raise RuntimeError, '' } - type_error_proc = -> *_ { raise TypeError, '' } + type_error_proc = -> *_ { raise Exception, 'custom error' } @s.rb_rescue2(arg_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc @s.rb_rescue2(run_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc -> { @s.rb_rescue2(type_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError) - }.should raise_error(TypeError) + }.should raise_error(Exception, 'custom error') + end + + ruby_bug "#17305", ""..."2.7" do + it "raises TypeError if one of the passed exceptions is not a Module" do + -> { + @s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42) + }.should raise_error(TypeError, /class or module required/) + end end end diff --git a/spec/ruby/optional/capi/module_spec.rb b/spec/ruby/optional/capi/module_spec.rb index f5ce7ed8de3..fde86d22235 100644 --- a/spec/ruby/optional/capi/module_spec.rb +++ b/spec/ruby/optional/capi/module_spec.rb @@ -135,7 +135,7 @@ end it "returns a constant defined at toplevel" do - @m.rb_const_get(CApiModuleSpecs::A, :Fixnum).should == Fixnum + @m.rb_const_get(CApiModuleSpecs::A, :Integer).should == Integer end it "returns a constant defined in a superclass" do @@ -176,8 +176,8 @@ end it "calls #const_missing if the constant is not defined in the class or ancestors" do - CApiModuleSpecs::M.should_receive(:const_missing).with(:Fixnum) - @m.rb_const_get_from(CApiModuleSpecs::M, :Fixnum) + CApiModuleSpecs::M.should_receive(:const_missing).with(:Integer) + @m.rb_const_get_from(CApiModuleSpecs::M, :Integer) end it "resolves autoload constants" do diff --git a/spec/ruby/optional/capi/struct_spec.rb b/spec/ruby/optional/capi/struct_spec.rb index c0712036730..0e9e3669080 100644 --- a/spec/ruby/optional/capi/struct_spec.rb +++ b/spec/ruby/optional/capi/struct_spec.rb @@ -62,7 +62,7 @@ end describe "C-API Struct function" do - before :each do + before :all do @s = CApiStructSpecs.new @struct = @s.rb_struct_define_under(CApiStructSpecs, "CAPIStructUnder", "a", "b", "c") end diff --git a/spec/ruby/shared/enumerable/minmax.rb b/spec/ruby/shared/enumerable/minmax.rb new file mode 100644 index 00000000000..8af2626d2a7 --- /dev/null +++ b/spec/ruby/shared/enumerable/minmax.rb @@ -0,0 +1,24 @@ +describe :enumerable_minmax, shared: true do + it "min should return the minimum element" do + @enum.minmax.should == [4, 10] + @strs.minmax.should == ["1010", "60"] + end + + it "returns the minimum when using a block rule" do + @enum.minmax {|a,b| b <=> a }.should == [10, 4] + @strs.minmax {|a,b| a.length <=> b.length }.should == ["2", "55555"] + end + + it "returns [nil, nil] for an empty Enumerable" do + @empty_enum.minmax.should == [nil, nil] + end + + it "raises a NoMethodError for elements without #<=>" do + -> { @incomparable_enum.minmax }.should raise_error(NoMethodError) + end + + it "raises an ArgumentError when elements are incompatible" do + -> { @incompatible_enum.minmax }.should raise_error(ArgumentError) + -> { @enum.minmax{ |a, b| nil } }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/shared/enumerator/enum_for.rb b/spec/ruby/shared/enumerator/enum_for.rb index 9030ffbd7de..a67a76c4613 100644 --- a/spec/ruby/shared/enumerator/enum_for.rb +++ b/spec/ruby/shared/enumerator/enum_for.rb @@ -12,6 +12,13 @@ enum.map { |v| v }.should == [1,2].each { |v| v } end + it "sets regexp matches in the caller" do + "wawa".send(@method, :scan, /./).map {|o| $& }.should == ["w", "a", "w", "a"] + a = [] + "wawa".send(@method, :scan, /./).each {|o| a << $& } + a.should == ["w", "a", "w", "a"] + end + it "exposes multi-arg yields as an array" do o = Object.new def o.each diff --git a/spec/ruby/shared/fiber/resume.rb b/spec/ruby/shared/fiber/resume.rb index d3dc438ae26..f3477804ad1 100644 --- a/spec/ruby/shared/fiber/resume.rb +++ b/spec/ruby/shared/fiber/resume.rb @@ -35,32 +35,11 @@ fiber.send(@method) end - it "runs until Fiber.yield" do - obj = mock('obj') - obj.should_not_receive(:do) - fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do } - fiber.send(@method) - end - - it "resumes from the last call to Fiber.yield on subsequent invocations" do - fiber = Fiber.new { Fiber.yield :first; :second } - fiber.send(@method).should == :first - fiber.send(@method).should == :second - end - it "accepts any number of arguments" do fiber = Fiber.new { |a| } -> { fiber.send(@method, *(1..10).to_a) }.should_not raise_error end - it "sets the block parameters to its arguments on the first invocation" do - first = mock('first') - first.should_receive(:arg).with(:first).twice - fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; } - fiber.send(@method, :first) - fiber.send(@method, :second) - end - it "raises a FiberError if the Fiber is dead" do fiber = Fiber.new { true } fiber.send(@method) diff --git a/spec/ruby/shared/file/identical.rb b/spec/ruby/shared/file/identical.rb index ecc21727ca9..b7a2904839a 100644 --- a/spec/ruby/shared/file/identical.rb +++ b/spec/ruby/shared/file/identical.rb @@ -9,7 +9,11 @@ touch(@file2) { |f| f.puts "file2" } rm_r @link - File.link(@file1, @link) + begin + File.link(@file1, @link) + rescue Errno::EACCES + File.symlink(@file1, @link) + end end after :each do diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb index 7d9954e29a2..f00a6ef294a 100644 --- a/spec/ruby/shared/kernel/raise.rb +++ b/spec/ruby/shared/kernel/raise.rb @@ -50,20 +50,43 @@ def initialize end it "re-raises a previously rescued exception without overwriting the backtrace" do - begin - initial_raise_line = __LINE__; @object.raise 'raised' - rescue => raised - begin - raise_again_line = __LINE__; @object.raise raised - rescue => raised_again - # This spec is written using #backtrace and matching the line number - # from the string, as backtrace_locations is a more advanced - # method that is not always supported by implementations. + # This spec is written using #backtrace and matching the line number + # from the string, as backtrace_locations is a more advanced + # method that is not always supported by implementations. + # + initial_raise_line = nil + raise_again_line = nil + raised_again = nil - raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:") - raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") + if defined?(FiberSpecs::NewFiberToRaise) and @object == FiberSpecs::NewFiberToRaise + fiber = Fiber.new do + begin + initial_raise_line = __LINE__; Fiber.yield + rescue => raised + begin + raise_again_line = __LINE__; Fiber.yield raised + rescue => raised_again + raised_again + end + end + end + fiber.resume + raised = fiber.raise 'raised' + raised_again = fiber.raise raised + else + begin + initial_raise_line = __LINE__; @object.raise 'raised' + rescue => raised + begin + raise_again_line = __LINE__; @object.raise raised + rescue => raised_again + raised_again + end end end + + raised_again.backtrace.first.should include("#{__FILE__}:#{initial_raise_line}:") + raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") end it "allows Exception, message, and backtrace parameters" do diff --git a/spec/ruby/shared/rational/coerce.rb b/spec/ruby/shared/rational/coerce.rb index ffb118e2a71..ccc8901ba0a 100644 --- a/spec/ruby/shared/rational/coerce.rb +++ b/spec/ruby/shared/rational/coerce.rb @@ -17,6 +17,11 @@ result.last.is_a?(Rational).should be_true end + it "coerces to Rational, when given a Complex" do + Rational(3, 4).coerce(Complex(5)).should == [Rational(5, 1), Rational(3, 4)] + Rational(12, 4).coerce(Complex(5, 1)).should == [Complex(5, 1), Complex(3)] + end + it "returns [argument, self] when given a Rational" do Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)] end diff --git a/spec/ruby/shared/string/times.rb b/spec/ruby/shared/string/times.rb index 4dd59884c87..cd4edf5340c 100644 --- a/spec/ruby/shared/string/times.rb +++ b/spec/ruby/shared/string/times.rb @@ -32,10 +32,20 @@ class MyString < String; end @object.call("", max_long).should == "" end - it "returns subclass instances" do - @object.call(MyString.new("cool"), 0).should be_an_instance_of(MyString) - @object.call(MyString.new("cool"), 1).should be_an_instance_of(MyString) - @object.call(MyString.new("cool"), 2).should be_an_instance_of(MyString) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + @object.call(MyString.new("cool"), 0).should be_an_instance_of(MyString) + @object.call(MyString.new("cool"), 1).should be_an_instance_of(MyString) + @object.call(MyString.new("cool"), 2).should be_an_instance_of(MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + @object.call(MyString.new("cool"), 0).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 1).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 2).should be_an_instance_of(String) + end end ruby_version_is ''...'2.7' do diff --git a/spec/tags/ruby/command_line/dash_n_tags.txt b/spec/tags/ruby/command_line/dash_n_tags.txt index 5e8ac5dcf74..a1aea590719 100644 --- a/spec/tags/ruby/command_line/dash_n_tags.txt +++ b/spec/tags/ruby/command_line/dash_n_tags.txt @@ -1,3 +1,2 @@ -fails:The -n command line option only evaluates BEGIN blocks once fails:The -n command line option only evaluates END blocks once fails:The -n command line option allows summing over a whole file diff --git a/spec/tags/ruby/command_line/dash_x_tags.txt b/spec/tags/ruby/command_line/dash_x_tags.txt index fdb23b3d814..747f47abd48 100644 --- a/spec/tags/ruby/command_line/dash_x_tags.txt +++ b/spec/tags/ruby/command_line/dash_x_tags.txt @@ -1,3 +1,2 @@ windows:The -x command line option runs code after the first /#!.*ruby.*/-ish line in target file -fails:The -x command line option runs code after the first /#!.*ruby.*/-ish line in target file fails:The -x command line option behaves as -x was set when non-ruby shebang is encountered on first line diff --git a/spec/tags/ruby/command_line/frozen_strings_tags.txt b/spec/tags/ruby/command_line/frozen_strings_tags.txt index d3ad8546c7b..efb92c18b26 100644 --- a/spec/tags/ruby/command_line/frozen_strings_tags.txt +++ b/spec/tags/ruby/command_line/frozen_strings_tags.txt @@ -1,3 +1,3 @@ -fails:The --enable-frozen-string-literal flag causes string literals to produce the same object for literals with the same content -fails:The --enable-frozen-string-literal flag causes string literals to produce the same object for literals with the same content in different files +travis:The --enable-frozen-string-literal flag causes string literals to produce the same object for literals with the same content +travis:The --enable-frozen-string-literal flag causes string literals to produce the same object for literals with the same content in different files fails:The --debug flag produces debugging info on attempted frozen string modification diff --git a/spec/tags/ruby/core/argf/codepoints_tags.txt b/spec/tags/ruby/core/argf/codepoints_tags.txt index 8237b60b8ae..5bafefaf997 100644 --- a/spec/tags/ruby/core/argf/codepoints_tags.txt +++ b/spec/tags/ruby/core/argf/codepoints_tags.txt @@ -1,7 +1,2 @@ -fails:ARGF.codepoints is a public method -fails:ARGF.codepoints does not require arguments -fails:ARGF.codepoints returns self when passed a block -fails:ARGF.codepoints returns an Enumerator when passed no block +hangs:ARGF.codepoints returns self when passed a block fails:ARGF.codepoints yields each codepoint of all streams -fails:ARGF.codepoints when no block is given returns an Enumerator -fails:ARGF.codepoints when no block is given returned Enumerator size should return nil diff --git a/spec/tags/ruby/core/argf/each_codepoint_tags.txt b/spec/tags/ruby/core/argf/each_codepoint_tags.txt index cd25841a187..628660b3465 100644 --- a/spec/tags/ruby/core/argf/each_codepoint_tags.txt +++ b/spec/tags/ruby/core/argf/each_codepoint_tags.txt @@ -1,7 +1,2 @@ -fails:ARGF.each_codepoint is a public method -fails:ARGF.each_codepoint does not require arguments -fails:ARGF.each_codepoint returns self when passed a block -fails:ARGF.each_codepoint returns an Enumerator when passed no block +hangs:ARGF.each_codepoint returns self when passed a block fails:ARGF.each_codepoint yields each codepoint of all streams -fails:ARGF.each_codepoint when no block is given returns an Enumerator -fails:ARGF.each_codepoint when no block is given returned Enumerator size should return nil diff --git a/spec/tags/ruby/core/argf/read_tags.txt b/spec/tags/ruby/core/argf/read_tags.txt index d097e30c689..516c8296bae 100644 --- a/spec/tags/ruby/core/argf/read_tags.txt +++ b/spec/tags/ruby/core/argf/read_tags.txt @@ -1,3 +1,3 @@ -slow:ARGF.read reads the contents of stdin -slow:ARGF.read reads a number of bytes from stdin -slow:ARGF.read reads the contents of one file and stdin +slow:ARGF.read reads the contents of stdin +slow:ARGF.read reads a number of bytes from stdin +slow:ARGF.read reads the contents of one file and stdin diff --git a/spec/tags/ruby/core/array/pack/buffer_tags.txt b/spec/tags/ruby/core/array/pack/buffer_tags.txt deleted file mode 100644 index c29e175db07..00000000000 --- a/spec/tags/ruby/core/array/pack/buffer_tags.txt +++ /dev/null @@ -1,3 +0,0 @@ -fails:Array#pack with :buffer option offset (@) is specified keeps buffer content if it is longer than offset -fails:Array#pack with :buffer option offset (@) is specified fills the gap with \0 if buffer content is shorter than offset -fails:Array#pack with :buffer option offset (@) is specified does not keep buffer content if it is longer than offset + result diff --git a/spec/tags/ruby/core/array/pack/j_tags.txt b/spec/tags/ruby/core/array/pack/j_tags.txt deleted file mode 100644 index 9a5addc32c1..00000000000 --- a/spec/tags/ruby/core/array/pack/j_tags.txt +++ /dev/null @@ -1,108 +0,0 @@ -fails:Array#pack with format 'J' raises an ArgumentError if there are fewer elements than the format requires -fails:Array#pack with format 'J' raises a TypeError when passed nil -fails:Array#pack with format 'J' raises a TypeError when passed true -fails:Array#pack with format 'J' raises a TypeError when passed false -fails:Array#pack with format 'J' raises a TypeError when the object does not respond to #to_int -fails:Array#pack with format 'J' raises a TypeError when passed a String -fails:Array#pack with format 'j' raises an ArgumentError if there are fewer elements than the format requires -fails:Array#pack with format 'j' raises a TypeError when passed nil -fails:Array#pack with format 'j' raises a TypeError when passed true -fails:Array#pack with format 'j' raises a TypeError when passed false -fails:Array#pack with format 'j' raises a TypeError when the object does not respond to #to_int -fails:Array#pack with format 'j' raises a TypeError when passed a String -fails:Array#pack with format 'J' with modifier '_' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'J' with modifier '_' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'J' with modifier '_' encodes a Float truncated as an Integer -fails:Array#pack with format 'J' with modifier '_' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'J' with modifier '_' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'J' with modifier '_' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'J' with modifier '_' ignores NULL bytes between directives -fails:Array#pack with format 'J' with modifier '_' ignores spaces between directives -fails:Array#pack with format 'J' with modifier '!' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'J' with modifier '!' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'J' with modifier '!' encodes a Float truncated as an Integer -fails:Array#pack with format 'J' with modifier '!' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'J' with modifier '!' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'J' with modifier '!' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'J' with modifier '!' ignores NULL bytes between directives -fails:Array#pack with format 'J' with modifier '!' ignores spaces between directives -fails:Array#pack with format 'j' with modifier '_' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'j' with modifier '_' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'j' with modifier '_' encodes a Float truncated as an Integer -fails:Array#pack with format 'j' with modifier '_' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'j' with modifier '_' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'j' with modifier '_' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'j' with modifier '_' ignores NULL bytes between directives -fails:Array#pack with format 'j' with modifier '_' ignores spaces between directives -fails:Array#pack with format 'j' with modifier '!' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'j' with modifier '!' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'j' with modifier '!' encodes a Float truncated as an Integer -fails:Array#pack with format 'j' with modifier '!' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'j' with modifier '!' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'j' with modifier '!' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'j' with modifier '!' ignores NULL bytes between directives -fails:Array#pack with format 'j' with modifier '!' ignores spaces between directives -fails:Array#pack with format 'J' with modifier '<' and '_' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'J' with modifier '<' and '_' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'J' with modifier '<' and '_' encodes a Float truncated as an Integer -fails:Array#pack with format 'J' with modifier '<' and '_' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'J' with modifier '<' and '_' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'J' with modifier '<' and '_' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'J' with modifier '<' and '_' ignores NULL bytes between directives -fails:Array#pack with format 'J' with modifier '<' and '_' ignores spaces between directives -fails:Array#pack with format 'J' with modifier '<' and '!' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'J' with modifier '<' and '!' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'J' with modifier '<' and '!' encodes a Float truncated as an Integer -fails:Array#pack with format 'J' with modifier '<' and '!' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'J' with modifier '<' and '!' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'J' with modifier '<' and '!' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'J' with modifier '<' and '!' ignores NULL bytes between directives -fails:Array#pack with format 'J' with modifier '<' and '!' ignores spaces between directives -fails:Array#pack with format 'J' with modifier '>' and '_' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'J' with modifier '>' and '_' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'J' with modifier '>' and '_' encodes a Float truncated as an Integer -fails:Array#pack with format 'J' with modifier '>' and '_' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'J' with modifier '>' and '_' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'J' with modifier '>' and '_' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'J' with modifier '>' and '_' ignores NULL bytes between directives -fails:Array#pack with format 'J' with modifier '>' and '_' ignores spaces between directives -fails:Array#pack with format 'J' with modifier '>' and '!' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'J' with modifier '>' and '!' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'J' with modifier '>' and '!' encodes a Float truncated as an Integer -fails:Array#pack with format 'J' with modifier '>' and '!' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'J' with modifier '>' and '!' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'J' with modifier '>' and '!' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'J' with modifier '>' and '!' ignores NULL bytes between directives -fails:Array#pack with format 'J' with modifier '>' and '!' ignores spaces between directives -fails:Array#pack with format 'j' with modifier '<' and '_' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'j' with modifier '<' and '_' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'j' with modifier '<' and '_' encodes a Float truncated as an Integer -fails:Array#pack with format 'j' with modifier '<' and '_' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'j' with modifier '<' and '_' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'j' with modifier '<' and '_' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'j' with modifier '<' and '_' ignores NULL bytes between directives -fails:Array#pack with format 'j' with modifier '<' and '_' ignores spaces between directives -fails:Array#pack with format 'j' with modifier '<' and '!' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'j' with modifier '<' and '!' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'j' with modifier '<' and '!' encodes a Float truncated as an Integer -fails:Array#pack with format 'j' with modifier '<' and '!' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'j' with modifier '<' and '!' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'j' with modifier '<' and '!' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'j' with modifier '<' and '!' ignores NULL bytes between directives -fails:Array#pack with format 'j' with modifier '<' and '!' ignores spaces between directives -fails:Array#pack with format 'j' with modifier '>' and '_' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'j' with modifier '>' and '_' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'j' with modifier '>' and '_' encodes a Float truncated as an Integer -fails:Array#pack with format 'j' with modifier '>' and '_' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'j' with modifier '>' and '_' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'j' with modifier '>' and '_' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'j' with modifier '>' and '_' ignores NULL bytes between directives -fails:Array#pack with format 'j' with modifier '>' and '_' ignores spaces between directives -fails:Array#pack with format 'j' with modifier '>' and '!' encodes the least significant 64 bits of a positive number -fails:Array#pack with format 'j' with modifier '>' and '!' encodes the least significant 64 bits of a negative number -fails:Array#pack with format 'j' with modifier '>' and '!' encodes a Float truncated as an Integer -fails:Array#pack with format 'j' with modifier '>' and '!' calls #to_int to convert the pack argument to an Integer -fails:Array#pack with format 'j' with modifier '>' and '!' encodes the number of array elements specified by the count modifier -fails:Array#pack with format 'j' with modifier '>' and '!' encodes all remaining elements when passed the '*' modifier -fails:Array#pack with format 'j' with modifier '>' and '!' ignores NULL bytes between directives -fails:Array#pack with format 'j' with modifier '>' and '!' ignores spaces between directives diff --git a/spec/tags/ruby/core/array/pack/p_tags.txt b/spec/tags/ruby/core/array/pack/p_tags.txt index c625b48a55a..1ef6f5da4ec 100644 --- a/spec/tags/ruby/core/array/pack/p_tags.txt +++ b/spec/tags/ruby/core/array/pack/p_tags.txt @@ -8,3 +8,5 @@ fails:Array#pack with format 'p' returns a untrusted string when a pack argument fails:Array#pack with format 'p' round-trips a string through pack and unpack fails:Array#pack with format 'p' taints the input string fails:Array#pack with format 'p' with nil gives a null pointer +fails:Array#pack with format 'P' produces as many bytes as there are in a pointer +fails:Array#pack with format 'p' produces as many bytes as there are in a pointer diff --git a/spec/tags/ruby/core/array/reverse_tags.txt b/spec/tags/ruby/core/array/reverse_tags.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/tags/ruby/core/array/values_at_tags.txt b/spec/tags/ruby/core/array/values_at_tags.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/tags/ruby/core/basicobject/instance_eval_tags.txt b/spec/tags/ruby/core/basicobject/instance_eval_tags.txt deleted file mode 100644 index 7e817e0228b..00000000000 --- a/spec/tags/ruby/core/basicobject/instance_eval_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:BasicObject#instance_eval evaluates string with given filename and negative linenumber diff --git a/spec/tags/ruby/core/binding/local_variable_defined_tags.txt b/spec/tags/ruby/core/binding/local_variable_defined_tags.txt deleted file mode 100644 index 1ca0d08060a..00000000000 --- a/spec/tags/ruby/core/binding/local_variable_defined_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:Binding#local_variable_defined? allows usage of a String as the variable name -fails:Binding#local_variable_defined? allows usage of an object responding to #to_str as the variable name diff --git a/spec/tags/ruby/core/comparable/equal_value_tags.txt b/spec/tags/ruby/core/comparable/equal_value_tags.txt deleted file mode 100644 index 5d40414213d..00000000000 --- a/spec/tags/ruby/core/comparable/equal_value_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Comparable#== when #<=> calls super calls the defined #<=> only once for different objects diff --git a/spec/tags/ruby/core/dir/glob_tags.txt b/spec/tags/ruby/core/dir/glob_tags.txt index 1a7a5af75ee..fb50d9d9dcc 100644 --- a/spec/tags/ruby/core/dir/glob_tags.txt +++ b/spec/tags/ruby/core/dir/glob_tags.txt @@ -1,3 +1,4 @@ -fails(JRUBY-5667):Dir.glob splits the string on \0 if there is only one string given -fails:Dir.glob raises an Encoding::CompatibilityError if the argument encoding is not compatible with US-ASCII -fails:Dir.glob splits the string on \0 if there is only one string given and warns +fails(JRUBY-5667):Dir.glob splits the string on \0 if there is only one string given +fails:Dir.glob raises an Encoding::CompatibilityError if the argument encoding is not compatible with US-ASCII +fails:Dir.glob splits the string on \0 if there is only one string given and warns +fails:Dir.glob recursively matches files and directories in nested dot subdirectory with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH diff --git a/spec/tags/ruby/core/enumerable/collect_tags.txt b/spec/tags/ruby/core/enumerable/collect_tags.txt deleted file mode 100644 index ac6848dbfcf..00000000000 --- a/spec/tags/ruby/core/enumerable/collect_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Enumerable#collect yields 2 arguments for a Hash diff --git a/spec/tags/ruby/core/enumerable/map_tags.txt b/spec/tags/ruby/core/enumerable/map_tags.txt deleted file mode 100644 index e06fd3789b7..00000000000 --- a/spec/tags/ruby/core/enumerable/map_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Enumerable#map yields 2 arguments for a Hash diff --git a/spec/tags/ruby/core/env/fetch_tags.txt b/spec/tags/ruby/core/env/fetch_tags.txt deleted file mode 100644 index 92faaaae24e..00000000000 --- a/spec/tags/ruby/core/env/fetch_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.fetch raises a TypeError if the key is not a String diff --git a/spec/tags/ruby/core/exception/interrupt_tags.txt b/spec/tags/ruby/core/exception/interrupt_tags.txt index fa81ff0e9ad..616598b7dc7 100644 --- a/spec/tags/ruby/core/exception/interrupt_tags.txt +++ b/spec/tags/ruby/core/exception/interrupt_tags.txt @@ -1 +1 @@ -fails:rescuing Interrupt raises an Interrupt when sent a signal SIGINT +critical(terminates):rescuing Interrupt raises an Interrupt when sent a signal SIGINT diff --git a/spec/tags/ruby/core/file/atime_tags.txt b/spec/tags/ruby/core/file/atime_tags.txt index 347112c7097..fece2d8f4a9 100644 --- a/spec/tags/ruby/core/file/atime_tags.txt +++ b/spec/tags/ruby/core/file/atime_tags.txt @@ -1 +1 @@ -windows:File.atime returns the last access time for the named file with microseconds +windows:File.atime returns the last access time for the named file with microseconds diff --git a/spec/tags/ruby/core/file/ctime_tags.txt b/spec/tags/ruby/core/file/ctime_tags.txt index 2bda6029aff..60f3082e95b 100644 --- a/spec/tags/ruby/core/file/ctime_tags.txt +++ b/spec/tags/ruby/core/file/ctime_tags.txt @@ -1 +1 @@ -windows:File.ctime returns the change time for the named file (the time at which directory information about the file was changed, not the file itself) with microseconds. +windows:File.ctime returns the change time for the named file (the time at which directory information about the file was changed, not the file itself) with microseconds. diff --git a/spec/tags/ruby/core/file/expand_path_tags.txt b/spec/tags/ruby/core/file/expand_path_tags.txt index 4d9b4bdf777..dc68e78b9e2 100644 --- a/spec/tags/ruby/core/file/expand_path_tags.txt +++ b/spec/tags/ruby/core/file/expand_path_tags.txt @@ -1,5 +1,5 @@ -fails:File.expand_path raises an Encoding::CompatibilityError if the external encoding is not compatible -windows:File.expand_path does not modify a HOME string argument -fails:File.expand_path when HOME is not set uses the user database when passed '~' if HOME is nil -fails:File.expand_path when HOME is not set uses the user database when passed '~/' if HOME is nil -fails:File.expand_path expands a path when the default external encoding is BINARY +fails:File.expand_path raises an Encoding::CompatibilityError if the external encoding is not compatible +windows:File.expand_path does not modify a HOME string argument +fails:File.expand_path when HOME is not set uses the user database when passed '~' if HOME is nil +fails:File.expand_path when HOME is not set uses the user database when passed '~/' if HOME is nil +fails:File.expand_path expands a path when the default external encoding is BINARY diff --git a/spec/tags/ruby/core/file/grpowned_tags.txt b/spec/tags/ruby/core/file/grpowned_tags.txt index 9b88ca7ee1e..81dd8c992bf 100644 --- a/spec/tags/ruby/core/file/grpowned_tags.txt +++ b/spec/tags/ruby/core/file/grpowned_tags.txt @@ -1 +1 @@ -fails:File.grpowned? takes non primary groups into account +fails:File.grpowned? takes non primary groups into account diff --git a/spec/tags/ruby/core/file/identical_tags.txt b/spec/tags/ruby/core/file/identical_tags.txt index 8ccdf9675f1..fdeae37be90 100644 --- a/spec/tags/ruby/core/file/identical_tags.txt +++ b/spec/tags/ruby/core/file/identical_tags.txt @@ -1,2 +1,2 @@ -windows:File.identical? returns true for a file and its link -windows:File.identical? accepts an object that has a #to_path method +windows:File.identical? returns true for a file and its link +windows:File.identical? accepts an object that has a #to_path method diff --git a/spec/tags/ruby/core/file/mtime_tags.txt b/spec/tags/ruby/core/file/mtime_tags.txt index 8408689c446..436b7df2594 100644 --- a/spec/tags/ruby/core/file/mtime_tags.txt +++ b/spec/tags/ruby/core/file/mtime_tags.txt @@ -1 +1 @@ -windows:File.mtime returns the modification Time of the file with microseconds +windows:File.mtime returns the modification Time of the file with microseconds diff --git a/spec/tags/ruby/core/file/new_tags.txt b/spec/tags/ruby/core/file/new_tags.txt index 8cb9a2f4351..03ce0353563 100644 --- a/spec/tags/ruby/core/file/new_tags.txt +++ b/spec/tags/ruby/core/file/new_tags.txt @@ -1,2 +1,2 @@ -windows:File.new can't alter mode or permissions when opening a file -windows:File.new opens directories +windows:File.new can't alter mode or permissions when opening a file +windows:File.new opens directories diff --git a/spec/tags/ruby/core/file/open_tags.txt b/spec/tags/ruby/core/file/open_tags.txt index d3f60ee44f2..4f3eae1a2c0 100644 --- a/spec/tags/ruby/core/file/open_tags.txt +++ b/spec/tags/ruby/core/file/open_tags.txt @@ -1 +1 @@ -windows:File.open opens directories +windows:File.open opens directories diff --git a/spec/tags/ruby/core/file/printf_tags.txt b/spec/tags/ruby/core/file/printf_tags.txt index 180ab5a2eaf..868ea39e931 100644 --- a/spec/tags/ruby/core/file/printf_tags.txt +++ b/spec/tags/ruby/core/file/printf_tags.txt @@ -1,6 +1,4 @@ fails:File#printf integer formats u converts argument as a decimal number -fails:File#printf float formats g otherwise cuts fraction part to have only 6 digits at all -fails:File#printf float formats G otherwise cuts fraction part to have only 6 digits at all fails:File#printf float formats a converts floating point argument as [-]0xh.hhhhp[+-]dd fails:File#printf float formats a displays Float::INFINITY as Inf fails:File#printf float formats a displays Float::NAN as NaN diff --git a/spec/tags/ruby/core/file/stat/grpowned_tags.txt b/spec/tags/ruby/core/file/stat/grpowned_tags.txt index 9429fd2d53d..49a69ad666c 100644 --- a/spec/tags/ruby/core/file/stat/grpowned_tags.txt +++ b/spec/tags/ruby/core/file/stat/grpowned_tags.txt @@ -1 +1 @@ -fails:File::Stat#grpowned? takes non primary groups into account +fails:File::Stat#grpowned? takes non primary groups into account diff --git a/spec/tags/ruby/core/file/stat_tags.txt b/spec/tags/ruby/core/file/stat_tags.txt index 290b251ba60..91135ac4917 100644 --- a/spec/tags/ruby/core/file/stat_tags.txt +++ b/spec/tags/ruby/core/file/stat_tags.txt @@ -1,2 +1,2 @@ -windows:File.stat returns information for a file that has been deleted but is still open -fails:File.stat returns an error when given missing non-ASCII path +windows:File.stat returns information for a file that has been deleted but is still open +fails:File.stat returns an error when given missing non-ASCII path diff --git a/spec/tags/ruby/core/file/utime_tags.txt b/spec/tags/ruby/core/file/utime_tags.txt index 9505f185b7a..b9bce9c92e4 100644 --- a/spec/tags/ruby/core/file/utime_tags.txt +++ b/spec/tags/ruby/core/file/utime_tags.txt @@ -1,2 +1,3 @@ fails(linux):File.utime allows Time instances in the far future to set mtime and atime fails:File.utime allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10) +fails:File.utime allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19) diff --git a/spec/tags/ruby/core/filetest/grpowned_tags.txt b/spec/tags/ruby/core/filetest/grpowned_tags.txt index 3d84c6d8967..785e385386c 100644 --- a/spec/tags/ruby/core/filetest/grpowned_tags.txt +++ b/spec/tags/ruby/core/filetest/grpowned_tags.txt @@ -1 +1 @@ -fails:FileTest.grpowned? takes non primary groups into account +fails:FileTest.grpowned? takes non primary groups into account diff --git a/spec/tags/ruby/core/filetest/identical_tags.txt b/spec/tags/ruby/core/filetest/identical_tags.txt index a34b9e6c438..97c4e22157e 100644 --- a/spec/tags/ruby/core/filetest/identical_tags.txt +++ b/spec/tags/ruby/core/filetest/identical_tags.txt @@ -1,2 +1,2 @@ -windows:FileTest.identical? returns true for a file and its link -windows:FileTest.identical? accepts an object that has a #to_path method +windows:FileTest.identical? returns true for a file and its link +windows:FileTest.identical? accepts an object that has a #to_path method diff --git a/spec/tags/ruby/core/hash/each_pair_tags.txt b/spec/tags/ruby/core/hash/each_pair_tags.txt deleted file mode 100644 index e18866bd526..00000000000 --- a/spec/tags/ruby/core/hash/each_pair_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Hash#each_pair yields 2 values and not an Array of 2 elements when given a callable of arity 2 diff --git a/spec/tags/ruby/core/hash/each_tags.txt b/spec/tags/ruby/core/hash/each_tags.txt deleted file mode 100644 index 9c091fc35db..00000000000 --- a/spec/tags/ruby/core/hash/each_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Hash#each yields 2 values and not an Array of 2 elements when given a callable of arity 2 diff --git a/spec/tags/ruby/core/hash/hash_tags.txt b/spec/tags/ruby/core/hash/hash_tags.txt index 0a2a6ebcc6a..016e29ab2ee 100644 --- a/spec/tags/ruby/core/hash/hash_tags.txt +++ b/spec/tags/ruby/core/hash/hash_tags.txt @@ -1,2 +1 @@ -fails:Hash#hash returns a value in which element values do not cancel each other out fails:Hash#hash returns a value in which element keys and values do not cancel each other out diff --git a/spec/tags/ruby/core/io/close_tags.txt b/spec/tags/ruby/core/io/close_tags.txt index 8a71a9dd168..7dc9599526a 100644 --- a/spec/tags/ruby/core/io/close_tags.txt +++ b/spec/tags/ruby/core/io/close_tags.txt @@ -1,2 +1 @@ -unstable(JRUBY-4110,linux,intermittent failure):IO#close on an IO.popen stream sets $? -fails(spurious):IO#close raises an IOError with a clear message +unstable(JRUBY-4110,linux,intermittent failure):IO#close on an IO.popen stream sets $? diff --git a/spec/tags/ruby/core/io/copy_stream_tags.txt b/spec/tags/ruby/core/io/copy_stream_tags.txt index e566adc3a0d..24b3c1e87bf 100644 --- a/spec/tags/ruby/core/io/copy_stream_tags.txt +++ b/spec/tags/ruby/core/io/copy_stream_tags.txt @@ -1,8 +1,8 @@ -fails:IO.copy_stream from a pipe IO raises an error when an offset is specified -fails:IO.copy_stream with non-IO Objects calls #readpartial on the source Object if defined -windows:IO.copy_stream from an IO to a file name copies only length bytes from the offset -windows:IO.copy_stream from an IO to an IO copies only length bytes from the offset -windows:IO.copy_stream from a file name to a file name copies only length bytes from the offset -windows:IO.copy_stream from a file name to an IO copies only length bytes from the offset -windows:IO.copy_stream with non-IO Objects calls #read on the source Object -fails:IO.copy_stream with non-IO Objects calls #read on the source Object +fails:IO.copy_stream from a pipe IO raises an error when an offset is specified +fails:IO.copy_stream with non-IO Objects calls #readpartial on the source Object if defined +windows:IO.copy_stream from an IO to a file name copies only length bytes from the offset +windows:IO.copy_stream from an IO to an IO copies only length bytes from the offset +windows:IO.copy_stream from a file name to a file name copies only length bytes from the offset +windows:IO.copy_stream from a file name to an IO copies only length bytes from the offset +windows:IO.copy_stream with non-IO Objects calls #read on the source Object +fails:IO.copy_stream with non-IO Objects calls #read on the source Object diff --git a/spec/tags/ruby/core/io/each_line_tags.txt b/spec/tags/ruby/core/io/each_line_tags.txt index 932b480c89a..e3d7765959b 100644 --- a/spec/tags/ruby/core/io/each_line_tags.txt +++ b/spec/tags/ruby/core/io/each_line_tags.txt @@ -1,2 +1,2 @@ -fails:IO#each_line with limit when limit is 0 raises an ArgumentError -fails:IO#each_line with both separator and limit when no block is given returns an Enumerator +hangs:IO#each_line with limit when limit is 0 raises an ArgumentError +fails:IO#each_line with both separator and limit when no block is given returns an Enumerator diff --git a/spec/tags/ruby/core/io/each_tags.txt b/spec/tags/ruby/core/io/each_tags.txt index a28782717cd..faf64c970b5 100644 --- a/spec/tags/ruby/core/io/each_tags.txt +++ b/spec/tags/ruby/core/io/each_tags.txt @@ -1,2 +1,2 @@ -critical:IO#each with limit when limit is 0 raises an ArgumentError -fails:IO#each with both separator and limit when no block is given returns an Enumerator +critical:IO#each with limit when limit is 0 raises an ArgumentError +fails:IO#each with both separator and limit when no block is given returns an Enumerator diff --git a/spec/tags/ruby/core/io/for_fd_tags.txt b/spec/tags/ruby/core/io/for_fd_tags.txt index 5e60307048d..7cd53401c7d 100644 --- a/spec/tags/ruby/core/io/for_fd_tags.txt +++ b/spec/tags/ruby/core/io/for_fd_tags.txt @@ -1,5 +1,5 @@ -fails:IO.for_fd raises an error if passed matching binary/text mode two ways -fails:IO.for_fd raises an error if passed conflicting binary/text mode two ways -windows:IO.for_fd raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode -fails:IO.for_fd ignores the :encoding option when the :external_encoding option is present -fails:IO.for_fd ignores the :encoding option when the :internal_encoding option is present +fails:IO.for_fd raises an error if passed matching binary/text mode two ways +fails:IO.for_fd raises an error if passed conflicting binary/text mode two ways +windows:IO.for_fd raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode +fails:IO.for_fd ignores the :encoding option when the :external_encoding option is present +fails:IO.for_fd ignores the :encoding option when the :internal_encoding option is present diff --git a/spec/tags/ruby/core/io/gets_tags.txt b/spec/tags/ruby/core/io/gets_tags.txt index 19b273400ea..295f65fe6c6 100644 --- a/spec/tags/ruby/core/io/gets_tags.txt +++ b/spec/tags/ruby/core/io/gets_tags.txt @@ -1,2 +1,2 @@ -windows:IO#gets ignores the internal encoding if the default external encoding is ASCII-8BIT -windows:IO#gets transcodes to internal encoding if the IO object's external encoding is ASCII-8BIT +windows:IO#gets ignores the internal encoding if the default external encoding is ASCII-8BIT +windows:IO#gets transcodes to internal encoding if the IO object's external encoding is ASCII-8BIT diff --git a/spec/tags/ruby/core/io/new_tags.txt b/spec/tags/ruby/core/io/new_tags.txt index 51782b971e1..dff327e6787 100644 --- a/spec/tags/ruby/core/io/new_tags.txt +++ b/spec/tags/ruby/core/io/new_tags.txt @@ -1,6 +1,6 @@ -fails:IO.new raises an error if passed matching binary/text mode two ways -fails:IO.new raises an error if passed conflicting binary/text mode two ways -windows:IO.new ingores the :encoding option when the :internal_encoding option is present -windows:IO.new raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode -fails:IO.new ignores the :encoding option when the :external_encoding option is present -fails:IO.new ignores the :encoding option when the :internal_encoding option is present +fails:IO.new raises an error if passed matching binary/text mode two ways +fails:IO.new raises an error if passed conflicting binary/text mode two ways +windows:IO.new ingores the :encoding option when the :internal_encoding option is present +windows:IO.new raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode +fails:IO.new ignores the :encoding option when the :external_encoding option is present +fails:IO.new ignores the :encoding option when the :internal_encoding option is present diff --git a/spec/tags/ruby/core/io/open_tags.txt b/spec/tags/ruby/core/io/open_tags.txt index b7575442da4..87de9a0418e 100644 --- a/spec/tags/ruby/core/io/open_tags.txt +++ b/spec/tags/ruby/core/io/open_tags.txt @@ -1,6 +1,6 @@ -fails:IO.open raises an error if passed matching binary/text mode two ways -fails:IO.open raises an error if passed conflicting binary/text mode two ways -windows:IO.open ingores the :encoding option when the :internal_encoding option is present -windows:IO.open raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode -fails:IO.open ignores the :encoding option when the :external_encoding option is present -fails:IO.open ignores the :encoding option when the :internal_encoding option is present +fails:IO.open raises an error if passed matching binary/text mode two ways +fails:IO.open raises an error if passed conflicting binary/text mode two ways +windows:IO.open ingores the :encoding option when the :internal_encoding option is present +windows:IO.open raises an Errno::EINVAL if the new mode is not compatible with the descriptor's current mode +fails:IO.open ignores the :encoding option when the :external_encoding option is present +fails:IO.open ignores the :encoding option when the :internal_encoding option is present diff --git a/spec/tags/ruby/core/io/popen_tags.txt b/spec/tags/ruby/core/io/popen_tags.txt index 0384903e835..64cae501b4d 100644 --- a/spec/tags/ruby/core/io/popen_tags.txt +++ b/spec/tags/ruby/core/io/popen_tags.txt @@ -1,18 +1,18 @@ -unstable(JRUBY-4171,linux,intermittent failure):IO.popen writes to a write-only pipe -fails:IO.popen starts returns a forked process if the command is - -fails:IO.popen with a leading Array argument accepts a trailing Hash of Process.exec options -fails:IO.popen with a leading Array argument accepts an IO mode argument following the Array -fails:IO.popen with a leading ENV Hash accepts a single String command with a trailing Hash of Process.exec options, and an IO mode -fails:IO.popen with a leading ENV Hash accepts an Array command with a separate trailing Hash of Process.exec options, and an IO mode -windows:IO.popen reads a read-only pipe -windows:IO.popen with a block returns the value of the block -windows:IO.popen with a leading ENV Hash accepts a single String command -windows:IO.popen with a leading ENV Hash accepts a single String command, and an IO mode -windows:IO.popen with a leading ENV Hash accepts a single String command with a trailing Hash of Process.exec options -windows:IO.popen with a leading ENV Hash accepts an Array of command and arguments -windows:IO.popen with a leading ENV Hash accepts an Array of command and arguments, and an IO mode -windows:IO.popen with a leading ENV Hash accepts an Array command with a separate trailing Hash of Process.exec options -windows:IO.popen with a leading Array argument accepts [env, command, arg1, arg2, ..., exec options] -windows:IO.popen with a leading Array argument accepts '[env, command, arg1, arg2, ..., exec options], mode' -windows:IO.popen with a leading Array argument accepts '[env, command, arg1, arg2, ..., exec options], mode, IO options' -windows:IO.popen with a leading Array argument accepts '[env, command, arg1, arg2, ...], mode, IO + exec options' +unstable(JRUBY-4171,linux,intermittent failure):IO.popen writes to a write-only pipe +fails:IO.popen starts returns a forked process if the command is - +fails:IO.popen with a leading Array argument accepts a trailing Hash of Process.exec options +fails:IO.popen with a leading Array argument accepts an IO mode argument following the Array +fails:IO.popen with a leading ENV Hash accepts a single String command with a trailing Hash of Process.exec options, and an IO mode +fails:IO.popen with a leading ENV Hash accepts an Array command with a separate trailing Hash of Process.exec options, and an IO mode +windows:IO.popen reads a read-only pipe +windows:IO.popen with a block returns the value of the block +windows:IO.popen with a leading ENV Hash accepts a single String command +windows:IO.popen with a leading ENV Hash accepts a single String command, and an IO mode +windows:IO.popen with a leading ENV Hash accepts a single String command with a trailing Hash of Process.exec options +windows:IO.popen with a leading ENV Hash accepts an Array of command and arguments +windows:IO.popen with a leading ENV Hash accepts an Array of command and arguments, and an IO mode +windows:IO.popen with a leading ENV Hash accepts an Array command with a separate trailing Hash of Process.exec options +windows:IO.popen with a leading Array argument accepts [env, command, arg1, arg2, ..., exec options] +windows:IO.popen with a leading Array argument accepts '[env, command, arg1, arg2, ..., exec options], mode' +windows:IO.popen with a leading Array argument accepts '[env, command, arg1, arg2, ..., exec options], mode, IO options' +windows:IO.popen with a leading Array argument accepts '[env, command, arg1, arg2, ...], mode, IO + exec options' diff --git a/spec/tags/ruby/core/io/read_tags.txt b/spec/tags/ruby/core/io/read_tags.txt index 7ddbbead90c..7dccd01a3b7 100644 --- a/spec/tags/ruby/core/io/read_tags.txt +++ b/spec/tags/ruby/core/io/read_tags.txt @@ -1,7 +1,7 @@ -fails:IO.read from a pipe opens a pipe to a fork if the rest is - -windows:IO.read from a pipe runs the rest as a subprocess and returns the standard output -windows:IO.read from a pipe reads only the specified number of bytes requested -windows:IO#read expands the buffer when too small -windows:IO#read overwrites the buffer -windows:IO#read truncates the buffer when too big -windows:IO#read on Windows normalizes line endings in text mode +fails:IO.read from a pipe opens a pipe to a fork if the rest is - +windows:IO.read from a pipe runs the rest as a subprocess and returns the standard output +windows:IO.read from a pipe reads only the specified number of bytes requested +windows:IO#read expands the buffer when too small +windows:IO#read overwrites the buffer +windows:IO#read truncates the buffer when too big +windows:IO#read on Windows normalizes line endings in text mode diff --git a/spec/tags/ruby/core/io/reopen_tags.txt b/spec/tags/ruby/core/io/reopen_tags.txt index 881e950b06d..cb8a418bf0c 100644 --- a/spec/tags/ruby/core/io/reopen_tags.txt +++ b/spec/tags/ruby/core/io/reopen_tags.txt @@ -1,6 +1,3 @@ -fails:IO#reopen with an IO sets path equals to the other IO's path if other IO is File -fails:IO#reopen changes the class of the instance to the class of the object returned by #to_io -fails:IO#reopen with an IO may change the class of the instance fails:IO#reopen with a String closes the file descriptor obtained by opening the new file windows:IO#reopen calls #to_io to convert an object windows:IO#reopen with a String calls #to_path on non-String arguments diff --git a/spec/tags/ruby/core/kernel/__dir___tags.txt b/spec/tags/ruby/core/kernel/__dir___tags.txt index 09cbb057915..e27c6507e28 100644 --- a/spec/tags/ruby/core/kernel/__dir___tags.txt +++ b/spec/tags/ruby/core/kernel/__dir___tags.txt @@ -1 +1 @@ -fails:Kernel#__dir__ when used in eval with a given filename returns File.dirname(filename) +fails:Kernel#__dir__ when used in eval with a given filename returns File.dirname(filename) diff --git a/spec/tags/ruby/core/kernel/autoload_tags.txt b/spec/tags/ruby/core/kernel/autoload_tags.txt deleted file mode 100644 index d24fc107d20..00000000000 --- a/spec/tags/ruby/core/kernel/autoload_tags.txt +++ /dev/null @@ -1,10 +0,0 @@ -fails:Kernel.autoload sets the autoload constant in Object's constant table -fails:Kernel#autoload registers a file to load the first time the named constant is accessed -fails:Kernel#autoload? returns the name of the file that will be autoloaded -fails:Kernel#autoload when called from included module's method setups the autoload on the included module -fails:Kernel#autoload when called from included module's method the autoload relative to the included module works -fails:Kernel.autoload when called from included module's method setups the autoload on the included module -fails:Kernel.autoload when called from included module's method the autoload is reacheable from the class too -fails:Kernel.autoload when called from included module's method the autoload relative to the included module works -fails:Kernel#autoload calls main.require(path) to load the file -fails:Kernel.autoload when called from included module's method the autoload is reachable from the class too diff --git a/spec/tags/ruby/core/kernel/backtick_tags.txt b/spec/tags/ruby/core/kernel/backtick_tags.txt index 9b9f51bde68..ef8b5225589 100644 --- a/spec/tags/ruby/core/kernel/backtick_tags.txt +++ b/spec/tags/ruby/core/kernel/backtick_tags.txt @@ -1 +1,2 @@ -fails(on Linux, Travis, likely posix_spawn error-after-fork problem):Kernel#` raises an Errno::ENOENT if the command is not executable +critical(on Linux, Travis, likely posix_spawn error-after-fork problem):Kernel#` raises an Errno::ENOENT if the command is not executable +fails:Kernel#` handles invalid UTF-8 bytes in command diff --git a/spec/tags/ruby/core/kernel/fork_tags.txt b/spec/tags/ruby/core/kernel/fork_tags.txt index 0b590309be5..716e9bc10fb 100644 --- a/spec/tags/ruby/core/kernel/fork_tags.txt +++ b/spec/tags/ruby/core/kernel/fork_tags.txt @@ -1,10 +1,10 @@ -fails:Kernel#fork returns status zero -fails:Kernel#fork returns status non-zero -fails:Kernel#fork returns nil for the child process -fails:Kernel#fork runs a block in a child process -fails:Kernel#fork marks threads from the parent as killed -fails:Kernel.fork returns status zero -fails:Kernel.fork returns status non-zero -fails:Kernel.fork returns nil for the child process -fails:Kernel.fork runs a block in a child process -fails:Kernel.fork marks threads from the parent as killed +fails:Kernel#fork returns status zero +fails:Kernel#fork returns status non-zero +fails:Kernel#fork returns nil for the child process +fails:Kernel#fork runs a block in a child process +fails:Kernel#fork marks threads from the parent as killed +fails:Kernel.fork returns status zero +fails:Kernel.fork returns status non-zero +fails:Kernel.fork returns nil for the child process +fails:Kernel.fork runs a block in a child process +fails:Kernel.fork marks threads from the parent as killed diff --git a/spec/tags/ruby/core/kernel/printf_tags.txt b/spec/tags/ruby/core/kernel/printf_tags.txt index 0e06e063dc3..f7813ea8ba0 100644 --- a/spec/tags/ruby/core/kernel/printf_tags.txt +++ b/spec/tags/ruby/core/kernel/printf_tags.txt @@ -1,6 +1,4 @@ fails:Kernel.printf formatting io is specified integer formats u converts argument as a decimal number -fails:Kernel.printf formatting io is specified float formats g otherwise cuts fraction part to have only 6 digits at all -fails:Kernel.printf formatting io is specified float formats G otherwise cuts fraction part to have only 6 digits at all fails:Kernel.printf formatting io is specified float formats a converts floating point argument as [-]0xh.hhhhp[+-]dd fails:Kernel.printf formatting io is specified float formats a displays Float::INFINITY as Inf fails:Kernel.printf formatting io is specified float formats a displays Float::NAN as NaN @@ -26,8 +24,6 @@ fails:Kernel.printf formatting io is specified width specifies the minimum numbe fails:Kernel.printf formatting io is specified precision float types controls the number of decimal places displayed in fraction part fails:Kernel.printf formatting io is specified reference by name %{name} style supports flags, width and precision fails:Kernel.printf formatting io is not specified integer formats u converts argument as a decimal number -fails:Kernel.printf formatting io is not specified float formats g otherwise cuts fraction part to have only 6 digits at all -fails:Kernel.printf formatting io is not specified float formats G otherwise cuts fraction part to have only 6 digits at all fails:Kernel.printf formatting io is not specified float formats a converts floating point argument as [-]0xh.hhhhp[+-]dd fails:Kernel.printf formatting io is not specified float formats a displays Float::INFINITY as Inf fails:Kernel.printf formatting io is not specified float formats a displays Float::NAN as NaN diff --git a/spec/tags/ruby/core/kernel/require_relative_tags.txt b/spec/tags/ruby/core/kernel/require_relative_tags.txt index e24cf159276..cc108d39da3 100644 --- a/spec/tags/ruby/core/kernel/require_relative_tags.txt +++ b/spec/tags/ruby/core/kernel/require_relative_tags.txt @@ -1,7 +1,4 @@ -fails:Kernel#require_relative with a relative path stores the missing path in a LoadError object -fails:Kernel#require_relative with an absolute path stores the missing path in a LoadError object fails:Kernel#require_relative with a relative path in an #instance_eval with a synthetic file base name loads a file base name relative to the working directory fails:Kernel#require_relative with a relative path in an #instance_eval with a synthetic file path loads a relative path relative to the working directory plus the directory of the synthetic path fails:Kernel#require_relative with a relative path in an #instance_eval with a synthetic relative file path with a Windows path separator specified loads a relative path relative to the working directory fails:Kernel#require_relative with a relative path ($LOADED_FEATURES) with symlinks does not canonicalize the path and stores a path with symlinks -fails:Kernel#require_relative with a relative path raises a LoadError that includes the missing path diff --git a/spec/tags/ruby/core/kernel/require_tags.txt b/spec/tags/ruby/core/kernel/require_tags.txt index 2bf6cbd323b..d4d5af1097e 100644 --- a/spec/tags/ruby/core/kernel/require_tags.txt +++ b/spec/tags/ruby/core/kernel/require_tags.txt @@ -1,15 +1,3 @@ -fails(JRUBY-5668):Kernel#require ($LOADED_FEATURES) when a non-extensioned file is in $LOADED_FEATURES loads a .rb extensioned file when a non extensioned file is in $LOADED_FEATURES -fails(JRUBY-5668):Kernel.require ($LOADED_FEATURES) when a non-extensioned file is in $LOADED_FEATURES loads a .rb extensioned file when a non extensioned file is in $LOADED_FEATURES -fails:Kernel#require (concurrently) blocks a second thread from returning while the 1st is still requiring -fails:Kernel#require (concurrently) blocks based on the path -fails:Kernel#require (concurrently) allows a 2nd require if the 1st raised an exception -fails:Kernel#require (concurrently) blocks a 3rd require if the 1st raises an exception and the 2nd is still running -fails:Kernel#require (path resolution) does not load a relative path unless the current working directory is in $LOAD_PATH -fails:Kernel#require (path resolution) does not load a bare filename unless the current working directory is in $LOAD_PATH -fails:Kernel.require (path resolution) does not load a bare filename unless the current working directory is in $LOAD_PATH -fails:Kernel.require (path resolution) does not load a relative path unless the current working directory is in $LOAD_PATH -fails:Kernel.require (concurrently) allows a 2nd require if the 1st raised an exception -fails:Kernel.require (concurrently) blocks a second thread from returning while the 1st is still requiring fails:Kernel#require ($LOADED_FEATURES) complex, enumerator, rational, thread and unicode_normalize are already required fails:Kernel.require ($LOADED_FEATURES) complex, enumerator, rational, thread and unicode_normalize are already required fails:Kernel#require ($LOADED_FEATURES) with symlinks does not canonicalize the path and stores a path with symlinks diff --git a/spec/tags/ruby/core/kernel/respond_to_tags.txt b/spec/tags/ruby/core/kernel/respond_to_tags.txt new file mode 100644 index 00000000000..1886cfa2097 --- /dev/null +++ b/spec/tags/ruby/core/kernel/respond_to_tags.txt @@ -0,0 +1 @@ +fails:Kernel#respond_to? throws a type error if argument can't be coerced into a Symbol diff --git a/spec/tags/ruby/core/kernel/sprintf_tags.txt b/spec/tags/ruby/core/kernel/sprintf_tags.txt index ca3b225bb24..6692a0a1463 100644 --- a/spec/tags/ruby/core/kernel/sprintf_tags.txt +++ b/spec/tags/ruby/core/kernel/sprintf_tags.txt @@ -1,7 +1,5 @@ fails(compiler):Kernel#sprintf passes some tests for negative %u fails:Kernel#sprintf integer formats u converts argument as a decimal number -fails:Kernel#sprintf float formats g otherwise cuts fraction part to have only 6 digits at all -fails:Kernel#sprintf float formats G otherwise cuts fraction part to have only 6 digits at all fails:Kernel#sprintf float formats a converts floating point argument as [-]0xh.hhhhp[+-]dd fails:Kernel#sprintf float formats a displays Float::INFINITY as Inf fails:Kernel#sprintf float formats a displays Float::NAN as NaN @@ -27,8 +25,6 @@ fails:Kernel#sprintf width specifies the minimum number of characters that will fails:Kernel#sprintf precision float types controls the number of decimal places displayed in fraction part fails:Kernel#sprintf reference by name %{name} style supports flags, width and precision fails:Kernel.sprintf integer formats u converts argument as a decimal number -fails:Kernel.sprintf float formats g otherwise cuts fraction part to have only 6 digits at all -fails:Kernel.sprintf float formats G otherwise cuts fraction part to have only 6 digits at all fails:Kernel.sprintf float formats a converts floating point argument as [-]0xh.hhhhp[+-]dd fails:Kernel.sprintf float formats a displays Float::INFINITY as Inf fails:Kernel.sprintf float formats a displays Float::NAN as NaN diff --git a/spec/tags/ruby/core/marshal/restore_tags.txt b/spec/tags/ruby/core/marshal/restore_tags.txt index e14280993e0..0b0890226cc 100644 --- a/spec/tags/ruby/core/marshal/restore_tags.txt +++ b/spec/tags/ruby/core/marshal/restore_tags.txt @@ -5,6 +5,5 @@ fails:Marshal.restore for a user Class raises ArgumentError if the object from a fails:Marshal.restore for a Module loads an old module fails:Marshal.restore for a wrapped C pointer loads fails:Marshal.restore for a wrapped C pointer raises TypeError when the local class is missing _load_data -fails:Marshal.restore when a class does not exist in the namespace raises an ArgumentError fails:Marshal.restore for a Symbol loads a binary encoded Symbol fails:Marshal.restore for an Object raises ArgumentError if the object from an 'o' stream is not dumpable as 'o' type user class diff --git a/spec/tags/ruby/core/math/lgamma_tags.txt b/spec/tags/ruby/core/math/lgamma_tags.txt deleted file mode 100644 index 7c446cdfaf9..00000000000 --- a/spec/tags/ruby/core/math/lgamma_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Math.lgamma returns [Infinity, 1] when passed 0 diff --git a/spec/tags/ruby/core/module/autoload_tags.txt b/spec/tags/ruby/core/module/autoload_tags.txt index f3b770944c6..52eed4fec63 100644 --- a/spec/tags/ruby/core/module/autoload_tags.txt +++ b/spec/tags/ruby/core/module/autoload_tags.txt @@ -1,25 +1,4 @@ -fails:Module#autoload does not load the file when referring to the constant in defined? -fails:Module#autoload shares the autoload request across dup'ed copies of modules -fails:Module#autoload returns 'constant' on referring the constant with defined?() -fails:Module#autoload does not load the file when referring to the constant in defined? -fails:Module#autoload returns 'constant' on referring the constant with defined?() -fails(hangs):Module#autoload during the autoload before the constant is assigned returns nil in autoload thread and 'constant' otherwise for defined? -fails:Module#autoload calls main.require(path) to load the file -fails:Module#autoload does not remove the constant from Module#constants if load fails and keeps it as an autoload -fails:Module#autoload does not remove the constant from Module#constants if load raises a RuntimeError and keeps it as an autoload -fails:Module#autoload interacting with defined? does not load the file when referring to the constant in defined? -fails:Module#autoload during the autoload before the constant is assigned returns false in autoload thread and true otherwise for Module#const_defined? -fails:Module#autoload during the autoload before the constant is assigned returns nil in autoload thread and returns the path in other threads for Module#autoload? -fails:Module#autoload after autoloading searches for the constant like the original lookup in the included modules -fails:Module#autoload after autoloading searches for the constant like the original lookup in the included modules of the superclass -fails:Module#autoload after autoloading searches for the constant like the original lookup in the prepended modules -fails:Module#autoload the autoload is removed when the same file is required directly without autoload with a full path -fails:Module#autoload the autoload is removed when the same file is required directly without autoload with a relative path -fails(hangs):Module#autoload the autoload is removed when the same file is required directly without autoload in a nested require -fails:Module#autoload the autoload is triggered when the same file is required directly with a full path -fails:Module#autoload the autoload is triggered when the same file is required directly with a relative path -fails:Module#autoload the autoload is triggered when the same file is required directly in a nested require critical(hangs intermittently, #5717):Module#autoload (concurrently) blocks a second thread while a first is doing the autoload critical(hangs intermittently, #5717):Module#autoload (concurrently) blocks others threads while doing an autoload -fails:Module#autoload the autoload is triggered when the same file is required directly does not raise an error if the autoload constant was not defined -fails:Module#autoload considers an autoload constant as loaded when autoload is called for/from the current file +fails(conflicting state changes for failed load and autoload):Module#autoload does not remove the constant from Module#constants if load raises a RuntimeError and keeps it as an autoload +fails(incompatible locking in autoload):Module#autoload during the autoload before the constant is assigned returns nil in autoload thread and returns the path in other threads for Module#autoload? diff --git a/spec/tags/ruby/core/module/instance_method_tags.txt b/spec/tags/ruby/core/module/instance_method_tags.txt deleted file mode 100644 index 3a25dac86d2..00000000000 --- a/spec/tags/ruby/core/module/instance_method_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Module#instance_method sets the NameError#name attribute to the name of the missing method diff --git a/spec/tags/ruby/core/module/public_instance_method_tags.txt b/spec/tags/ruby/core/module/public_instance_method_tags.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/tags/ruby/core/objectspace/_id2ref_tags.txt b/spec/tags/ruby/core/objectspace/_id2ref_tags.txt index 6afad11463c..2554d354a3d 100644 --- a/spec/tags/ruby/core/objectspace/_id2ref_tags.txt +++ b/spec/tags/ruby/core/objectspace/_id2ref_tags.txt @@ -1,3 +1,3 @@ -fails:ObjectSpace._id2ref converts an object id to a reference to the object -fails:ObjectSpace._id2ref retrieves a Symbol by object_id fails:ObjectSpace._id2ref raises RangeError when an object could not be found +objectspace:ObjectSpace._id2ref converts an object id to a reference to the object +objectspace:ObjectSpace._id2ref retrieves a Symbol by object_id diff --git a/spec/tags/ruby/core/objectspace/define_finalizer_tags.txt b/spec/tags/ruby/core/objectspace/define_finalizer_tags.txt index 80848097942..a2c69c47fac 100644 --- a/spec/tags/ruby/core/objectspace/define_finalizer_tags.txt +++ b/spec/tags/ruby/core/objectspace/define_finalizer_tags.txt @@ -1,4 +1,3 @@ -fails:ObjectSpace.define_finalizer calls finalizer on process termination fails:ObjectSpace.define_finalizer calls finalizer at exit even if it is self-referencing fails:ObjectSpace.define_finalizer raises ArgumentError trying to define a finalizer on a non-reference fails:ObjectSpace.define_finalizer calls a finalizer defined in a finalizer running at exit diff --git a/spec/tags/ruby/core/objectspace/each_object_tags.txt b/spec/tags/ruby/core/objectspace/each_object_tags.txt index 74f6e91b589..fb27125f8e4 100644 --- a/spec/tags/ruby/core/objectspace/each_object_tags.txt +++ b/spec/tags/ruby/core/objectspace/each_object_tags.txt @@ -1,20 +1,20 @@ -fails:ObjectSpace.each_object calls the block once for each living, non-immediate object in the Ruby process -fails:ObjectSpace.each_object returns an enumerator if not given a block -fails:ObjectSpace.each_object finds an object stored in a global variable -fails:ObjectSpace.each_object finds an object stored in a top-level constant -fails:ObjectSpace.each_object finds an object stored in a second-level constant -fails:ObjectSpace.each_object finds an object stored in a local variable -fails:ObjectSpace.each_object finds an object stored in a local variable captured in a block explicitly -fails:ObjectSpace.each_object finds an object stored in a local variable captured in a block implicitly -fails:ObjectSpace.each_object finds an object stored in a local variable captured in a Proc#binding -fails:ObjectSpace.each_object finds an object stored in a local variable captured in a Kernel#binding -fails:ObjectSpace.each_object finds an object stored in a local variable set in a binding manually -fails:ObjectSpace.each_object finds an object stored in an array -fails:ObjectSpace.each_object finds an object stored in a hash key -fails:ObjectSpace.each_object finds an object stored in a hash value -fails:ObjectSpace.each_object finds an object stored in an instance variable -fails:ObjectSpace.each_object finds an object stored in a thread local -fails:ObjectSpace.each_object finds an object stored in a fiber local -fails:ObjectSpace.each_object finds an object captured in an at_exit handler -fails:ObjectSpace.each_object finds an object captured in finalizer -fails:ObjectSpace.each_object finds an object stored in a local variable captured in by a method defined with a block +objectspace:ObjectSpace.each_object calls the block once for each living, non-immediate object in the Ruby process +objectspace:ObjectSpace.each_object returns an enumerator if not given a block +objectspace:ObjectSpace.each_object finds an object stored in a global variable +objectspace:ObjectSpace.each_object finds an object stored in a top-level constant +objectspace:ObjectSpace.each_object finds an object stored in a second-level constant +objectspace:ObjectSpace.each_object finds an object stored in a local variable +objectspace:ObjectSpace.each_object finds an object stored in a local variable captured in a block explicitly +objectspace:ObjectSpace.each_object finds an object stored in a local variable captured in a block implicitly +objectspace:ObjectSpace.each_object finds an object stored in a local variable captured in by a method defined with a block +objectspace:ObjectSpace.each_object finds an object stored in a local variable captured in a Proc#binding +objectspace:ObjectSpace.each_object finds an object stored in a local variable captured in a Kernel#binding +objectspace:ObjectSpace.each_object finds an object stored in a local variable set in a binding manually +objectspace:ObjectSpace.each_object finds an object stored in an array +objectspace:ObjectSpace.each_object finds an object stored in a hash key +objectspace:ObjectSpace.each_object finds an object stored in a hash value +objectspace:ObjectSpace.each_object finds an object stored in an instance variable +objectspace:ObjectSpace.each_object finds an object stored in a thread local +objectspace:ObjectSpace.each_object finds an object stored in a fiber local +objectspace:ObjectSpace.each_object finds an object captured in an at_exit handler +objectspace:ObjectSpace.each_object finds an object captured in finalizer diff --git a/spec/tags/ruby/core/process/exec_tags.txt b/spec/tags/ruby/core/process/exec_tags.txt index d016983cc1c..0ac5da0ee6d 100644 --- a/spec/tags/ruby/core/process/exec_tags.txt +++ b/spec/tags/ruby/core/process/exec_tags.txt @@ -1,18 +1,18 @@ -fails:Process.exec raises Errno::EACCES when passed a directory -fails:Process.exec sets the current directory when given the :chdir option -fails:Process.exec with a command array uses the first element as the command name and the second as the argv[0] value -fails:Process.exec with a command array coerces the argument using to_ary -fails:Process.exec (environment variables) unsets other environment variables when given a true :unsetenv_others option -fails:Process.exec with a command array raises an ArgumentError if the Array does not have exactly two elements -fails:Process.exec with an options Hash with Integer option keys maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value -windows:Process.exec runs the specified command, replacing current process -windows:Process.exec with a single argument subjects the specified command to shell expansion -windows:Process.exec with a single argument creates an argument array with shell parsing semantics for whitespace -windows:Process.exec (environment variables) sets environment variables in the child environment -windows:Process.exec (environment variables) unsets environment variables whose value is nil -windows:Process.exec (environment variables) coerces environment argument using to_hash -fails:Process.exec (environment variables) sets environment variables in the child environment -fails:Process.exec (environment variables) unsets environment variables whose value is nil -fails:Process.exec (environment variables) coerces environment argument using to_hash -fails:Process.exec with an options Hash with Integer option keys lets the process after exec have specified file descriptor despite close_on_exec -fails:Process.exec with an options Hash with Integer option keys sets close_on_exec to false on specified fd even when it fails +fails:Process.exec raises Errno::EACCES when passed a directory +fails:Process.exec sets the current directory when given the :chdir option +fails:Process.exec with a command array uses the first element as the command name and the second as the argv[0] value +fails:Process.exec with a command array coerces the argument using to_ary +fails:Process.exec (environment variables) unsets other environment variables when given a true :unsetenv_others option +fails:Process.exec with a command array raises an ArgumentError if the Array does not have exactly two elements +fails:Process.exec with an options Hash with Integer option keys maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value +windows:Process.exec runs the specified command, replacing current process +windows:Process.exec with a single argument subjects the specified command to shell expansion +windows:Process.exec with a single argument creates an argument array with shell parsing semantics for whitespace +windows:Process.exec (environment variables) sets environment variables in the child environment +windows:Process.exec (environment variables) unsets environment variables whose value is nil +windows:Process.exec (environment variables) coerces environment argument using to_hash +fails:Process.exec (environment variables) sets environment variables in the child environment +fails:Process.exec (environment variables) unsets environment variables whose value is nil +fails:Process.exec (environment variables) coerces environment argument using to_hash +fails:Process.exec with an options Hash with Integer option keys lets the process after exec have specified file descriptor despite close_on_exec +fails:Process.exec with an options Hash with Integer option keys sets close_on_exec to false on specified fd even when it fails diff --git a/spec/tags/ruby/core/process/exit_tags.txt b/spec/tags/ruby/core/process/exit_tags.txt index f14eedd8fe8..bf310a01823 100644 --- a/spec/tags/ruby/core/process/exit_tags.txt +++ b/spec/tags/ruby/core/process/exit_tags.txt @@ -1,2 +1 @@ -fails:Process.exit! exits with the given status fails:Process.exit! overrides the original exception and exit status when called from #at_exit diff --git a/spec/tags/ruby/core/process/getrlimit_tags.txt b/spec/tags/ruby/core/process/getrlimit_tags.txt index 14bd467511a..06736a0df9c 100644 --- a/spec/tags/ruby/core/process/getrlimit_tags.txt +++ b/spec/tags/ruby/core/process/getrlimit_tags.txt @@ -4,5 +4,5 @@ fails:Process.getrlimit when passed a Symbol coerces :OFILE into RLIMIT_OFILE fails:Process.getrlimit when passed a String coerces 'LOCKS' into RLIMIT_LOCKS fails:Process.getrlimit when passed a String coerces 'NLIMITS' into RLIMIT_NLIMITS fails:Process.getrlimit when passed a String coerces 'OFILE' into RLIMIT_OFILE -fails:Process.getrlimit when passed a Symbol coerces the short name into the full RLIMIT_ prefixed name -fails:Process.getrlimit when passed a String coerces the short name into the full RLIMIT_ prefixed name +linux(LOCKS seems to be unsupported):Process.getrlimit when passed a Symbol coerces the short name into the full RLIMIT_ prefixed name +linux(LOCKS seems to be unsupported):Process.getrlimit when passed a String coerces the short name into the full RLIMIT_ prefixed name \ No newline at end of file diff --git a/spec/tags/ruby/core/process/kill_tags.txt b/spec/tags/ruby/core/process/kill_tags.txt index 8da1f99a4c0..265943c30d9 100644 --- a/spec/tags/ruby/core/process/kill_tags.txt +++ b/spec/tags/ruby/core/process/kill_tags.txt @@ -1,14 +1,15 @@ -critical(hangs on OS X and Windows):Process.kill signals the process group if the PID is zero -windows(hangs):Process.kill signals the process group if the signal number is negative -windows(hangs):Process.kill signals the process group if the short signal name starts with a minus sign -windows(hangs):Process.kill signals the process group if the full signal name starts with a minus sign -unstable(travis,intermittent):Process.kill accepts a signal name without the 'SIG' prefix -windows:Process.kill raises Errno::ESRCH if the process does not exist -windows:Process.kill accepts a Symbol as a signal name -windows:Process.kill accepts a String as signal name -windows:Process.kill accepts a signal name without the 'SIG' prefix -windows:Process.kill accepts a signal name with the 'SIG' prefix -windows:Process.kill acceps an Integer as a signal value -windows:Process.kill calls #to_int to coerce the pid to an Integer -windows:Process.kill signals multiple processes -windows:Process.kill returns the number of processes signaled +critical(hangs on OS X and Windows):Process.kill signals the process group if the PID is zero +windows(hangs):Process.kill signals the process group if the signal number is negative +windows(hangs):Process.kill signals the process group if the short signal name starts with a minus sign +windows(hangs):Process.kill signals the process group if the full signal name starts with a minus sign +unstable(travis,intermittent):Process.kill accepts a signal name without the 'SIG' prefix +windows:Process.kill raises Errno::ESRCH if the process does not exist +windows:Process.kill accepts a Symbol as a signal name +windows:Process.kill accepts a String as signal name +hangs:Process.kill accepts a String as signal name +windows:Process.kill accepts a signal name without the 'SIG' prefix +windows:Process.kill accepts a signal name with the 'SIG' prefix +windows:Process.kill acceps an Integer as a signal value +windows:Process.kill calls #to_int to coerce the pid to an Integer +windows:Process.kill signals multiple processes +windows:Process.kill returns the number of processes signaled diff --git a/spec/tags/ruby/core/process/ppid_tags.txt b/spec/tags/ruby/core/process/ppid_tags.txt deleted file mode 100644 index bb4d50981c0..00000000000 --- a/spec/tags/ruby/core/process/ppid_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Process.ppid returns the process id of the parent of this process diff --git a/spec/tags/ruby/core/process/spawn_tags.txt b/spec/tags/ruby/core/process/spawn_tags.txt index ef26f3365e6..b599da9cb7f 100644 --- a/spec/tags/ruby/core/process/spawn_tags.txt +++ b/spec/tags/ruby/core/process/spawn_tags.txt @@ -1,6 +1,4 @@ fails:Process.spawn calls #to_str to convert the environment keys -fails:Process.spawn joins a new process group if pgroup: true -fails:Process.spawn joins a new process group if pgroup: 0 fails:Process.spawn sets the umask if given the :umask option critical(runs very long before failing):Process.spawn redirects STDOUT to the given file if out: String critical(runs very long before failing):Process.spawn redirects STDERR to the given file if err: String @@ -9,10 +7,8 @@ fails:Process.spawn with a command array uses the first element as the command n fails:Process.spawn with a command array calls #to_ary to convert the argument to an Array fails:Process.spawn does not unset other environment variables when given a false :unsetenv_others option fails:Process.spawn does not unset environment variables included in the environment hash -fails:Process.spawn joins the current process if pgroup: false fails:Process.spawn redirects STDOUT to the given file if out: String fails:Process.spawn redirects STDERR to the given file if err: String -fails:Process.spawn when passed close_others: false does not close file descriptors >= 3 in the child process if fds are set close_on_exec=false critical(hangs):Process.spawn when passed close_others: true closes file descriptors >= 3 in the child process even if fds are set close_on_exec=false windows:Process.spawn executes the given command windows:Process.spawn sets environment variables in the child environment @@ -73,7 +69,6 @@ windows:Process.spawn with Integer option keys maps the key to a file descriptor fails:Process.spawn unsets other environment variables when given a true :unsetenv_others option fails:Process.spawn unsets other environment variables when given a non-false :unsetenv_others option fails:Process.spawn redirects both STDERR and STDOUT at the time to the given name -fails:Process.spawn with Integer option keys maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value fails:Process.spawn raises an Errno::EACCES or Errno::EISDIR when passed a directory fails:Process.spawn defaults :close_others to true fails(linux):Process.spawn inside Dir.chdir kills extra chdir processes diff --git a/spec/tags/ruby/core/process/status/exitstatus_tags.txt b/spec/tags/ruby/core/process/status/exitstatus_tags.txt deleted file mode 100644 index 338f894f088..00000000000 --- a/spec/tags/ruby/core/process/status/exitstatus_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Process::Status#exitstatus for a child that raised SignalException returns nil diff --git a/spec/tags/ruby/core/process/wait_tags.txt b/spec/tags/ruby/core/process/wait_tags.txt index e98af6856fa..c57399dab81 100644 --- a/spec/tags/ruby/core/process/wait_tags.txt +++ b/spec/tags/ruby/core/process/wait_tags.txt @@ -1,9 +1,3 @@ fails:Process.wait returns its childs pid -fails:Process.wait sets $? to a Process::Status -fails:Process.wait waits for any child process if no pid is given -fails:Process.wait waits for a specific child if a pid is given -fails:Process.wait waits for a child whose process group ID is that of the calling process fails:Process.wait doesn't block if no child is available when WNOHANG is used -fails:Process.wait always accepts flags=0 -fails:Process.wait coerces the pid to an Integer windows:Process.wait raises an Errno::ECHILD if there are no child processes diff --git a/spec/tags/ruby/core/range/minmax_tags.txt b/spec/tags/ruby/core/range/minmax_tags.txt new file mode 100644 index 00000000000..7f2c6f808c7 --- /dev/null +++ b/spec/tags/ruby/core/range/minmax_tags.txt @@ -0,0 +1,2 @@ +fails:Range#minmax on an inclusive range should try to iterate endlessly on an endless range +fails:Range#minmax on an exclusive range should try to iterate endlessly on an endless range diff --git a/spec/tags/ruby/core/string/unpack/j_tags.txt b/spec/tags/ruby/core/string/unpack/j_tags.txt deleted file mode 100644 index fdddfbe0d87..00000000000 --- a/spec/tags/ruby/core/string/unpack/j_tags.txt +++ /dev/null @@ -1,142 +0,0 @@ -fails:String#unpack with format 'J' with modifier '_' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '_' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '_' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '_' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '_' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '_' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'J' with modifier '_' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '_' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '_' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'J' with modifier '!' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '!' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '!' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '!' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '!' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '!' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'J' with modifier '!' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '!' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '!' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'j' with modifier '_' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '_' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '_' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '_' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '_' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '_' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'j' with modifier '_' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '_' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '_' decodes a long with most significant bit set as a negative number -fails:String#unpack with format 'j' with modifier '!' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '!' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '!' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '!' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '!' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '!' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'j' with modifier '!' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '!' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '!' decodes a long with most significant bit set as a negative number -fails:String#unpack with format 'J' with modifier '<' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '<' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '<' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '<' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '<' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '<' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '<' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '<' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'J' with modifier '>' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '>' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '>' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '>' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '>' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '>' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'J' with modifier '>' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '>' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '>' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'J' with modifier '<' and '_' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '<' and '_' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '<' and '_' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '<' and '_' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '<' and '_' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '<' and '_' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'J' with modifier '<' and '_' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '<' and '_' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '<' and '_' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'J' with modifier '<' and '!' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '<' and '!' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '<' and '!' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '<' and '!' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '<' and '!' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '<' and '!' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'J' with modifier '<' and '!' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '<' and '!' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '<' and '!' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'J' with modifier '>' and '_' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '>' and '_' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '>' and '_' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '>' and '_' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '>' and '_' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '>' and '_' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'J' with modifier '>' and '_' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '>' and '_' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '>' and '_' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'J' with modifier '>' and '!' decodes one long for a single format character -fails:String#unpack with format 'J' with modifier '>' and '!' decodes two longs for two format characters -fails:String#unpack with format 'J' with modifier '>' and '!' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'J' with modifier '>' and '!' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'J' with modifier '>' and '!' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'J' with modifier '>' and '!' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'J' with modifier '>' and '!' ignores NULL bytes between directives -fails:String#unpack with format 'J' with modifier '>' and '!' ignores spaces between directives -fails:String#unpack with format 'J' with modifier '>' and '!' decodes a long with most significant bit set as a positive number -fails:String#unpack with format 'j' with modifier '<' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '<' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '<' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '<' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '<' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '<' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '<' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '<' decodes a long with most significant bit set as a negative number -fails:String#unpack with format 'j' with modifier '>' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '>' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '>' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '>' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '>' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '>' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'j' with modifier '>' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '>' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '>' decodes a long with most significant bit set as a negative number -fails:String#unpack with format 'j' with modifier '<' and '_' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '<' and '_' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '<' and '_' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '<' and '_' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '<' and '_' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '<' and '_' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'j' with modifier '<' and '_' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '<' and '_' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '<' and '_' decodes a long with most significant bit set as a negative number -fails:String#unpack with format 'j' with modifier '<' and '!' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '<' and '!' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '<' and '!' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '<' and '!' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '<' and '!' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '<' and '!' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'j' with modifier '<' and '!' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '<' and '!' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '<' and '!' decodes a long with most significant bit set as a negative number -fails:String#unpack with format 'j' with modifier '>' and '_' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '>' and '_' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '>' and '_' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '>' and '_' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '>' and '_' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '>' and '_' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'j' with modifier '>' and '_' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '>' and '_' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '>' and '_' decodes a long with most significant bit set as a negative number -fails:String#unpack with format 'j' with modifier '>' and '!' decodes one long for a single format character -fails:String#unpack with format 'j' with modifier '>' and '!' decodes two longs for two format characters -fails:String#unpack with format 'j' with modifier '>' and '!' decodes the number of longs requested by the count modifier -fails:String#unpack with format 'j' with modifier '>' and '!' decodes the remaining longs when passed the '*' modifier -fails:String#unpack with format 'j' with modifier '>' and '!' decodes the remaining longs when passed the '*' modifier after another directive -fails:String#unpack with format 'j' with modifier '>' and '!' does not decode a long when fewer bytes than a long remain and the '*' modifier is passed -fails:String#unpack with format 'j' with modifier '>' and '!' ignores NULL bytes between directives -fails:String#unpack with format 'j' with modifier '>' and '!' ignores spaces between directives -fails:String#unpack with format 'j' with modifier '>' and '!' decodes a long with most significant bit set as a negative number diff --git a/spec/tags/ruby/core/thread/backtrace/location/absolute_path_tags.txt b/spec/tags/ruby/core/thread/backtrace/location/absolute_path_tags.txt index 95c18eac55b..61f825539e0 100644 --- a/spec/tags/ruby/core/thread/backtrace/location/absolute_path_tags.txt +++ b/spec/tags/ruby/core/thread/backtrace/location/absolute_path_tags.txt @@ -3,3 +3,4 @@ fails:Thread::Backtrace::Location#absolute_path returns a canonical path without fails:Thread::Backtrace::Location#absolute_path canonicalization returns a canonical path without symlinks, even when __FILE__ does not fails:Thread::Backtrace::Location#absolute_path canonicalization returns a canonical path without symlinks, even when __FILE__ is removed fails:Thread::Backtrace::Location#absolute_path returns an absolute path when using a relative main script path +fails:Thread::Backtrace::Location#absolute_path when used in a core method returns nil diff --git a/spec/tags/ruby/core/thread/backtrace/location/base_label_tags.txt b/spec/tags/ruby/core/thread/backtrace/location/base_label_tags.txt index c39b318040d..8a2ae990d25 100644 --- a/spec/tags/ruby/core/thread/backtrace/location/base_label_tags.txt +++ b/spec/tags/ruby/core/thread/backtrace/location/base_label_tags.txt @@ -1,2 +1 @@ fails:Thread::Backtrace::Location#base_label returns the base label of the call frame -fails:Thread::Backtrace::Location#base_label when call frame is inside a block returns the name of the method that contains the block diff --git a/spec/tags/ruby/core/thread/exclusive_tags.txt b/spec/tags/ruby/core/thread/exclusive_tags.txt deleted file mode 100644 index b16b07ce833..00000000000 --- a/spec/tags/ruby/core/thread/exclusive_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Thread.exclusive blocks the caller if another thread is also in an exclusive block diff --git a/spec/tags/ruby/core/thread/join_tags.txt b/spec/tags/ruby/core/thread/join_tags.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/tags/ruby/core/thread/priority_tags.txt b/spec/tags/ruby/core/thread/priority_tags.txt index 9c1e5b79249..5a24b623656 100644 --- a/spec/tags/ruby/core/thread/priority_tags.txt +++ b/spec/tags/ruby/core/thread/priority_tags.txt @@ -1,2 +1 @@ fails:Thread#priority= sets priority even when the thread has died -fails:Thread#priority= when set with an integer clamps the priority to -3..3 diff --git a/spec/tags/ruby/core/thread/report_on_exception_tags.txt b/spec/tags/ruby/core/thread/report_on_exception_tags.txt deleted file mode 100644 index b51fee572ea..00000000000 --- a/spec/tags/ruby/core/thread/report_on_exception_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Thread#report_on_exception= when used in conjunction with Thread#abort_on_exception first reports then send the exception back to the main Thread diff --git a/spec/tags/ruby/core/time/getlocal_tags.txt b/spec/tags/ruby/core/time/getlocal_tags.txt index a862316f935..607df0df9ea 100644 --- a/spec/tags/ruby/core/time/getlocal_tags.txt +++ b/spec/tags/ruby/core/time/getlocal_tags.txt @@ -1,7 +1,4 @@ fails:Time#getlocal returns a Time with a UTC offset of the specified number of Rational seconds fails:Time#getlocal raises ArgumentError if the String argument is not in an ASCII-compatible encoding -fails:Time#getlocal raises ArgumentError if the argument represents a value less than or equal to -86400 seconds -fails:Time#getlocal raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds fails:Time#getlocal with an argument that responds to #to_r coerces using #to_r -fails:Time#getlocal with an argument that responds to #to_str coerces using #to_str fails(not implemented, jruby/jruby#6161):Time#getlocal raises ArgumentError if the String argument is not of the form (+|-)HH:MM diff --git a/spec/tags/ruby/core/time/local_tags.txt b/spec/tags/ruby/core/time/local_tags.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/tags/ruby/core/time/localtime_tags.txt b/spec/tags/ruby/core/time/localtime_tags.txt index e6428683b72..6d26720d639 100644 --- a/spec/tags/ruby/core/time/localtime_tags.txt +++ b/spec/tags/ruby/core/time/localtime_tags.txt @@ -1,9 +1,5 @@ fails:Time#localtime returns a Time with a UTC offset of the specified number of Rational seconds fails:Time#localtime raises ArgumentError if the String argument is not in an ASCII-compatible encoding -fails:Time#localtime raises ArgumentError if the argument represents a value less than or equal to -86400 seconds -fails:Time#localtime raises ArgumentError if the argument represents a value greater than or equal to 86400 seconds fails:Time#localtime with an argument that responds to #to_r coerces using #to_r -fails:Time#localtime with an argument that responds to #to_str coerces using #to_str -fails:Time#localtime on a frozen time does not raise an error if already in the right time zone fails:Time#localtime does nothing if already in a local time zone fails(not implemented, jruby/jruby#6161):Time#localtime raises ArgumentError if the String argument is not of the form (+|-)HH:MM diff --git a/spec/tags/ruby/core/time/mktime_tags.txt b/spec/tags/ruby/core/time/mktime_tags.txt deleted file mode 100644 index e33b2b1a95b..00000000000 --- a/spec/tags/ruby/core/time/mktime_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Time.mktime creates the correct time just after dst change diff --git a/spec/tags/ruby/core/time/new_tags.txt b/spec/tags/ruby/core/time/new_tags.txt index bc08ba955f1..99e4672c8b1 100644 --- a/spec/tags/ruby/core/time/new_tags.txt +++ b/spec/tags/ruby/core/time/new_tags.txt @@ -1,7 +1,6 @@ fails:Time.new with a utc_offset argument returns a Time with a UTC offset of the specified number of Rational seconds fails:Time.new with a utc_offset argument raises ArgumentError if the String argument is not in an ASCII-compatible encoding fails:Time.new with a utc_offset argument with an argument that responds to #to_r coerces using #to_r -fails:Time.new with a utc_offset argument with an argument that responds to #to_str coerces using #to_str fails:Time.new with a utc_offset argument raises ArgumentError if the month is greater than 12 fails(not implemented, jruby/jruby#6161):Time.new with a timezone argument the #abbr method is used by '%Z' in #strftime fails(not implemented, jruby/jruby#6161):Time.new with a timezone argument Time-like argument of #utc_to_local and #local_to_utc methods has attribute values the same as a Time object in UTC diff --git a/spec/tags/ruby/core/time/strftime_tags.txt b/spec/tags/ruby/core/time/strftime_tags.txt index 3843721d98b..c0b0821cd3c 100644 --- a/spec/tags/ruby/core/time/strftime_tags.txt +++ b/spec/tags/ruby/core/time/strftime_tags.txt @@ -1,3 +1,2 @@ -fails:Time#strftime should be able to show the timezone if available fails:Time#strftime rounds an offset to the nearest second when formatting with %z fails:Time#strftime with %N formats the picoseconds of the second with %12N diff --git a/spec/tags/ruby/core/time/succ_tags.txt b/spec/tags/ruby/core/time/succ_tags.txt index 48e89293710..a00ea26ed5c 100644 --- a/spec/tags/ruby/core/time/succ_tags.txt +++ b/spec/tags/ruby/core/time/succ_tags.txt @@ -1,3 +1 @@ -fails:Time#succ returns a new time one second later than time -fails:Time#succ returns a new instance fails:Time#succ is obsolete diff --git a/spec/tags/ruby/core/tracepoint/binding_tags.txt b/spec/tags/ruby/core/tracepoint/binding_tags.txt index 96c3f5f8cc0..2e2ab7a649b 100644 --- a/spec/tags/ruby/core/tracepoint/binding_tags.txt +++ b/spec/tags/ruby/core/tracepoint/binding_tags.txt @@ -1 +1 @@ -fails(not implemented, jruby/jruby#6149):TracePoint#binding return the generated binding object from event +debug:TracePoint#binding return the generated binding object from event diff --git a/spec/tags/ruby/core/tracepoint/disable_tags.txt b/spec/tags/ruby/core/tracepoint/disable_tags.txt index f8f8ca08e6e..9ed93db63e8 100644 --- a/spec/tags/ruby/core/tracepoint/disable_tags.txt +++ b/spec/tags/ruby/core/tracepoint/disable_tags.txt @@ -1 +1 @@ -fails(not implemented, jruby/jruby#6149):TracePoint#disable returns true if trace was enabled +debug:TracePoint#disable returns true if trace was enabled diff --git a/spec/tags/ruby/core/tracepoint/enable_tags.txt b/spec/tags/ruby/core/tracepoint/enable_tags.txt index 2cbec4c7aa7..9cee44fd717 100644 --- a/spec/tags/ruby/core/tracepoint/enable_tags.txt +++ b/spec/tags/ruby/core/tracepoint/enable_tags.txt @@ -1,8 +1,4 @@ fails(not implemented, jruby/jruby#6149):TracePoint#enable without a block returns true if trace was enabled -fails(not implemented, jruby/jruby#6149):TracePoint#enable without a block returns false if trace was disabled -fails(not implemented, jruby/jruby#6149):TracePoint#enable with a block enables the trace object within a block -fails(not implemented, jruby/jruby#6149):TracePoint#enable with a block can accept arguments within a block but it should not yield arguments -fails(not implemented, jruby/jruby#6149):TracePoint#enable with a block disables the trace object outside the block fails(not implemented, jruby/jruby#6149):TracePoint#enable target: option enables trace point for specific location fails(not implemented, jruby/jruby#6149):TracePoint#enable target: option traces all the events triggered in specified location fails(not implemented, jruby/jruby#6149):TracePoint#enable target: option does not trace events in nested locations @@ -27,3 +23,9 @@ fails(not implemented, jruby/jruby#6149):TracePoint#enable target_line: option r fails(not implemented, jruby/jruby#6149):TracePoint#enable target_line: option raises ArgumentError if :target_line value is negative fails(not implemented, jruby/jruby#6149):TracePoint#enable target_line: option accepts value that could be coerced to Integer fails:TracePoint#enable when nested enables both TracePoints but only calls the respective callbacks +debug:TracePoint#enable without a block returns false if trace was disabled +debug:TracePoint#enable without a block returns true if trace was already enabled +debug:TracePoint#enable with a block enables the trace object within a block +debug:TracePoint#enable with a block enables the trace object for any thread +debug:TracePoint#enable with a block can accept arguments within a block but it should not yield arguments +debug:TracePoint#enable with a block disables the trace object outside the block diff --git a/spec/tags/ruby/core/tracepoint/lineno_tags.txt b/spec/tags/ruby/core/tracepoint/lineno_tags.txt index 8b44cf19939..885a330de52 100644 --- a/spec/tags/ruby/core/tracepoint/lineno_tags.txt +++ b/spec/tags/ruby/core/tracepoint/lineno_tags.txt @@ -1 +1 @@ -fails:TracePoint#lineno returns the line number of the event +debug:TracePoint#lineno returns the line number of the event diff --git a/spec/tags/ruby/core/tracepoint/new_tags.txt b/spec/tags/ruby/core/tracepoint/new_tags.txt index ebd27fff69e..d19a1fb0903 100644 --- a/spec/tags/ruby/core/tracepoint/new_tags.txt +++ b/spec/tags/ruby/core/tracepoint/new_tags.txt @@ -1,3 +1,3 @@ fails:TracePoint.new includes :line event when event is not specified fails:TracePoint.new includes multiple events when multiple event names are passed as params -fails(not implemented, jruby/jruby#6149):TracePoint.new converts given event name as string into symbol using to_sym +debug:TracePoint.new converts given event name as string into symbol using to_sym diff --git a/spec/tags/ruby/core/tracepoint/path_tags.txt b/spec/tags/ruby/core/tracepoint/path_tags.txt index fefd5de498f..8c3c0ebc312 100644 --- a/spec/tags/ruby/core/tracepoint/path_tags.txt +++ b/spec/tags/ruby/core/tracepoint/path_tags.txt @@ -1 +1 @@ -fails(not implemented, jruby/jruby#6149):TracePoint#path returns the path of the file being run +debug:TracePoint#path returns the path of the file being run diff --git a/spec/tags/ruby/core/tracepoint/self_tags.txt b/spec/tags/ruby/core/tracepoint/self_tags.txt index 24fca6a2eaa..8572a2211ed 100644 --- a/spec/tags/ruby/core/tracepoint/self_tags.txt +++ b/spec/tags/ruby/core/tracepoint/self_tags.txt @@ -1 +1 @@ -fails(not implemented, jruby/jruby#6149):TracePoint#self return the trace object from event +debug:TracePoint#self return the trace object from event diff --git a/spec/tags/ruby/core/unboundmethod/hash_tags.txt b/spec/tags/ruby/core/unboundmethod/hash_tags.txt index 661dce1ecc3..033a044a20e 100644 --- a/spec/tags/ruby/core/unboundmethod/hash_tags.txt +++ b/spec/tags/ruby/core/unboundmethod/hash_tags.txt @@ -1,2 +1 @@ -fails:UnboundMethod#hash returns the same value for user methods that are eql? fails:UnboundMethod#hash returns the same value for builtin methods that are eql? diff --git a/spec/tags/ruby/core/unboundmethod/owner_tags.txt b/spec/tags/ruby/core/unboundmethod/owner_tags.txt deleted file mode 100644 index add215556f1..00000000000 --- a/spec/tags/ruby/core/unboundmethod/owner_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:UnboundMethod#owner returns the new owner for aliased methods on singleton classes diff --git a/spec/tags/ruby/language/defined_tags.txt b/spec/tags/ruby/language/defined_tags.txt index 24a330bfe50..0bad700b45b 100644 --- a/spec/tags/ruby/language/defined_tags.txt +++ b/spec/tags/ruby/language/defined_tags.txt @@ -1,6 +1,2 @@ -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset class variable -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset class variable fails:The defined? keyword for a variable scoped constant returns nil if the scoped constant is not defined fails:The defined? keyword for a variable scoped constant returns 'constant' if the constant is defined in the scope of the variable reference -fails:The defined? keyword for a variable scoped constant returns nil if the class scoped constant is not defined -fails:The defined? keyword for a variable scoped constant returns 'constant' if the constant is defined in the scope of the class variable diff --git a/spec/tags/ruby/language/magic_comment_tags.txt b/spec/tags/ruby/language/magic_comment_tags.txt index c67b8e99f99..3e72a8f07d3 100644 --- a/spec/tags/ruby/language/magic_comment_tags.txt +++ b/spec/tags/ruby/language/magic_comment_tags.txt @@ -1,5 +1,5 @@ fails:Magic comment is case-insensitive fails:Magic comments in an -e argument do not cause bytes to be mangled by passing them through the wrong encoding -windows:Magic comments in stdin are optional -windows:Magic comments in stdin must be at the first line -windows:Magic comments in stdin must be the first token of the line +windows:Magic comments in stdin are optional +windows:Magic comments in stdin must be at the first line +windows:Magic comments in stdin must be the first token of the line diff --git a/spec/tags/ruby/language/next_tags.txt b/spec/tags/ruby/language/next_tags.txt deleted file mode 100644 index fb4939cef19..00000000000 --- a/spec/tags/ruby/language/next_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:The next statement in a method is invalid and raises a SyntaxError diff --git a/spec/tags/ruby/language/predefined_tags.txt b/spec/tags/ruby/language/predefined_tags.txt index 3ecc89361a4..0e2801459f9 100644 --- a/spec/tags/ruby/language/predefined_tags.txt +++ b/spec/tags/ruby/language/predefined_tags.txt @@ -2,4 +2,3 @@ fails:Global variable $0 raises a TypeError when not given an object that can be fails:Global variable $0 actually sets the program name windows:The predefined global constant ARGV contains Strings encoded in locale Encoding fails:Predefined global $! in bodies without ensure should be cleared when an exception is rescued even when a non-local return is present -fails(linux):Execution variable $: does not include the current directory diff --git a/spec/tags/ruby/language/regexp_tags.txt b/spec/tags/ruby/language/regexp_tags.txt deleted file mode 100644 index b80a863a613..00000000000 --- a/spec/tags/ruby/language/regexp_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Literal Regexps matches against $_ (last input) in a conditional if no explicit matchee provided diff --git a/spec/tags/ruby/language/retry_tags.txt b/spec/tags/ruby/language/retry_tags.txt deleted file mode 100644 index 820178679f8..00000000000 --- a/spec/tags/ruby/language/retry_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:The retry statement raises a SyntaxError when used outside of a begin statement diff --git a/spec/tags/ruby/language/return_tags.txt b/spec/tags/ruby/language/return_tags.txt index 5baf06feb72..7a6874cb490 100644 --- a/spec/tags/ruby/language/return_tags.txt +++ b/spec/tags/ruby/language/return_tags.txt @@ -1,2 +1 @@ fails:The return keyword at top level within a block within a class is allowed - diff --git a/spec/tags/ruby/language/string_tags.txt b/spec/tags/ruby/language/string_tags.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/tags/ruby/language/symbol_tags.txt b/spec/tags/ruby/language/symbol_tags.txt deleted file mode 100644 index f433facc9c3..00000000000 --- a/spec/tags/ruby/language/symbol_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:A Symbol literal with invalid bytes raises an EncodingError at parse time diff --git a/spec/tags/ruby/library/bigdecimal/BigDecimal_tags.txt b/spec/tags/ruby/library/bigdecimal/BigDecimal_tags.txt index 4482a649916..1e25d8ef340 100644 --- a/spec/tags/ruby/library/bigdecimal/BigDecimal_tags.txt +++ b/spec/tags/ruby/library/bigdecimal/BigDecimal_tags.txt @@ -4,6 +4,4 @@ fails:Kernel#BigDecimal when interacting with Rational BigDecimal precision is t fails:Kernel#BigDecimal when interacting with Rational BigDecimal maximum precision is nine more than precision except for abnormals fails:Kernel#BigDecimal when interacting with Rational BigDecimal(Rational, BigDecimal.precs[0]) produces the result we expect fails:Kernel#BigDecimal when interacting with Rational produces the expected result -fails(not implemented, jruby/jruby#6161):Kernel#BigDecimal does not ignores trailing garbage -fails(not implemented, jruby/jruby#6161):Kernel#BigDecimal process underscores as Float() fails:Kernel#BigDecimal with exception: false returns nil for invalid strings diff --git a/spec/tags/ruby/library/bigdecimal/constants_tags.txt b/spec/tags/ruby/library/bigdecimal/constants_tags.txt index 523ea08a43f..cad11db310c 100644 --- a/spec/tags/ruby/library/bigdecimal/constants_tags.txt +++ b/spec/tags/ruby/library/bigdecimal/constants_tags.txt @@ -1,4 +1,3 @@ -fails:BigDecimal constants has a BASE value fails:BigDecimal constants rounding-related constants has a ROUND_UP value fails:BigDecimal constants rounding-related constants has a ROUND_DOWN value fails:BigDecimal constants rounding-related constants has a ROUND_HALF_UP value diff --git a/spec/tags/ruby/library/coverage/peek_result_tags.txt b/spec/tags/ruby/library/coverage/peek_result_tags.txt deleted file mode 100644 index 4e021b92fdb..00000000000 --- a/spec/tags/ruby/library/coverage/peek_result_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:Coverage.peek_result returns the result so far -fails:Coverage.peek_result second call after require returns accumulated result diff --git a/spec/tags/ruby/library/coverage/result_tags.txt b/spec/tags/ruby/library/coverage/result_tags.txt deleted file mode 100644 index e9f6c9ac8bb..00000000000 --- a/spec/tags/ruby/library/coverage/result_tags.txt +++ /dev/null @@ -1,4 +0,0 @@ -fails:Coverage.result gives the covered files as a hash with arrays of count or nil -fails:Coverage.result no requires/loads should give empty hash -fails:Coverage.result second run without load/require should give empty hash -fails:Coverage.result second Coverage.start does nothing diff --git a/spec/tags/ruby/library/datetime/sec_tags.txt b/spec/tags/ruby/library/datetime/sec_tags.txt index f56ead8971a..24419e7fa24 100644 --- a/spec/tags/ruby/library/datetime/sec_tags.txt +++ b/spec/tags/ruby/library/datetime/sec_tags.txt @@ -1,2 +1 @@ fails:DateTime.sec raises an error when minute is given as a rational -fails:DateTime.sec raises an error for second fractions smaller than -60 diff --git a/spec/tags/ruby/library/datetime/second_tags.txt b/spec/tags/ruby/library/datetime/second_tags.txt index 22ab3e0175e..8595c127577 100644 --- a/spec/tags/ruby/library/datetime/second_tags.txt +++ b/spec/tags/ruby/library/datetime/second_tags.txt @@ -1,2 +1 @@ fails:DateTime#second raises an error when minute is given as a rational -fails:DateTime#second raises an error for second fractions smaller than -60 diff --git a/spec/tags/ruby/library/datetime/subtract_tags.txt b/spec/tags/ruby/library/datetime/subtract_tags.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/tags/ruby/library/delegate/delegator/send_tags.txt b/spec/tags/ruby/library/delegate/delegator/send_tags.txt deleted file mode 100644 index 469a8916334..00000000000 --- a/spec/tags/ruby/library/delegate/delegator/send_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:SimpleDelegator.new forwards protected method calls diff --git a/spec/tags/ruby/library/etc/getlogin_tags.txt b/spec/tags/ruby/library/etc/getlogin_tags.txt index c02f72163cd..e1d6c7a6c2d 100644 --- a/spec/tags/ruby/library/etc/getlogin_tags.txt +++ b/spec/tags/ruby/library/etc/getlogin_tags.txt @@ -1 +1 @@ -fails(Travis):Etc.getlogin returns the name associated with the current login activity +travis:Etc.getlogin returns the name associated with the current login activity diff --git a/spec/tags/ruby/library/net/http/http/get2_tags.txt b/spec/tags/ruby/library/net/http/http/get2_tags.txt index 1a23cfc6502..a3f7bdcc457 100644 --- a/spec/tags/ruby/library/net/http/http/get2_tags.txt +++ b/spec/tags/ruby/library/net/http/http/get2_tags.txt @@ -1 +1 @@ -critical(hangs on Travis):Net::HTTP#get2 when passed no block sends a GET request to the passed path and returns the response \ No newline at end of file +critical(hangs on Travis):Net::HTTP#get2 when passed no block sends a GET request to the passed path and returns the response diff --git a/spec/tags/ruby/library/net/http/http/post_tags.txt b/spec/tags/ruby/library/net/http/http/post_tags.txt index 30c198ecb78..241c39954cc 100644 --- a/spec/tags/ruby/library/net/http/http/post_tags.txt +++ b/spec/tags/ruby/library/net/http/http/post_tags.txt @@ -1 +1 @@ -critical(hangs on travis):Net::HTTP#post sends an post request to the passed path and returns the response \ No newline at end of file +critical(hangs on travis):Net::HTTP#post sends an post request to the passed path and returns the response diff --git a/spec/tags/ruby/library/net/http/http/proxy_port_tags.txt b/spec/tags/ruby/library/net/http/http/proxy_port_tags.txt deleted file mode 100644 index 94a040fb671..00000000000 --- a/spec/tags/ruby/library/net/http/http/proxy_port_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Net::HTTP#proxy_port when self is no proxy class instance returns nil diff --git a/spec/tags/ruby/library/net/http/http/started_tags.txt b/spec/tags/ruby/library/net/http/http/started_tags.txt deleted file mode 100644 index a6aaf63a316..00000000000 --- a/spec/tags/ruby/library/net/http/http/started_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Net::HTTP#started? returns false when self has been stopped again diff --git a/spec/tags/ruby/library/socket/socket/getaddrinfo_tags.txt b/spec/tags/ruby/library/socket/socket/getaddrinfo_tags.txt index 96b49356452..a6d7ddb3bcc 100644 --- a/spec/tags/ruby/library/socket/socket/getaddrinfo_tags.txt +++ b/spec/tags/ruby/library/socket/socket/getaddrinfo_tags.txt @@ -8,4 +8,4 @@ fails:Socket.getaddrinfo without global reverse lookups performs a reverse looku fails:Socket.getaddrinfo without global reverse lookups performs a reverse lookup when the reverse_lookup argument is :hostname fails:Socket.getaddrinfo without global reverse lookups performs a reverse lookup when the reverse_lookup argument is :numeric fails:Socket.getaddrinfo without global reverse lookups accepts an Integer as the address family using IPv6 -travis(no IPv6 so spec ends up having no expectations):Socket.getaddrinfo accepts empty addresses for IPv6 non-passive sockets \ No newline at end of file +travis(no IPv6 so spec ends up having no expectations):Socket.getaddrinfo accepts empty addresses for IPv6 non-passive sockets diff --git a/spec/tags/ruby/library/socket/socket/gethostname_tags.txt b/spec/tags/ruby/library/socket/socket/gethostname_tags.txt index aef3b5f3e8f..f7d657e1955 100644 --- a/spec/tags/ruby/library/socket/socket/gethostname_tags.txt +++ b/spec/tags/ruby/library/socket/socket/gethostname_tags.txt @@ -1 +1 @@ -travis(reverses localhost to a travis hostname):Socket.gethostname returns the host name \ No newline at end of file +travis(reverses localhost to a travis hostname):Socket.gethostname returns the host name diff --git a/spec/tags/ruby/library/socket/socket/listen_tags.txt b/spec/tags/ruby/library/socket/socket/listen_tags.txt index e102d1bf815..a76f267a6d8 100644 --- a/spec/tags/ruby/library/socket/socket/listen_tags.txt +++ b/spec/tags/ruby/library/socket/socket/listen_tags.txt @@ -7,3 +7,4 @@ fails:Socket#listen using IPv6 using a STREAM socket returns 0 fails:Socket#listen using IPv6 using a STREAM socket raises when the given argument can't be coerced to a Fixnum fails:Socket#listen using IPv4 using a STREAM socket raises when the given argument can't be coerced to an Integer fails:Socket#listen using IPv6 using a STREAM socket raises when the given argument can't be coerced to an Integer +fails:Socket#listen using IPv4 using a DGRAM socket raises Errno::EOPNOTSUPP or Errno::EACCES diff --git a/spec/tags/ruby/library/socket/socket/udp_server_loop_on_tags.txt b/spec/tags/ruby/library/socket/socket/udp_server_loop_on_tags.txt index 73d5da9c042..1f449f8b080 100644 --- a/spec/tags/ruby/library/socket/socket/udp_server_loop_on_tags.txt +++ b/spec/tags/ruby/library/socket/socket/udp_server_loop_on_tags.txt @@ -1,2 +1 @@ fails:Socket.udp_server_loop_on when a connection is available yields the message and a Socket::UDPSource -fails(intermittent, bug in select, jruby/jruby#6019):Socket.udp_server_loop_on when no connections are available blocks the caller diff --git a/spec/tags/ruby/library/socket/socket/unix_server_loop_tags.txt b/spec/tags/ruby/library/socket/socket/unix_server_loop_tags.txt index 03c88305361..0944522eae3 100644 --- a/spec/tags/ruby/library/socket/socket/unix_server_loop_tags.txt +++ b/spec/tags/ruby/library/socket/socket/unix_server_loop_tags.txt @@ -1,2 +1,2 @@ fails:Socket.unix_server_loop when a connection is available yields a Socket and an Addrinfo -fails:Socket.unix_server_loop when no connections are available blocks the caller +critical(intermittent):Socket.unix_server_loop when no connections are available blocks the caller diff --git a/spec/tags/ruby/library/stringio/printf_tags.txt b/spec/tags/ruby/library/stringio/printf_tags.txt index ef54e2933c5..7e2ee61de20 100644 --- a/spec/tags/ruby/library/stringio/printf_tags.txt +++ b/spec/tags/ruby/library/stringio/printf_tags.txt @@ -1,6 +1,4 @@ fails:StringIO#printf formatting integer formats u converts argument as a decimal number -fails:StringIO#printf formatting float formats g otherwise cuts fraction part to have only 6 digits at all -fails:StringIO#printf formatting float formats G otherwise cuts fraction part to have only 6 digits at all fails:StringIO#printf formatting float formats a converts floating point argument as [-]0xh.hhhhp[+-]dd fails:StringIO#printf formatting float formats a displays Float::INFINITY as Inf fails:StringIO#printf formatting float formats a displays Float::NAN as NaN diff --git a/spec/tags/ruby/library/weakref/__getobj___tags.txt b/spec/tags/ruby/library/weakref/__getobj___tags.txt deleted file mode 100644 index dd7be653b2c..00000000000 --- a/spec/tags/ruby/library/weakref/__getobj___tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails(depends on GC behavior, fails intermittently):WeakRef#__getobj__ raises WeakRef::RefError if the object is no longer reachable -fails(depends on GC behavior, fails intermittently):WeakRef#__getobj__ returns the object if it is reachable diff --git a/spec/tags/ruby/library/weakref/send_tags.txt b/spec/tags/ruby/library/weakref/send_tags.txt deleted file mode 100644 index bb5033e889e..00000000000 --- a/spec/tags/ruby/library/weakref/send_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:WeakRef#__send__ delegates to protected methods of the weakly-referenced object diff --git a/spec/tags/ruby/library/weakref/weakref_alive_tags.txt b/spec/tags/ruby/library/weakref/weakref_alive_tags.txt index d4ab0ba0716..0293b249fa8 100644 --- a/spec/tags/ruby/library/weakref/weakref_alive_tags.txt +++ b/spec/tags/ruby/library/weakref/weakref_alive_tags.txt @@ -1,2 +1 @@ -fails(depends on GC behavior, fails intermittently):WeakRef#weakref_alive? returns true if the object is reachable fails(depends on GC behavior, fails intermittently):WeakRef#weakref_alive? returns a falsey value if the object is no longer reachable diff --git a/spec/tags/ruby/library/zlib/deflate/deflate_tags.txt b/spec/tags/ruby/library/zlib/deflate/deflate_tags.txt index 0e34b14868b..0126f382161 100644 --- a/spec/tags/ruby/library/zlib/deflate/deflate_tags.txt +++ b/spec/tags/ruby/library/zlib/deflate/deflate_tags.txt @@ -1,7 +1,5 @@ fails:Zlib::Deflate.deflate deflates chunked data fails:Zlib::Deflate#deflate without break deflates chunked data fails:Zlib::Deflate#deflate without break deflates chunked data with final chunk -fails:Zlib::Deflate#deflate without break deflates chunked data without errors fails:Zlib::Deflate#deflate with break deflates only first chunk fails:Zlib::Deflate#deflate with break deflates chunked data with final chunk -fails:Zlib::Deflate#deflate with break deflates chunked data without errors diff --git a/test/check_versions.sh b/test/check_versions.sh index ead96af60d9..c9f4cd9f7c6 100755 --- a/test/check_versions.sh +++ b/test/check_versions.sh @@ -63,7 +63,7 @@ function check { check lib/target/jruby-stdlib-$jar_version.jar 12 check maven/jruby-jars/pkg/jruby-jars-$gem_version.gem 30 -check maven/jruby-jars/lib/jruby-core-$jar_version-complete.jar 15 +check maven/jruby-jars/lib/jruby-core-$jar_version-complete.jar 16 check maven/jruby-jars/lib/jruby-stdlib-$jar_version.jar 12 check maven/jruby-complete/target/jruby-complete-$jar_version.jar 27 check maven/jruby/target/jruby-$jar_version.jar 9 diff --git a/test/jruby/compiler/#test_jrubyc.rb# b/test/jruby/compiler/#test_jrubyc.rb# new file mode 100644 index 00000000000..08259ea130f --- /dev/null +++ b/test/jruby/compiler/#test_jrubyc.rb# @@ -0,0 +1,139 @@ +# coding: utf-8 +require 'test/unit' +require 'stringio' +require 'tempfile' +require 'fileutils' + +class TestJRubyc < Test::Unit::TestCase + + def setup; require 'jruby/jrubyc' + + @tempfile_stdout = Tempfile.open("test_jrubyc_stdout") + @old_stdout = $stdout.dup + $stdout.reopen @tempfile_stdout + $stdout.sync = true + + @tempfile_stderr = Tempfile.open("test_jrubyc_stderr") + @old_stderr = $stderr.dup + $stderr.reopen @tempfile_stderr + $stderr.sync = true + end + + def teardown + FileUtils.rm_rf(["foo", "ruby"]) rescue nil + + $stdout.reopen(@old_stdout) if @old_stdout + $stderr.reopen(@old_stderr) if @old_stderr + + $compile_test = nil; $encoding = nil + end + + def test_basic + @old_stdout.puts "test_basic" + JRuby::Compiler::compile_argv ["--verbose", __FILE__] + + output = File.read(@tempfile_stdout.path) + assert_equal "Compiling #{__FILE__}\n", output + + class_file = __FILE__.sub('.rb', '.class') + + assert File.exist?(class_file) + ensure + ( class_file && FileUtils.rm_rf(class_file) ) rescue nil + end + + def test_target + @old_stdout.puts "test_target" + tempdir = File.dirname(@tempfile_stdout.path) + class_file = File.join(tempdir, __FILE__.sub('.rb', '.class')) + + JRuby::Compiler::compile_argv ["--verbose", "--target", tempdir, __FILE__] + + output = File.read(@tempfile_stdout.path) + assert_equal "Compiling #{__FILE__}\n", output + + assert File.exist?(class_file) + ensure + ( class_file && FileUtils.rm_rf(class_file) ) rescue nil + end + + def test_bad_target + @old_stdout.puts "test_bad_target" + begin + JRuby::Compiler::compile_argv(["--verbose", "-t", "does_not_exist", __FILE__]) + fail "expected #{__method__} to raise" + rescue Exception => e + assert_equal "Target dir not found: does_not_exist", e.message + end + end + + def test_require + @old_stdout.puts "test_require" + $compile_test = false + File.open("test_file1.rb", "w") { |file| file.write("$compile_test = true") } + + JRuby::Compiler::compile_argv(["--verbose", "test_file1.rb"]) + output = File.read(@tempfile_stdout.path) + + assert_equal "Compiling test_file1.rb\n", output + + assert_nothing_raised { require 'test_file1' } + assert($compile_test) + ensure + File.delete("test_file1.rb") rescue nil + File.delete("test_file1.class") rescue nil + end + + def test_unicode + @old_stdout.puts "test_unicode" + file = Tempfile.create("test_unicode") + filename = file.path + file.write("$encoding = 'jalapeño'.encoding") + + JRuby::Compiler::compile_argv(["--verbose", filename, "--dir", File.dirname(filename)]) + + file.close + + assert_nothing_raised { load filename } + assert_equal(Encoding::UTF_8, $encoding) + ensure + file.close rescue nil + end + + # only filesystem installations of jruby can compile ruby to java + if !(RbConfig::CONFIG['bindir'].match( /!\//) || RbConfig::CONFIG['bindir'].match( /:\//)) + + def test_signature_with_arg_named_result + @old_stdout.puts "test_signaut...." + $compile_test = false + File.open("test_file2.rb", "w") { |file| file.write(<<-RUBY + class C + java_signature 'public int f(int result)' + def f(arg) + $compile_test = true + end + end + + C.new.f(0) + RUBY + )} + + JRuby::Compiler::compile_argv(["--verbose", "--java", "--javac", "test_file2.rb"]) + output = File.read(@tempfile_stderr.path) + assert_equal("", output) + + assert_nothing_raised { require 'test_file2' } + assert($compile_test) + ensure + File.delete("test_file2.rb") rescue nil + File.delete("C.java") rescue nil + File.delete("C.class") rescue nil + end + + end + + private + + def println(msg); Java::JavaLang::System.out.println(msg.to_s) end + +end diff --git a/test/jruby/compiler/test_jrubyc.rb b/test/jruby/compiler/test_jrubyc.rb index a7641689bbd..2c52569c3c3 100644 --- a/test/jruby/compiler/test_jrubyc.rb +++ b/test/jruby/compiler/test_jrubyc.rb @@ -3,6 +3,7 @@ require 'tempfile' require 'fileutils' require 'test/jruby/test_helper' +require 'pathname' class TestJRubyc < Test::Unit::TestCase @@ -42,17 +43,17 @@ def test_basic end def test_target - pend 'TODO: mangled path issue (SystemCallError) - Unknown Error (20109)' if TestHelper::WINDOWS tempdir = File.dirname(@tempfile_stdout.path) - class_file = File.join(tempdir, __FILE__.sub('.rb', '.class')) + relative_path = Pathname.new(File.absolute_path(__FILE__)).relative_path_from(Dir.pwd) + class_file = File.join(tempdir, relative_path.sub('.rb', '.class')) JRuby::Compiler::compile_argv ["--verbose", "--target", tempdir, __FILE__] output = File.read(@tempfile_stdout.path) assert_equal "Compiling #{__FILE__}\n", output - assert File.exist?(class_file) + assert File.exist?(class_file), "#{class_file} does not exists" ensure ( class_file && FileUtils.rm_rf(class_file) ) rescue nil end @@ -83,8 +84,6 @@ def test_require end def test_unicode - pend 'TODO: mangled path issue (SystemCallError) - Unknown Error (20109)' if TestHelper::WINDOWS - file = Tempfile.create("test_unicode") filename = file.path file.write("$encoding = 'jalapeño'.encoding") diff --git a/test/jruby/test_date.rb b/test/jruby/test_date.rb index 9996fde3036..084e19a12ba 100644 --- a/test/jruby/test_date.rb +++ b/test/jruby/test_date.rb @@ -912,6 +912,14 @@ def test_parse_bc_date_time # GH-5191 assert_equal(-1199, dt.year) end + def test_marshaling_keeps_offset + dt = DateTime.now + offset = dt.offset + dt2 = Marshal.load(Marshal.dump(dt)) + assert_equal(offset, dt2.offset) + assert_equal(dt, dt2) + end + def test_marshaling_with_active_support_like_calculation # GH-5188 time = ActiveSupport.time_advance(Time.now, days: 1) date = time.to_date diff --git a/test/jruby/test_file.rb b/test/jruby/test_file.rb index 05aab018c1d..db67a766c91 100644 --- a/test/jruby/test_file.rb +++ b/test/jruby/test_file.rb @@ -104,6 +104,15 @@ def test_expand_path_nil assert_raise(TypeError) { File.expand_path(nil, nil) } end + def test_copy_file_and_preserve + FileUtils.touch("original") + FileUtils.copy_file('original', 'copy', true) + assert(File.exist?('original')) + assert(File.exist?('copy')) + ensure + FileUtils.rm_rf %w[ original copy ] + end + # JRUBY-1116: these are currently broken on windows # what are these testing anyway?!?! if WINDOWS diff --git a/test/jruby/test_load_compiled_ruby.rb b/test/jruby/test_load_compiled_ruby.rb index 39ab43ff6e1..ffbecfdaf08 100644 --- a/test/jruby/test_load_compiled_ruby.rb +++ b/test/jruby/test_load_compiled_ruby.rb @@ -5,7 +5,12 @@ class TestLoadCompiledRuby < Test::Unit::TestCase FILENAME = 'test_load_compiled_ruby_script.rb' COMPILED = 'test_load_compiled_ruby_script.class' - def test_load_compiled_ruby; require 'jruby/jrubyc' + def test_load_compiled_ruby + unless org.jruby.util.cli.Options::AOT_LOADCLASSES.load + omit "loading .class not enabled; this test will be skipped" + end + + require 'jruby/jrubyc' begin File.open(FILENAME, 'w') do |f| f.write('$test_load_compiled_ruby = true') diff --git a/test/jruby/test_require.rb b/test/jruby/test_require.rb index e11d97cd516..967bcbe4927 100644 --- a/test/jruby/test_require.rb +++ b/test/jruby/test_require.rb @@ -7,11 +7,11 @@ class TestRequire < Test::Unit::TestCase # See JRUBY-3078. def test_require_fires_once_across_threads $foo = 0 - 100.times do + 100.times do |i| (1..(ENV['THREAD_COUNT'] || 5).to_i).map do Thread.new { require 'test/jruby/test_require_once_foo' } end.each { |t| t.join } - raise "Concurrent requires caused double-loading" if $foo != 1 + raise "Concurrent requires caused double-loading in iteration #{i} with $foo == #{$foo}" if $foo != 1 $foo = 0 $".pop end diff --git a/test/mri.extra.index b/test/mri.extra.index index 90961fc0e83..7ab9a7cb3ac 100644 --- a/test/mri.extra.index +++ b/test/mri.extra.index @@ -3,4 +3,5 @@ # Tracing tests, all spawn subprocesses test_tracer.rb -ruby/test_settracefunc.rb \ No newline at end of file +ruby/test_settracefunc.rb +ruby/test_syntax.rb diff --git a/test/mri/excludes/TestAutoload.rb b/test/mri/excludes/TestAutoload.rb index 5a03e155452..9718bc8e870 100644 --- a/test/mri/excludes/TestAutoload.rb +++ b/test/mri/excludes/TestAutoload.rb @@ -1,6 +1,4 @@ exclude :test_autoload_deprecate_constant, "to be fixed in #5489" -exclude :test_autoload_private_constant, "to be fixed in #5489" +exclude :test_autoload_so, "to be fixed in #5489" exclude :test_autoload_same_file, "to be fixed in #5489" -exclude :test_autoload_while_autoloading, "to be fixed in #5489" exclude :test_bug_13526, "racey test that doesn't behave as expected with concurrent threads #5294" -exclude :test_require_implemented_in_ruby_is_called, "attempted to dispatch to require but it seems to recursively call itself" diff --git a/test/mri/excludes/TestParse.rb b/test/mri/excludes/TestParse.rb index a6b04a1da93..c54e1e37a30 100644 --- a/test/mri/excludes/TestParse.rb +++ b/test/mri/excludes/TestParse.rb @@ -1,20 +1,5 @@ -exclude :test_arg_concat, "needs investigation" -exclude :test_error_def_in_argument, "provides different syntax errors" -exclude :test_invalid_char, "needs investigation" -exclude :test_lparenarg, "space issue with parens in really weird syntax" exclude :test_literal_in_conditional, "flip-flop case raises because do not implement flip-flop" -exclude :test_location_of_invalid_token, "not implemented, #6159" -exclude :test_method_block_location, "needs investigation" -exclude :test_method_location_in_rescue, "parser updates corrected defs to use first line" -exclude :test_named_capture_conflict, "needs investigation" -exclude :test_negative_line_number, "only backtrace is wrong from linenum instr getting wrong number" -exclude :test_question, "needs investigation" -exclude :test_rescue_in_command_assignment, "needs investigation" +exclude :test_method_location_in_rescue, "raise is not adding call_location element for obj.location" +exclude :test_negative_line_number, "JVM emits negative like some overflow (JIT only)" exclude :test_string, "lots of very specific error messages in which we differ a little" -exclude :test_symbol, "we should allow empty unicode escapes that not really" exclude :test_truncated_source_line, "2.5 truncates long source lines...we dont yet" -exclude :test_unexpected_token_after_numeric, "More strict parsing of text immediately after numbers" -exclude :test_unused_variable, "missing warning in parser (#2147)" -exclude :test_void_expr_stmts_value, "1; next; 2 is figured via compile.c. IR can do equivalent for 9k. Not a huge issue for 1.7.x barring real issue" -exclude :test_whitespace_warning, "not implemented, #6159" -exclude :test_yyerror_at_eol, "needs investigation" diff --git a/test/mri/excludes/TestSyntax.rb b/test/mri/excludes/TestSyntax.rb deleted file mode 100644 index 6cf59dc90c1..00000000000 --- a/test/mri/excludes/TestSyntax.rb +++ /dev/null @@ -1,19 +0,0 @@ -exclude :test__END___cr, "needs investigation" -exclude :test_block_after_cmdarg_in_paren, "needs investigation" -exclude :test_constant_reassignment_nested, "needs investigation" -exclude :test_constant_reassignment_toplevel, "needs investigation" -exclude :test_dedented_heredoc_with_blank_more_indented_line, "needs investigation #4308" -exclude :test_dedented_heredoc_with_indentation, "needs investigation #4308" -exclude :test_dedented_heredoc_with_interpolated_expression, "needs investigation #4308" -exclude :test_dedented_heredoc_with_interpolated_string, "needs investigation #4308" -exclude :test_dedented_heredoc_invalid_identifer, "needs investigation #4308" -exclude :test_defined_empty_argument, "needs investigation" -exclude :test_do_block_in_lambda, "needs investigation" -exclude :test_duplicated_when, "needs investigation" -exclude :test_heredoc_newline, "needs investigation" -exclude :test_integer_suffix, "needs investigation" -exclude :test_invalid_next, "lazy method build make this fail" -exclude :test_invalid_break, "lazy method build makes this fail" -exclude :test_syntax_error_in_rescue, "needs investigation" -exclude :test_warn_unreachable, "needs investigation" -exclude :test_warning_literal_in_condition, "needs investigation" diff --git a/test/mri/lib/test/unit/assertions.rb b/test/mri/lib/test/unit/assertions.rb index 346bef50363..d4629e6f175 100644 --- a/test/mri/lib/test/unit/assertions.rb +++ b/test/mri/lib/test/unit/assertions.rb @@ -519,11 +519,10 @@ def check_syntax(src, filename, line) if defined? RubyVM::InstructionSequence RubyVM::InstructionSequence.compile(src, filename, filename, line) else - src = <<-WRAPPED -#{src} - BEGIN { throw :tag, :ok } - WRAPPED - assert_equal(:ok, catch(:tag) { eval(src, binding, filename, line)}) + require 'jruby' + root = JRuby.parse(src, filename, false, line - 1) + runtime = JRuby::runtime + org.jruby.ir.IRBuilder.build_root(runtime.ir_manager, root) end end diff --git a/test/mri/ruby/test_syntax.rb b/test/mri/ruby/test_syntax.rb index 4e403a9ffd4..513c5b1cce3 100644 --- a/test/mri/ruby/test_syntax.rb +++ b/test/mri/ruby/test_syntax.rb @@ -958,8 +958,10 @@ def test_warning_literal_in_condition assert_warn(/literal in condition/) do eval('1 if //') end - assert_warn(/literal in condition/) do - eval('1 if true..false') + if RUBY_ENGINE != 'jruby' + assert_warn(/literal in condition/) do + eval('1 if true..false') + end end assert_warning(/literal in condition/) do eval('1 if 1') @@ -977,8 +979,10 @@ def test_warning_literal_in_condition assert_warn('') do eval('1 if !//') end - assert_warn('') do - eval('1 if !(true..false)') + if RUBY_ENGINE != 'jruby' + assert_warn('') do + eval('1 if !(true..false)') + end end assert_warning('') do eval('1 if !1') diff --git a/tool/generate_parser b/tool/generate_parser index 3e9e1cfb62c..eb68765d0ff 100755 --- a/tool/generate_parser +++ b/tool/generate_parser @@ -12,7 +12,7 @@ ###### Change these to tastes ###### JAY=jay -RUBY=ruby +RUBY=${RUBY:=ruby} PARSER_BASE=RubyParser YYTABLE_PREFIX= DEBUG=true @@ -47,7 +47,7 @@ $JAY $DEBUG_FLAG $PARSER_BASE.y < skeleton.parser | grep -v $DEBUG_STRIP >$PARSE # Patch file to get around Java static initialization issues plus extract # a bunch of stuff to seperate file (yytables). -$RUBY ../../../../../../../tool/patch_parser.rb $PARSER_BASE.out $YYTABLE_PREFIX > $PARSER_BASE.out2 +$RUBY ../../../../../../../tool/patch_parser.rb $PARSER_BASE.out $YYTABLE_PREFIX $PARSER_BASE.y > $PARSER_BASE.out2 $RUBY ../../../../../../../tool/optimize_parser.rb $PARSER_BASE.out2 $YYTABLE_PREFIX > $PARSER_BASE.java rm -f $PARSER_BASE.out $PARSER_BASE.out2 diff --git a/tool/generate_ripper b/tool/generate_ripper index 3fda3a63931..fa7a4b0818d 100755 --- a/tool/generate_ripper +++ b/tool/generate_ripper @@ -12,7 +12,7 @@ ###### Change these to tastes ###### JAY=jay -RUBY=/usr/bin/ruby +RUBY=${RUBY:=ruby} PARSER_BASE=RipperParser YYTABLE_PREFIX= DEBUG=true @@ -48,7 +48,7 @@ $JAY $DEBUG_FLAG $PARSER_BASE.y < skeleton.parser | grep -v $DEBUG_STRIP >$PARSE # Patch file to get around Java static initialization issues plus extract # a bunch of stuff to seperate file (yytables). -$RUBY $BACKUP_DIR/tool/patch_parser.rb $PARSER_BASE.out $YYTABLE_PREFIX > $PARSER_BASE.out2 +$RUBY $BACKUP_DIR/tool/patch_parser.rb $PARSER_BASE.out $YYTABLE_PREFIX $PARSER_BASE.y > $PARSER_BASE.out2 $RUBY $BACKUP_DIR/tool/optimize_parser.rb $PARSER_BASE.out2 $YYTABLE_PREFIX > $PARSER_BASE.java rm -f $PARSER_BASE.out $PARSER_BASE.out2 diff --git a/tool/optimize_parser.rb b/tool/optimize_parser.rb index dfb9fa34afe..f8c72908fab 100644 --- a/tool/optimize_parser.rb +++ b/tool/optimize_parser.rb @@ -64,13 +64,22 @@ def generate_ripper_action_body_method(state, code_body) def generate_action_body_method(state, code_body) @out.puts "states[#{state}] = new ParserState() {" - @out.puts " @Override public Object execute(ParserSupport support, RubyLexer lexer, Object yyVal, Object[] yyVals, int yyTop) {" - code_body.each { |line| @out.puts line } + @out.puts " @Override public Object execute(ParserSupport support, RubyLexer lexer, Object yyVal, ProductionState[] yyVals, int yyTop, int count) {" + code_body.each { |line| @out.puts frob_yyVals(line) } @out.puts " return yyVal;" @out.puts " }" @out.puts "};" end + # @{num} allows us to get direct access to the production state for that + # production or token. This is used for specialized reporting in syntax + # error messaged where we want to highlight a specific region. + def frob_yyVals(line) + line + .gsub(/yyVals\[([^\]]+)\]/, 'yyVals[\1].value') + .gsub(/@(\d+)/, 'yyVals[yyTop - count + \1]') + end + def translate_actions count = 1 while (translate_action) diff --git a/tool/patch_parser.rb b/tool/patch_parser.rb index 3733221ffa9..56c285e5050 100644 --- a/tool/patch_parser.rb +++ b/tool/patch_parser.rb @@ -1,59 +1,22 @@ -REMAPS = { - '"tUPLUS"' => '"unary+"', - '"tUMINUS"'=> '"unary-"', - '"tPOW"' => '"\'**\'"', - '"tCMP"' => '"\'<=>\'"', - '"tEQ"' => '"\'==\'"', - '"tEQQ"' => '"\'===\'"', - '"tNEQ"' => '"\'!=\'"', - '"tGEQ"' => '"\'>=\'"', - '"tLEQ"' => '"\'<=\'"', - '"tANDOP"' => '"\'&&\'"', - '"tOROP"' => '"\'||\'"', - '"tMATCH"' => '"\'=~\'"', - '"tNMATCH"'=> '"\'!~\'"', - '"tDOT"' => '"\'.\'"', - '"tDOT2"' => '"\'..\'"', - '"tDOT3"' => '"\'...\'"', - '"tAREF"' => '"\'[]\'"', - '"tASET"' => '"\'[]=\'"', - '"tLSHFT"' => '"\'<<\'"', - '"tRSHFT"' => '"\'>>\'"', - '"tANDDOT"' => '"\'&.\'"', - '"tCOLON2"' => '"\'::\'"', - '"tCOLON3"' => '"\':: at EXPR_BEG\'"', - '"tASSOC"' => '"\'=>\'"', - '"tLPAREN"' => '"\'(\'"', - '"tLPAREN2"'=> '"\'( arg\'"', - '"tRPAREN"' => '"\')\'"', - '"tLPAREN_ARG"' => '"\'[\'"', - '"tLBRACK"' => '"\'{\'"', - '"tRBRACK"' => '"\'{ arg\'"', - '"tLBRACE"' => '"\'[\'"', - '"tLBRACE_ARG"' => '"\'[ args\'"', - '"tSTAR"' => '"\'*\'"', - '"tSTAR2"' => '"\'*\'"', - '"tAMPER"' => '"\'&\'"', - '"tAMPER2"' => '"\'&\'"', - '"tTILDE"' => '"\'~\'"', - '"tPERCENT"' => '"\'%\'"', - '"tDIVIDE"' => '"\'/\'"', - '"tPLUS"' => '"\'+\'"', - '"tMINUS"' => '"\'-\'"', - '"tLT"' => '"\'<\'"', - '"tGT"' => '"\'>\'"', - '"tPIPE"' => '"\'|\'"', - '"tBANG"' => '"\'!\'"', - '"tCARET"' => '"\'^\'"', - '"tLCURLY"' => '"\'{\'"', - '"tRCURLY"' => '"\'}\'"', - '"tBACK_REF2"' => '"\'`\'"', - '"tSYMBEG"' => '"\':\'"', - '"tLAMBDA"' => '"\'->\'"', - '"tDSTAR"' => '"\'**\'"', -} +def generate_yyname_remaps(file) + remaps = {} + File.readlines(file).each do |line| + if /%token\s+\S+\s*(?\S+)[^{]*{{(?.*)}}/ =~ line + replacement = if replacement.length == 1 + %Q{\"'#{replacement}'\"} + else + %Q{\"#{replacement}\"} + end + name = %Q{"#{name}"} +# $stderr.puts "NAME #{name}(#{name.length}) = #{replacement.inspect}" + remaps[name] = replacement + end + end + remaps +end -def get_numbers_until_end_block(table) +def get_numbers_until_end_block + table = [] while line = gets break if /\};/ =~ line next if /^\/\// =~ line @@ -65,7 +28,7 @@ def get_numbers_until_end_block(table) table end -def print_names_until_end_block +def print_yynames_until_end_block(remaps) while line = gets if /\};/ =~ line print line @@ -73,7 +36,16 @@ def print_names_until_end_block end next if /^\/\// =~ line new_line = line.split(/,/).map do |element| - REMAPS[element.strip] || element +# $stderr.puts "ELEMENT #{element.strip} #{element.strip.size}" + key = element.strip.gsub("\\\\", '\\') + + # In .y we use '\\' which jay does realize is backslash in generated code + # but in yyNames it wraps the string in extra "" and then expands the number + # of \\ to make each \ its own backslash. Part of me does not quite grok + # how it encodes the name like this yet the specification works on matching + # an incoming token. Working around this by making it the key we need. + key = "\"\'\\\\'\"" if key == "\"'\\\\'\"" + remaps[key] || element end.join(',') puts new_line end @@ -81,21 +53,19 @@ def print_names_until_end_block # We use this script to generate our normal parser and the parser for # the ripper extension. -if ARGV[0] =~ /Ripper/ - package = 'org.jruby.ext.ripper' -else - package = 'org.jruby.parser' -end +package = ARGV[0] =~ /Ripper/ ? 'org.jruby.ext.ripper' : 'org.jruby.parser' while gets break if /protected static final short\[\] yyTable = \{/ =~ $_ print $_ end -# A little hacky...gets before ARGV to shift off and open file -yytable_prefix = ARGV.shift || '' +yytable_prefix = ARGV.length == 1 ? '' : ARGV.shift +original_grammar_file = ARGV.shift + +remaps = generate_yyname_remaps original_grammar_file -table4 = get_numbers_until_end_block([]) +table4 = get_numbers_until_end_block puts " protected static final short[] yyTable = #{yytable_prefix}YyTables.yyTable();" @@ -104,7 +74,7 @@ def print_names_until_end_block print $_ end -check4 = get_numbers_until_end_block([]) +check4 = get_numbers_until_end_block puts " protected static final short[] yyCheck = #{yytable_prefix}YyTables.yyCheck();" @@ -113,7 +83,7 @@ def print_names_until_end_block break if /protected static final String\[\] yyNames = \{/ =~ $_ end -print_names_until_end_block +print_yynames_until_end_block remaps while gets print $_ diff --git a/tool/sequel-travis.sh b/tool/sequel-travis.sh index cd671679ef0..5f55f8f97e2 100755 --- a/tool/sequel-travis.sh +++ b/tool/sequel-travis.sh @@ -13,8 +13,8 @@ psql -c 'create database sequel_test;' -U postgres # set up sequel git clone --depth=10 https://github.com/jeremyevans/sequel.git cd sequel -cp .travis.gemfile Gemfile +cp .ci.gemfile Gemfile bundle install # run tests -bundle exec rake spec_travis +bundle exec rake spec_ci