-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: execute commands consistently for paths with spaces
Note that this is a pretty heavy refactoring, where code was moved from `exe/tailwindcss` to `lib/tailwindcss/commands.rb` where we can more easily run unit tests on it. Note also that we no longer use Shellwords to build command strings, a library which does not generate correct strings on Windows platforms. Instead we consistently use arrays of command arguments, which can be passed to `exec` or `system` however we see fit. The wrapper script conditionally uses `system` on windows platforms because `exec` can't find the executable (see related issue at rubys/sprockets-esbuild#4). Finally, note that the rake tasks no longer use the `exe/tailwindcss` wrapper script, and instead use the binary executable directly. We can reverse this decision if we ever decide to support manually-installed tailwindcss somewhere on the $PATH; but because previously the rake tasks hardcoded the path/to/exe/tailwindcss, we're not introducing any new constraints by skipping the wrapper.
- Loading branch information
1 parent
30495ab
commit 76e5769
Showing
5 changed files
with
162 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,19 @@ | ||
#! /usr/bin/env ruby | ||
# because rubygems shims assume a gem's executables are Ruby | ||
|
||
require "shellwords" | ||
require "tailwindcss/upstream" | ||
|
||
supported_platforms = Tailwindcss::Upstream::NATIVE_PLATFORMS.keys | ||
platform = [:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-") | ||
|
||
if supported_platforms.none? { |supported_platform| Gem::Platform.match(supported_platform) } | ||
STDERR.puts(<<~ERRMSG) | ||
ERROR: tailwindcss-rails does not support the #{platform} platform | ||
Please install tailwindcss following instructions at https://tailwindcss.com/docs/installation | ||
ERRMSG | ||
require "tailwindcss/commands" | ||
|
||
begin | ||
command = [Tailwindcss::Commands.executable, *ARGV] | ||
puts command.inspect | ||
if Gem.win_platform? | ||
# use system rather than exec as exec inexplicably fails to find the executable on Windows | ||
# see related https://github.com/rubys/sprockets-esbuild/pull/4 | ||
system(*command, exception: true) | ||
else | ||
exec(*command) | ||
end | ||
rescue Tailwindcss::Commands::UnsupportedPlatformException, Tailwindcss::Commands::ExecutableNotFoundException => e | ||
STDERR.puts("ERROR: " + e.message) | ||
exit 1 | ||
end | ||
|
||
exe_path = Dir.glob(File.join(__dir__, "*", "tailwindcss")).find do |f| | ||
Gem::Platform.match(File.basename(File.dirname(f))) | ||
end | ||
if exe_path.nil? | ||
STDERR.puts(<<~ERRMSG) | ||
ERROR: Cannot find the tailwindcss executable for #{platform} in #{__dir__} | ||
If you're using bundler, please make sure you're on the latest bundler version: | ||
gem install bundler | ||
bundle update --bundler | ||
Then make sure your lock file includes this platform by running: | ||
bundle lock --add-platform #{platform} | ||
bundle install | ||
See `bundle lock --help` output for details. | ||
If you're still seeing this message after taking those steps, try running | ||
`bundle config` and ensure `force_ruby_platform` isn't set to `true`. See | ||
https://github.com/rails/tailwindcss-rails#check-bundle_force_ruby_platform | ||
for more details. | ||
ERRMSG | ||
exit 1 | ||
end | ||
|
||
command = Shellwords.join([exe_path, ARGV].flatten) | ||
puts "+ #{command}" | ||
exec(command) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
module Tailwindcss | ||
end | ||
|
||
require "tailwindcss/upstream" | ||
require "tailwindcss/version" | ||
require "tailwindcss/engine" | ||
require_relative "tailwindcss/upstream" | ||
require_relative "tailwindcss/version" | ||
require_relative "tailwindcss/engine" | ||
require_relative "tailwindcss/commands" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
require_relative "upstream" | ||
|
||
module Tailwindcss | ||
module Commands | ||
# raised when the host platform is not supported by upstream tailwindcss's binary releases | ||
class UnsupportedPlatformException < StandardError | ||
end | ||
|
||
# raised when the tailwindcss executable could not be found where we expected it to be | ||
class ExecutableNotFoundException < StandardError | ||
end | ||
|
||
class << self | ||
def platform | ||
[:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-") | ||
end | ||
|
||
def executable( | ||
exe_path: File.expand_path(File.join(__dir__, "..", "..", "exe")) | ||
) | ||
if Tailwindcss::Upstream::NATIVE_PLATFORMS.keys.none? { |p| Gem::Platform.match(p) } | ||
raise UnsupportedPlatformException, <<~MESSAGE | ||
tailwindcss-rails does not support the #{platform} platform | ||
Please install tailwindcss following instructions at https://tailwindcss.com/docs/installation | ||
MESSAGE | ||
end | ||
|
||
exe_path = Dir.glob(File.expand_path(File.join(exe_path, "*", "tailwindcss"))).find do |f| | ||
Gem::Platform.match(File.basename(File.dirname(f))) | ||
end | ||
|
||
if exe_path.nil? | ||
raise ExecutableNotFoundException, <<~MESSAGE | ||
Cannot find the tailwindcss executable for #{platform} in #{exe_path} | ||
If you're using bundler, please make sure you're on the latest bundler version: | ||
gem install bundler | ||
bundle update --bundler | ||
Then make sure your lock file includes this platform by running: | ||
bundle lock --add-platform #{platform} | ||
bundle install | ||
See `bundle lock --help` output for details. | ||
If you're still seeing this message after taking those steps, try running | ||
`bundle config` and ensure `force_ruby_platform` isn't set to `true`. See | ||
https://github.com/rails/tailwindcss-rails#check-bundle_force_ruby_platform | ||
for more details. | ||
MESSAGE | ||
end | ||
|
||
exe_path | ||
end | ||
|
||
def compile_command(**kwargs) | ||
[ | ||
executable(**kwargs), | ||
"-i", Rails.root.join("app/assets/stylesheets/application.tailwind.css").to_s, | ||
"-o", Rails.root.join("app/assets/builds/tailwind.css").to_s, | ||
"-c", Rails.root.join("config/tailwind.config.js").to_s, | ||
"--minify", | ||
] | ||
end | ||
|
||
def watch_command(**kwargs) | ||
compile_command(**kwargs) << "-w" | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
require "test_helper" | ||
require "minitest/mock" | ||
|
||
class Tailwindcss::CommandsTest < ActiveSupport::TestCase | ||
test ".platform is a string containing just the cpu and os (not the version)" do | ||
expected = "#{Gem::Platform.local.cpu}-#{Gem::Platform.local.os}" | ||
assert_equal(expected, Tailwindcss::Commands.platform) | ||
end | ||
|
||
def mock_exe_directory(platform) | ||
Dir.mktmpdir do |dir| | ||
FileUtils.mkdir(File.join(dir, platform)) | ||
path = File.join(dir, platform, "tailwindcss") | ||
FileUtils.touch(path) | ||
Gem::Platform.stub(:match, true) do | ||
yield(dir, path) | ||
end | ||
end | ||
end | ||
|
||
test ".executable returns the absolute path to the binary" do | ||
mock_exe_directory("sparc-solaris2.8") do |dir, executable| | ||
expected = File.expand_path(File.join(dir, "sparc-solaris2.8", "tailwindcss")) | ||
assert_equal(expected, executable, "assert on setup") | ||
assert_equal(expected, Tailwindcss::Commands.executable(exe_path: dir)) | ||
end | ||
end | ||
|
||
test ".executable raises UnsupportedPlatformException when we're not on a supported platform" do | ||
Gem::Platform.stub(:match, false) do # nothing is supported | ||
assert_raises(Tailwindcss::Commands::UnsupportedPlatformException) do | ||
Tailwindcss::Commands.executable | ||
end | ||
end | ||
end | ||
|
||
test ".executable raises ExecutableNotFoundException when we can't find the executable we expect" do | ||
Dir.mktmpdir do |dir| # empty directory | ||
assert_raises(Tailwindcss::Commands::ExecutableNotFoundException) do | ||
Tailwindcss::Commands.executable(exe_path: dir) | ||
end | ||
end | ||
end | ||
|
||
test ".compile_command" do | ||
mock_exe_directory("sparc-solaris2.8") do |dir, executable| | ||
Rails.stub(:root, File) do # Rails.root won't work in this test suite | ||
actual = Tailwindcss::Commands.compile_command(exe_path: dir) | ||
assert_kind_of(Array, actual) | ||
assert_equal(executable, actual.first) | ||
end | ||
end | ||
end | ||
|
||
test ".watch_command" do | ||
mock_exe_directory("sparc-solaris2.8") do |dir, executable| | ||
Rails.stub(:root, File) do # Rails.root won't work in this test suite | ||
actual = Tailwindcss::Commands.watch_command(exe_path: dir) | ||
assert_kind_of(Array, actual) | ||
assert_equal(executable, actual.first) | ||
assert_includes(actual, "-w") | ||
end | ||
end | ||
end | ||
end |