Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,33 @@ jobs:
require "rake"
puts "rexml #{REXML::VERSION}, csv #{CSV::VERSION}, rake #{Rake::VERSION}"
RUBY
# ironruby is the launcher, as jruby is JRuby's; RbConfig.ruby has to be a file,
# since libraries spawn it, and ir is the short name, which has to keep working.
cat > names.rb <<'RUBY'
abort "ruby_install_name: #{RbConfig::CONFIG["ruby_install_name"]}" unless RbConfig::CONFIG["ruby_install_name"] == "ironruby"
abort "no #{RbConfig.ruby}" unless File.file?(RbConfig.ruby)
puts "#{RbConfig.ruby} exists"
RUBY
# ironrubyw.exe, as rubyw.exe: the same interpreter as a Windows GUI program (PE
# subsystem 2), so it gets no console window. It still writes to a pipe it is given.
# (A heredoc's end has to start its line, so this one is not inside the if.)
cat > subsystem.rb <<'RUBY'
data = File.binread(ARGV[0], 4096)
subsystem = data[data[0x3c, 4].unpack1("V") + 24 + 68, 2].unpack1("v")
abort "#{ARGV[0]}: subsystem #{subsystem}" unless subsystem == 2
RUBY
if [ "$RUNNER_OS" = Windows ]; then
cmd //c ir.cmd smoke.rb
cmd //c ir.cmd Util/windows-desktop-check.rb
cmd //c ironruby.cmd smoke.rb
cmd //c ironruby.cmd names.rb
cmd //c ir.cmd -e "puts RUBY_ENGINE"
cmd //c ironruby.cmd Util/windows-desktop-check.rb
rubyw="Src/Console/bin/Debug/$TFM/ironrubyw.exe"
ruby subsystem.rb "$rubyw"
"$rubyw" -e 'require "set"; puts "ironrubyw: #{RUBY_ENGINE}"' | grep -x "ironrubyw: ironruby"
else
./ir.sh smoke.rb
./ironruby smoke.rb
./ironruby names.rb
./ir.sh -e 'puts RUBY_ENGINE'
fi

# IO#write_nonblock on a socket claims only what the kernel took (#14). On Linux the
Expand Down
28 changes: 18 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
name: Release

# Binary builds: a self-contained IronRuby for each platform, made by
# Util/package-release.sh, and the launch video, rendered from media/launch. Pushing a
# tag v* publishes them as a GitHub release (a pre-release while the version has a
# suffix such as -preview1), with Docs/releases/<tag>.md as the notes when there is one;
# running the workflow by hand, or a pull request that changes the packaging or the
# video, only keeps them as workflow artifacts. Run by hand with video_for set to a tag,
# it renders only the video and replaces it, and its SHA256SUMS line, on that release.
# Util/package-release.sh. Pushing a tag v* publishes them as a GitHub release (a
# pre-release while the version has a suffix such as -preview1), with
# Docs/releases/<tag>.md as the notes when there is one; running the workflow by hand, or
# a pull request that changes the packaging, only keeps them as workflow artifacts.
# The launch video, rendered from media/launch, is only rendered when asked for by hand -
# it takes about 7 minutes of every run otherwise: with render_video it is kept as an
# artifact, and with video_for set to a tag it alone is rendered and replaces the video,
# and its SHA256SUMS line, on that release (or adds them to one published without).
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
on:
push:
tags: ['v*']
pull_request:
paths:
- .github/workflows/release.yml
- Util/package-release.sh
- media/launch/**
workflow_dispatch:
inputs:
render_video:
description: Render the launch video as well, as a workflow artifact
type: boolean
required: false
default: false
video_for:
description: Render only the launch video and replace it on this release (a tag, such as v4.0.0)
required: false
Expand Down Expand Up @@ -157,6 +163,7 @@ jobs:
# does not render does not hold the archives back.
video:
name: launch video
if: github.event_name == 'workflow_dispatch' && (inputs.render_video || inputs.video_for != '')
runs-on: ubuntu-latest
continue-on-error: true
# A render takes about 7 minutes; a failed one can leave hyperframes waiting.
Expand Down Expand Up @@ -207,8 +214,9 @@ jobs:

release:
name: GitHub release
if: github.ref_type == 'tag'
needs: [package, video]
# A pushed tag only: a run by hand keeps its archives as artifacts, even on a tag.
if: github.event_name == 'push' && github.ref_type == 'tag'
needs: package
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -217,7 +225,7 @@ jobs:
with:
sparse-checkout: Docs/releases

# ironruby-* only: the archives and the video, not the review stills.
# ironruby-* only: the archives, not the review stills (the video is not rendered here).
- uses: actions/download-artifact@v8
with:
path: dist
Expand Down
4 changes: 3 additions & 1 deletion Docs/rails-on-windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ CRuby, the CSRF meta tags are there, and a POST without a token is refused with
`ruby_install_name`, which is `ir`, so they start `#!/usr/bin/env ir.exe"`; like MRI, the
command line and prism skip a `#!` line without "ruby" in it. A `#!` line naming IronRuby's
own launcher now counts as Ruby. `RubyUtils.ShebangNamesIronRuby`, `RubyCommandLine.cs`,
`PrismAstBridge.cs`.
`PrismAstBridge.cs`. Since then the launcher is called `ironruby`, as JRuby's is `jruby`,
and so is `ruby_install_name`: new binstubs say `#!/usr/bin/env ironruby` and need no
special case; this one keeps those written with `ir` running.
5. **`TZInfo::DataSourceNotFound` in the first initializer.** Windows has no zoneinfo, so the
Gemfile has `gem "tzinfo-data", platforms: %i[windows jruby]`; Bundler filters such gems by the
*generic* platform, and IronRuby's `universal-dotnet` is generic `ruby`. For the dotnet
Expand Down
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,23 @@ IronRuby. `io/console` is a C extension in CRuby, so IronRuby implements it over
Scripts run the same way, and gems install with real TLS:

```console
$ ./ir.sh script.rb # prism front end, vendored stdlib, JIT and OSR on
$ ./igem.sh install rack # or: ./ir.sh -S gem install rack
$ ./ir.sh -S bundle install
$ ./ironruby script.rb # prism front end, vendored stdlib, JIT and OSR on
$ ./igem.sh install rack # or: ./ironruby -S gem install rack
$ ./ironruby -S bundle install
```

`ir` / `igem` / `iirb` / `irubyc` are the i-prefixed names IronRuby has used since 1.x, so
they can sit on `PATH` beside CRuby's `ruby` and `gem` — the same reason JRuby ships
`jruby`, `jgem`, `jirb` and `jrubyc`. The unprefixed `gem`, `irb`, `bundle`, `bundler` and
`irubyc` live in `Src/StdLib/bin` and are what `ir -S <name>` finds.
The interpreter is `ironruby` (`ironruby.cmd` on Windows), as JRuby's is `jruby`: it is
RbConfig's `ruby_install_name`, so the binstubs Bundler and Rails write start
`#!/usr/bin/env ironruby` - a `#!` line with "ruby" in it, which Ruby runs as Ruby. (Those
RubyGems writes for an installed gem name the launcher by its path instead, `#!<root>/ironruby`,
so they only work where that path still does.) `ir.sh` and `ir.cmd` are its short name, the
one IronRuby has used since 1.x, and run the same thing.
`igem` / `iirb` / `irubyc` keep the i-prefix so they can sit on `PATH` beside CRuby's `gem`
and `irb`, as JRuby's `jgem`, `jirb` and `jrubyc` do. The unprefixed `gem`, `irb`, `bundle`,
`bundler` and `irubyc` live in `Src/StdLib/bin` and are what `ironruby -S <name>` finds.
On Windows the build also has `ironrubyw.exe` next to `ir.exe`, as CRuby has `rubyw.exe` and
JRuby `jrubyw.exe`: the same interpreter as a Windows GUI program, which gets no console
window - for Windows Forms and WPF programs; `Samples\Notepad\notepad.cmd` starts it.

```ruby
# all of this runs today
Expand Down Expand Up @@ -502,6 +510,8 @@ $ ./irb.sh
$ ./igem.sh install rack
```

4.0.1 has `ir.sh` and `ir.cmd`; releases after it also have `ironruby` and `ironruby.cmd`
(see above), and `ir.sh` / `ir.cmd` keep working there.
On Windows, unzip it and use `ir.cmd`, `irb.cmd` and `igem.cmd`, or double-click
`Samples\Notepad\notepad.cmd`. The archive has the same layout as a checkout, with the
Release build in `Src/Console/bin/Release/net8.0`, so everything above applies to it
Expand Down
24 changes: 0 additions & 24 deletions Ruby.sln
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ruby.ConsoleAny", "Src\Console\Ruby.ConsoleAny.csproj", "{6EE7A428-D803-41BC-8248-1297C3ACE369}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ruby.WinConsole", "Src\WinConsole\Ruby.WinConsole.csproj", "{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ruby.WinConsoleAny", "Src\WinConsole\Ruby.WinConsoleAny.csproj", "{F231EB3F-75E7-499F-B1F2-C26E56601E1B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{BBF4E796-17F9-4B55-A144-5CE412991105}"
ProjectSection(SolutionItems) = preProject
Build\After.targets = Build\After.targets
Expand Down Expand Up @@ -126,26 +122,6 @@ Global
{6EE7A428-D803-41BC-8248-1297C3ACE369}.v2Debug|Any CPU.Build.0 = v2Debug|Any CPU
{6EE7A428-D803-41BC-8248-1297C3ACE369}.v2Release|Any CPU.ActiveCfg = v2Release|Any CPU
{6EE7A428-D803-41BC-8248-1297C3ACE369}.v2Release|Any CPU.Build.0 = v2Release|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.FxCop|Any CPU.ActiveCfg = FxCop|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.FxCop|Any CPU.Build.0 = FxCop|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Release|Any CPU.Build.0 = Release|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Debug|Any CPU.ActiveCfg = v2Debug|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Debug|Any CPU.Build.0 = v2Debug|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Release|Any CPU.ActiveCfg = v2Release|Any CPU
{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Release|Any CPU.Build.0 = v2Release|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.FxCop|Any CPU.ActiveCfg = FxCop|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.FxCop|Any CPU.Build.0 = FxCop|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Release|Any CPU.Build.0 = Release|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Debug|Any CPU.ActiveCfg = v2Debug|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Debug|Any CPU.Build.0 = v2Debug|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Release|Any CPU.ActiveCfg = v2Release|Any CPU
{F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Release|Any CPU.Build.0 = v2Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
19 changes: 12 additions & 7 deletions Samples/Notepad/notepad.cmd
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
@echo off
rem IronRuby Notepad. Double-click it, drop a file on it, or run: notepad.cmd file.txt
rem
rem ir.exe is a console program, so Windows gives it a console window. "start /b" leaves
rem that console to ir.exe alone once this batch file has ended, and notepad.rb then
rem lets go of it, which closes the window. To keep the console for Ruby's output, run
rem ..\..\ir.cmd notepad.rb instead. The build is chosen as ir.cmd chooses it.
rem ironrubyw.exe is ironruby without a console window, as rubyw.exe is ruby's: a Windows
rem Forms program has no use for one. To keep a console for Ruby's output, run
rem ..\..\ironruby.cmd notepad.rb instead. The build is chosen as ironruby.cmd chooses it.
rem
rem A build from before ironrubyw has only ir.exe, a console program, which Windows gives
rem a console window: "start /b" leaves that console to ir.exe alone once this batch file
rem has ended, and notepad.rb then lets go of it, which closes the window. (Single-line
rem ifs: a dropped file name with a ")" in it would end a parenthesized block.)
setlocal
set "IR_ROOT=%~dp0..\.."
if "%IR_CONFIG%"=="" if not exist "%IR_ROOT%\Src\Console\bin\Debug\" if exist "%IR_ROOT%\Src\Console\bin\Release\" set "IR_CONFIG=Release"
if "%IR_CONFIG%"=="" set "IR_CONFIG=Debug"
if "%IR_TFM%"=="" set "IR_TFM=net8.0"
set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\win-x64\ir.exe"
if not exist "%IR_BIN%" set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\ir.exe"
set "IR_DIR=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\win-x64"
if not exist "%IR_DIR%\ir.exe" set "IR_DIR=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%"
set "S=%IR_ROOT%\Src\StdLib"
start "" /b "%IR_BIN%" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" "%~dp0notepad.rb" %*
if exist "%IR_DIR%\ironrubyw.exe" start "" "%IR_DIR%\ironrubyw.exe" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" "%~dp0notepad.rb" %*
if not exist "%IR_DIR%\ironrubyw.exe" start "" /b "%IR_DIR%\ir.exe" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" "%~dp0notepad.rb" %*
9 changes: 5 additions & 4 deletions Samples/Notepad/notepad.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# IronRuby Notepad: Windows Notepad, written in Ruby, on IronRuby and Windows Forms.
#
# notepad.cmd [file] double-click it, drop a file on it, or run it
# ..\..\ir.cmd notepad.rb [file] the same, keeping the console for Ruby's output
# notepad.cmd [file] double-click it, drop a file on it, or run it
# ..\..\ironruby.cmd notepad.rb [file] the same, keeping the console for Ruby's output
#
# What Notepad does, this does: New, New Window, Open, Save, Save As, Page Setup and
# Print with a header and page numbers; Undo and Redo, Cut, Copy, Paste, Delete, Find,
Expand Down Expand Up @@ -50,8 +50,9 @@ def self.caret_position
D::Point.new(*point[0, 8].unpack("l2"))
end

# ir.exe is a console program, so started from Explorer it gets a console window of
# its own. When nobody else is attached to it, let go of it: that closes the window.
# ir.exe and ironruby.exe are console programs, so started from Explorer they get a
# console window of their own. When nobody else is attached to it, let go of it: that
# closes the window. Under ironrubyw.exe, which notepad.cmd uses, there is none.
def self.detach_console_if_alone
list = Fiddle::Pointer.malloc(64)
return unless CONSOLE_PROCESSES.call(list, 16) == 1
Expand Down
32 changes: 32 additions & 0 deletions Src/Console/Ruby.Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@
file this process has LOCK_EX'd. Turn the emulation off. -->
<RuntimeHostConfigurationOption Include="System.IO.DisableFileLocking" Value="true" />
</ItemGroup>
<!-- RbConfig's ruby_install_name is "ironruby", as JRuby's is "jruby", so RbConfig.ruby is
<bindir>/ironruby(.exe): a copy of the apphost under that name. An apphost starts the
ir.dll whose name is written into it, whatever the file itself is called. -->
<Target Name="CopyIronRubyAppHost" AfterTargets="Build" Condition="'$(UseAppHost)' != 'false'">
<Copy SourceFiles="$(OutDir)$(AssemblyName)$(_NativeExecutableExtension)"
DestinationFiles="$(OutDir)ironruby$(_NativeExecutableExtension)"
Condition="Exists('$(OutDir)$(AssemblyName)$(_NativeExecutableExtension)')" SkipUnchangedFiles="true" />
</Target>
<Target Name="PublishIronRubyAppHost" AfterTargets="Publish" Condition="'$(UseAppHost)' != 'false'">
<Copy SourceFiles="$(PublishDir)$(AssemblyName)$(_NativeExecutableExtension)"
DestinationFiles="$(PublishDir)ironruby$(_NativeExecutableExtension)"
Condition="Exists('$(PublishDir)$(AssemblyName)$(_NativeExecutableExtension)')" SkipUnchangedFiles="true" />
</Target>
<!-- ironrubyw.exe, as CRuby has rubyw.exe and JRuby jrubyw.exe: the same ir.dll behind an
apphost marked as a Windows GUI program, so Windows gives it no console window - for
Windows Forms and WPF programs such as Samples/Notepad. It is the SDK's own
CreateAppHost, as for a WinExe project. Only a Windows apphost has the flag. -->
<!-- Inputs and Outputs as the SDK's own _CreateAppHost has them: CreateAppHost rewrites its
file every time, and a build while Notepad runs under ironrubyw.exe could not. -->
<Target Name="CreateIronRubyWAppHost" AfterTargets="Build"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
Inputs="@(IntermediateAssembly);$(AppHostSourcePath)" Outputs="$(OutDir)ironrubyw.exe"
Condition="'$(UseAppHost)' != 'false' and '$(_NativeExecutableExtension)' == '.exe' and '$(AppHostSourcePath)' != '' and Exists('$(AppHostSourcePath)')">
<CreateAppHost AppHostSourcePath="$(AppHostSourcePath)"
AppHostDestinationPath="$(OutDir)ironrubyw.exe"
AppBinaryName="$(AssemblyName)$(TargetExt)"
IntermediateAssembly="@(IntermediateAssembly->'%(FullPath)')"
WindowsGraphicalUserInterface="true" />
</Target>
<Target Name="PublishIronRubyWAppHost" AfterTargets="Publish"
Condition="'$(UseAppHost)' != 'false' and '$(_NativeExecutableExtension)' == '.exe' and Exists('$(OutDir)ironrubyw.exe')">
<Copy SourceFiles="$(OutDir)ironrubyw.exe" DestinationFiles="$(PublishDir)ironrubyw.exe" SkipUnchangedFiles="true" />
</Target>
<ItemGroup>
<ProjectReference Include="..\Ruby\Ruby.csproj" />
<ProjectReference Include="..\Libraries\IronRuby.Libraries.csproj" />
Expand Down
10 changes: 5 additions & 5 deletions Src/Ruby/Hosting/RubyCommandLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ protected override int Run() {
}
}

// `ruby` with no -e and no script argument reads the program from stdin when
// stdin is redirected. Only a real terminal gets the interactive loop — and
// the banner that goes with it. A script argument of "-" says to read stdin
// outright, whether or not it is redirected, and is how the CRuby test suite
// runs a program in a child process; ARGV is what follows it.
// A script argument of "-" says to read the program from stdin, and is how the CRuby
// test suite runs a program in a child process; ARGV is what follows it. The options
// parser gives "-" when there is neither -e nor a script, so `ironruby` alone reads
// stdin as `ruby` does - at a terminal too, until EOF. A host that skips the parser
// and gives neither still gets stdin when it is redirected.
if (Options.Command == null &&
(Options.FileName == "-" || (Options.FileName == null && System.Console.IsInputRedirected))) {
// The program is read as bytes: a magic comment may say they are not UTF-8, and
Expand Down
9 changes: 9 additions & 0 deletions Src/Ruby/Hosting/RubyOptionsParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,15 @@ protected override void AfterParse() {
ConsoleOptions.PrintVersion = true;
ConsoleOptions.Exit = true;
}

// `ruby` with neither -e nor a script reads the program from stdin until EOF - at a
// terminal too - as if "-" had been given, and $0 is "-" (MRI, JRuby). IronRuby used to
// start the DLR's interactive console there; irb is `irb` / `iirb`. ironrubyw, which has
// no console, then reads nothing and exits, as rubyw does.
if (!ConsoleOptions.Exit && ConsoleOptions.Command == null && ConsoleOptions.FileName == null) {
ConsoleOptions.FileName = "-";
LanguageSetup.Options["MainFile"] = "-";
}
}

/// <summary>
Expand Down
Loading
Loading