diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db04fb3f..78413ae9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,14 +20,13 @@ jobs: strategy: fail-fast: false matrix: - ruby: ["2.7", "3.0", "3.1", "3.2", "3.3", "head"] + ruby: ["3.1", "3.2", "3.3", "head"] steps: - uses: actions/checkout@v4 - run: rm Gemfile.lock - uses: ruby/setup-ruby@v1 with: ruby-version: ${{matrix.ruby}} - rubygems: "3.4.22" # last version to support Ruby 2.7 bundler: latest bundler-cache: true - name: Run tests diff --git a/.github/workflows/gem-install.yml b/.github/workflows/gem-install.yml deleted file mode 100644 index eb1300d6..00000000 --- a/.github/workflows/gem-install.yml +++ /dev/null @@ -1,153 +0,0 @@ -name: Native Gems -concurrency: - group: "${{github.workflow}}-${{github.ref}}" - cancel-in-progress: true -on: - workflow_dispatch: - push: - branches: - - main - tags: - - v*.*.* - pull_request: - types: [opened, synchronize] - branches: - - '*' - -jobs: - package: - strategy: - fail-fast: false - matrix: - platform: ["ruby", "x64-mingw32", "x64-mingw-ucrt", "x86_64-darwin", "arm64-darwin", "x86_64-linux", "arm-linux"] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: rm Gemfile.lock - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.2" - bundler: latest - bundler-cache: true - - run: "bundle exec rake gem:${{matrix.platform}}" - - uses: actions/upload-artifact@v4 - with: - name: gem-${{matrix.platform}} - path: pkg - retention-days: 1 - - vanilla-install: - needs: ["package"] - runs-on: ubuntu-latest - steps: - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.2" - - uses: actions/download-artifact@v4 - with: - name: gem-ruby - path: pkg - - run: "gem install pkg/tailwindcss-rails-*.gem" - - run: "tailwindcss 2>&1 | fgrep 'ERROR: Cannot find the tailwindcss executable'" - - linux-install: - needs: ["package"] - runs-on: ubuntu-latest - steps: - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.2" - - uses: actions/download-artifact@v4 - with: - name: gem-x86_64-linux - path: pkg - - run: "gem install pkg/tailwindcss-rails-*.gem" - - run: "tailwindcss --help" - - linux-musl-install: - needs: ["package"] - runs-on: ubuntu-latest - container: - image: ruby:3.2-alpine - steps: - - uses: actions/download-artifact@v4 - with: - name: gem-x86_64-linux - path: pkg - - run: "apk add build-base" # to compile racc, etc. - - run: "gem update --system" # let's make sure the latest is working for us (upstream test, see #200) - - run: "gem install pkg/tailwindcss-rails-*.gem" - - run: "tailwindcss --help" - - linux-arm-install: - needs: ["package"] - runs-on: ubuntu-latest - steps: - - uses: actions/download-artifact@v4 - with: - name: gem-arm-linux - path: pkg - - run: | - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker run --rm -v "$(pwd):/test" -w /test --platform=linux/arm/v7 ruby:3.2 \ - /bin/bash -c " - set -ex - gem install pkg/tailwindcss-rails-*.gem - tailwindcss --help - " - - darwin-x86_64-install: - needs: ["package"] - runs-on: macos-13 - steps: - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.2" - - uses: actions/download-artifact@v4 - with: - name: gem-x86_64-darwin - path: pkg - - run: "gem install pkg/tailwindcss-rails-*.gem" - - run: "tailwindcss --help" - - darwin-arm64-install: - needs: ["package"] - runs-on: macos-14 - steps: - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.2" - - uses: actions/download-artifact@v4 - with: - name: gem-arm64-darwin - path: pkg - - run: "gem install pkg/tailwindcss-rails-*.gem" - - run: "tailwindcss --help" - - windows-install: - needs: ["package"] - runs-on: windows-latest - steps: - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.0" - - uses: actions/download-artifact@v4 - with: - name: gem-x64-mingw32 - path: pkg - - run: "gem install pkg/tailwindcss-rails-*.gem" - - run: "tailwindcss --help" - - windows-ucrt-install: - needs: ["package"] - runs-on: windows-2022 - steps: - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.2" - - uses: actions/download-artifact@v4 - with: - name: gem-x64-mingw-ucrt - path: pkg - - run: "gem install pkg/tailwindcss-rails-*.gem" - - run: "tailwindcss --help" diff --git a/.gitignore b/.gitignore index b2a14451..de5dc1de 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,3 @@ *.gem .idea/ **/tmp/ -/exe/*/tailwindcss diff --git a/CHANGELOG.md b/CHANGELOG.md index 63d2e03c..19fcccb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## next / unreleased + +### Notable changes + +* The upstream `tailwindcss` executable has been extracted from this gem into a new dependency, `tailwindcss-ruby`. + + In advance of the upcoming TailwindCSS v4 release, we are decoupling the `tailwindcss` executable + from the Rails integration. This will allow users to upgrade TailwindCSS at a time of their + choosing, and allow early adopters to start using the beta releases. + + ## v2.7.7 / 2024-10-02 * Proactively support changes to Rails's authentication templates shipping in Rails 8.0.0.beta2 (which is not yet released). (#407, #408) @seanpdoyle @flavorjones diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8dfb3c45..debab121 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,23 +23,14 @@ gem "tailwindcss-rails", path: "/path/to/tailwindcss-rails" ``` -## Updating to the latest upstream tailwindcss version - -Update `lib/tailwindcss/upstream.rb` with the upstream version. - -Run `bundle exec rake clobber` then `bundle exec rake download` to ensure the tailwindcss binaries can be downloaded, and that you have the correct versions on local disk. - ## Cutting a release of tailwindcss-rails - bump the version - [ ] update `lib/tailwindcss/version.rb` - [ ] update `CHANGELOG.md` - [ ] commit and create a git tag -- build the native gems: - - [ ] `bundle exec rake clobber` to clean up possibly-old tailwindcss executables - - [ ] `bundle exec rake package` - push - - [ ] `for g in pkg/*.gem ; do gem push $g ; done` + - [ ] `gem push pkg/*.gem` - [ ] `git push && git push --tags` - announce - [ ] create a release at https://github.com/rails/tailwindcss-rails/releases diff --git a/Gemfile.lock b/Gemfile.lock index 0c679b3c..d486fe4c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,6 +3,7 @@ PATH specs: tailwindcss-rails (2.7.7) railties (>= 7.0.0) + tailwindcss-ruby GEM remote: https://rubygems.org/ @@ -59,13 +60,13 @@ GEM erubi (1.13.0) globalid (1.2.1) activesupport (>= 6.1) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) io-console (0.7.2) - irb (1.14.0) + irb (1.14.1) rdoc (>= 4.0.0) reline (>= 0.4.2) - logger (1.6.0) + logger (1.6.1) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -75,9 +76,8 @@ GEM net-pop net-smtp mini_mime (1.1.5) - mini_portile2 (2.8.7) minitest (5.25.1) - net-imap (0.4.14) + net-imap (0.4.16) date net-protocol net-pop (0.1.2) @@ -86,11 +86,14 @@ GEM timeout net-smtp (0.5.0) net-protocol - nokogiri (1.16.7) - mini_portile2 (~> 2.8.2) + nokogiri (1.16.7-aarch64-linux) + racc (~> 1.4) + nokogiri (1.16.7-arm-linux) racc (~> 1.4) nokogiri (1.16.7-arm64-darwin) racc (~> 1.4) + nokogiri (1.16.7-x86-linux) + racc (~> 1.4) nokogiri (1.16.7-x86_64-darwin) racc (~> 1.4) nokogiri (1.16.7-x86_64-linux) @@ -124,21 +127,29 @@ GEM rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) - reline (0.5.9) + reline (0.5.10) io-console (~> 0.5) securerandom (0.3.1) stringio (3.1.1) - thor (1.3.1) + tailwindcss-ruby (3.4.13) + tailwindcss-ruby (3.4.13-aarch64-linux) + tailwindcss-ruby (3.4.13-arm-linux) + tailwindcss-ruby (3.4.13-arm64-darwin) + tailwindcss-ruby (3.4.13-x86_64-darwin) + tailwindcss-ruby (3.4.13-x86_64-linux) + thor (1.3.2) timeout (0.4.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) useragent (0.16.10) webrick (1.8.2) - zeitwerk (2.6.17) + zeitwerk (2.6.18) PLATFORMS + aarch64-linux + arm-linux arm64-darwin - ruby + x86-linux x86_64-darwin x86_64-linux @@ -148,4 +159,4 @@ DEPENDENCIES tailwindcss-rails! BUNDLED WITH - 2.5.4 + 2.5.20 diff --git a/LICENSE-DEPENDENCIES b/LICENSE-DEPENDENCIES deleted file mode 100644 index 93a34024..00000000 --- a/LICENSE-DEPENDENCIES +++ /dev/null @@ -1,26 +0,0 @@ -tailwindcss-rails may redistribute executables from the https://github.com/tailwindlabs/tailwindcss project - -The license for that software can be found at https://github.com/tailwindlabs/tailwindcss/blob/master/LICENSE which is reproduced here for your convenience: - - MIT License - - Copyright (c) Adam Wathan - Copyright (c) Jonathan Reinink - - 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/README.md b/README.md index 01fa023b..2887ab3f 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ - [Installation](#installation) + * [Choosing a specific version of `tailwindcss`](#choosing-a-specific-version-of-tailwindcss) * [Using a local installation of `tailwindcss`](#using-a-local-installation-of-tailwindcss) - [Developing with Tailwindcss](#developing-with-tailwindcss) * [Configuration and commands](#configuration-and-commands) @@ -17,7 +18,7 @@ * [Using with PostCSS](#using-with-postcss) * [Custom inputs or outputs](#custom-inputs-or-outputs) - [Troubleshooting](#troubleshooting) - * [Lost keystrokes or hanging when using `ruby/debug` with the Puma plugin](#lost-keystrokes-or-hanging-when-using-rubydebug-with-the-puma-plugin) + * [Lost keystrokes or hanging when using terminal-based debugging tools (e.g. IRB, Pry, `ruby/debug`...etc.) with the Puma plugin](#lost-keystrokes-or-hanging-when-using-terminal-based-debugging-tools-eg-irb-pry-rubydebugetc-with-the-puma-plugin) * [Running in a docker container exits prematurely](#running-in-a-docker-container-exits-prematurely) * [Conflict with sassc-rails](#conflict-with-sassc-rails) * [Class names must be spelled out](#class-names-must-be-spelled-out) @@ -35,34 +36,23 @@ With Rails 7 you can generate a new application preconfigured with Tailwind by u 1. Run `./bin/bundle add tailwindcss-rails` 2. Run `./bin/rails tailwindcss:install` -This gem wraps [the standalone executable version](https://tailwindcss.com/blog/standalone-cli) of the Tailwind CSS v3 framework. These executables are platform specific, so there are actually separate underlying gems per platform, but the correct gem will automatically be picked for your platform. +This gem depends on the `tailwindcss-ruby` gem to install a working tailwind executable. -Supported platforms are: -- arm64-darwin (macos-arm64) -- x64-mingw32 (windows-x64) -- x64-mingw-ucr (windows-x64) -- x86_64-darwin (macos-x64) -- x86_64-linux (linux-x64) -- aarch64-linux (linux-arm64) -- arm-linux (linux-armv7) +### Choosing a specific version of `tailwindcss` +The `tailwindcss-ruby` gem is declared as a floating dependency of this gem, so by default you will get the most recent stable version. However, you can select a specific version of tailwind by pinning that gem to the analogous version in your application's `Gemfile`. For example, -### Using a local installation of `tailwindcss` - -If you are not able to use the vendored standalone executables (for example, if you're on an unsupported platform), you can use a local installation of the `tailwindcss` executable by setting an environment variable named `TAILWINDCSS_INSTALL_DIR` to the directory path containing the executable. - -For example, if you've installed `tailwindcss` so that the executable is found at `/path/to/node_modules/bin/tailwindcss`, then you should set your environment variable like so: +``` ruby +gem "tailwindcss-rails" -``` sh -TAILWINDCSS_INSTALL_DIR=/path/to/node_modules/bin +# pin to tailwindcss version 3.4.13 +gem "tailwindcss-ruby", "3.4.13" ``` -or, for relative paths like `./node_modules/.bin/tailwindcss`: +### Using a local installation of `tailwindcss` -``` sh -TAILWINDCSS_INSTALL_DIR=node_modules/.bin -``` +You can also use a local (npm-based) installation if you prefer, please go to https://github.com/flavorjones/tailwindcss-ruby for more information. ## Developing with Tailwindcss @@ -206,41 +196,7 @@ For Tailwind to work, your class names need to be spelled out. If you need to ma ### `ERROR: Cannot find the tailwindcss executable` for supported platform -Some users are reporting this error even when running on one of the supported native platforms: - -- arm64-darwin -- x64-mingw32 -- x64-mingw-ucrt -- x86_64-darwin -- x86_64-linux -- aarch64-linux - -#### Check Bundler PLATFORMS - -A possible cause of this is that Bundler has not been told to include native gems for your current platform. Please check your `Gemfile.lock` file to see whether your native platform is included in the `PLATFORMS` section. If necessary, run: - -``` sh -bundle lock --add-platform -``` - -and re-bundle. - - -#### Check BUNDLE_FORCE_RUBY_PLATFORM - -Another common cause of this is that bundler is configured to always use the "ruby" platform via the -`BUNDLE_FORCE_RUBY_PLATFORM` config parameter being set to `true`. Please remove this configuration: - -``` sh -bundle config unset force_ruby_platform -# or -bundle config set --local force_ruby_platform false -``` - -and re-bundle. - -See https://bundler.io/man/bundle-config.1.html for more information. - +See https://github.com/flavorjones/tailwindcss-ruby for help. ### Using asset-pipeline assets @@ -280,5 +236,4 @@ Or, if you do want to keep using the asset pipeline in parallel, make sure to re ## License Tailwind for Rails is released under the [MIT License](https://opensource.org/licenses/MIT). -Tailwind CSS is released under the [MIT License](https://opensource.org/licenses/MIT). The Inter font is released under the [SIL Open Font License, Version 1.1](https://github.com/rsms/inter/blob/master/LICENSE.txt). diff --git a/exe/tailwindcss b/exe/tailwindcss deleted file mode 100755 index ce4a4437..00000000 --- a/exe/tailwindcss +++ /dev/null @@ -1,19 +0,0 @@ -#! /usr/bin/env ruby -# because rubygems shims assume a gem's executables are Ruby - -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 diff --git a/lib/tailwindcss-rails.rb b/lib/tailwindcss-rails.rb index 112809c5..2b86ff1c 100644 --- a/lib/tailwindcss-rails.rb +++ b/lib/tailwindcss-rails.rb @@ -1,7 +1,6 @@ module Tailwindcss end -require_relative "tailwindcss/upstream" require_relative "tailwindcss/version" require_relative "tailwindcss/engine" require_relative "tailwindcss/commands" diff --git a/lib/tailwindcss/commands.rb b/lib/tailwindcss/commands.rb index 08b70d33..26c5178a 100644 --- a/lib/tailwindcss/commands.rb +++ b/lib/tailwindcss/commands.rb @@ -1,81 +1,11 @@ -require_relative "upstream" +require "tailwindcss/ruby" module Tailwindcss module Commands - DEFAULT_DIR = File.expand_path(File.join(__dir__, "..", "..", "exe")) - GEM_NAME = "tailwindcss-rails" - - # 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 - - # raised when TAILWINDCSS_INSTALL_DIR does not exist - class DirectoryNotFoundException < StandardError - end - class << self - def platform - [:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-") - end - - def executable(exe_path: DEFAULT_DIR) - tailwindcss_install_dir = ENV["TAILWINDCSS_INSTALL_DIR"] - if tailwindcss_install_dir - if File.directory?(tailwindcss_install_dir) - warn "NOTE: using TAILWINDCSS_INSTALL_DIR to find tailwindcss executable: #{tailwindcss_install_dir}" - exe_path = tailwindcss_install_dir - exe_file = File.expand_path(File.join(tailwindcss_install_dir, "tailwindcss")) - else - raise DirectoryNotFoundException, <<~MESSAGE - TAILWINDCSS_INSTALL_DIR is set to #{tailwindcss_install_dir}, but that directory does not exist. - MESSAGE - end - else - if Tailwindcss::Upstream::NATIVE_PLATFORMS.keys.none? { |p| Gem::Platform.match_gem?(Gem::Platform.new(p), GEM_NAME) } - 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_file = Dir.glob(File.expand_path(File.join(exe_path, "*", "tailwindcss"))).find do |f| - Gem::Platform.match_gem?(Gem::Platform.new(File.basename(File.dirname(f))), GEM_NAME) - end - end - - if exe_file.nil? || !File.exist?(exe_file) - 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_file - end - def compile_command(debug: false, **kwargs) command = [ - executable(**kwargs), + Tailwindcss::Ruby.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, diff --git a/lib/tailwindcss/upstream.rb b/lib/tailwindcss/upstream.rb index a2399140..358db1c0 100644 --- a/lib/tailwindcss/upstream.rb +++ b/lib/tailwindcss/upstream.rb @@ -1,17 +1,6 @@ module Tailwindcss - # constants describing the upstream tailwindcss project module Upstream - VERSION = "v3.4.13" - - # rubygems platform name => upstream release filename - NATIVE_PLATFORMS = { - "arm64-darwin" => "tailwindcss-macos-arm64", - "x64-mingw32" => "tailwindcss-windows-x64.exe", - "x64-mingw-ucrt" => "tailwindcss-windows-x64.exe", - "x86_64-darwin" => "tailwindcss-macos-x64", - "x86_64-linux" => "tailwindcss-linux-x64", - "aarch64-linux" => "tailwindcss-linux-arm64", - "arm-linux" => "tailwindcss-linux-armv7", - } + VERSION = Tailwindcss::Ruby::Upstream::VERSION + deprecate_constant :VERSION end end diff --git a/package/tailwindcss-v3.4.7-checksums.txt b/package/tailwindcss-v3.4.7-checksums.txt deleted file mode 100644 index 0d5079d3..00000000 --- a/package/tailwindcss-v3.4.7-checksums.txt +++ /dev/null @@ -1,6 +0,0 @@ -8f8b5cd32fc35843ec24bbcdb214e972df6a9c485bf4d4fd049140fbcc766bcc tailwindcss-macos-x64 -0eda3bc8fe90506b7b9e5cb930312042730b76a7f18026d19414d48fbb3100ed tailwindcss-macos-arm64 -3c2321e66718f39e48388707ce8b587946338f82ef3d636c8ee19670514d3394 tailwindcss-linux-x64 -4146a6f534fffb27f95de9926d7806a6e432eeb7e55cb8850a57c4e062689c2b tailwindcss-linux-arm64 -85c4c71618f0bfcdb0edf246ed6ee394a7addb8af34ed7dbdce9298279243994 tailwindcss-linux-armv7 -e6891c3d181314b7d78382fe93121ff8957a9dbb1132a47afb064c0ed1f906e4 tailwindcss-windows-x64.exe diff --git a/rakelib/package.rake b/rakelib/package.rake deleted file mode 100644 index 7cab2924..00000000 --- a/rakelib/package.rake +++ /dev/null @@ -1,149 +0,0 @@ -# coding: utf-8 -# -# Rake tasks to manage native gem packages with binary executables from tailwindlabs/tailwindcss -# -# TL;DR: run "rake package" -# -# The native platform gems (defined by Tailwindcss::Upstream::NATIVE_PLATFORMS) will each contain -# two files in addition to what the vanilla ruby gem contains: -# -# exe/ -# ├── tailwindcss # generic ruby script to find and run the binary -# └── / -# └── tailwindcss # the tailwindcss binary executable -# -# The ruby script `exe/tailwindcss` is installed into the user's path, and it simply locates the -# binary and executes it. Note that this script is required because rubygems requires that -# executables declared in a gemspec must be Ruby scripts. -# -# Windows support note: we ship the same executable in two gems, the `x64-mingw32` and -# `x64-mingw-ucrt` flavors because Ruby < 3.1 uses the MSCVRT runtime libraries, and Ruby >= 3.1 -# uses the UCRT runtime libraries. You can read more about this change here: -# -# https://rubyinstaller.org/2021/12/31/rubyinstaller-3.1.0-1-released.html -# -# As a concrete example, an x86_64-linux system will see these files on disk after installing -# tailwindcss-rails-1.x.x-x86_64-linux.gem: -# -# exe/ -# ├── tailwindcss -# └── x86_64-linux/ -# └── tailwindcss -# -# So the full set of gem files created will be: -# -# - pkg/tailwindcss-rails-1.0.0.gem -# - pkg/tailwindcss-rails-1.0.0-aarch64-linux.gem -# - pkg/tailwindcss-rails-1.0.0-arm64-darwin.gem -# - pkg/tailwindcss-rails-1.0.0-x64-mingw32.gem -# - pkg/tailwindcss-rails-1.0.0-x64-mingw-ucrt.gem -# - pkg/tailwindcss-rails-1.0.0-x86_64-darwin.gem -# - pkg/tailwindcss-rails-1.0.0-x86_64-linux.gem -# -# Note that in addition to the native gems, a vanilla "ruby" gem will also be created without -# either the `exe/tailwindcss` script or a binary executable present. -# -# -# New rake tasks created: -# -# - rake gem:ruby # Build the ruby gem -# - rake gem:aarch64-linux # Build the aarch64-linux gem -# - rake gem:arm64-darwin # Build the arm64-darwin gem -# - rake gem:x64-mingw32 # Build the x64-mingw32 gem -# - rake gem:x64-mingw-ucrt # Build the x64-mingw-ucrt gem -# - rake gem:x86_64-darwin # Build the x86_64-darwin gem -# - rake gem:x86_64-linux # Build the x86_64-linux gem -# - rake download # Download all tailwindcss binaries -# -# Modified rake tasks: -# -# - rake gem # Build all the gem files -# - rake package # Build all the gem files (same as `gem`) -# - rake repackage # Force a rebuild of all the gem files -# -# Note also that the binary executables will be lazily downloaded when needed, but you can -# explicitly download them with the `rake download` command. -# -require "rubygems/package_task" -require "open-uri" -require_relative "../lib/tailwindcss/upstream" - -def tailwindcss_download_url(filename) - "https://github.com/tailwindlabs/tailwindcss/releases/download/#{Tailwindcss::Upstream::VERSION}/#{filename}" -end - -TAILWINDCSS_RAILS_GEMSPEC = Bundler.load_gemspec("tailwindcss-rails.gemspec") - -# prepend the download task before the Gem::PackageTask tasks -task :package => :download - -gem_path = Gem::PackageTask.new(TAILWINDCSS_RAILS_GEMSPEC).define -desc "Build the ruby gem" -task "gem:ruby" => [gem_path] - -exepaths = [] -Tailwindcss::Upstream::NATIVE_PLATFORMS.each do |platform, filename| - TAILWINDCSS_RAILS_GEMSPEC.dup.tap do |gemspec| - exedir = File.join(gemspec.bindir, platform) # "exe/x86_64-linux" - exepath = File.join(exedir, "tailwindcss") # "exe/x86_64-linux/tailwindcss" - exepaths << exepath - - # modify a copy of the gemspec to include the native executable - gemspec.platform = platform - gemspec.files += [exepath, "LICENSE-DEPENDENCIES"] - - # create a package task - gem_path = Gem::PackageTask.new(gemspec).define - desc "Build the #{platform} gem" - task "gem:#{platform}" => [gem_path] - - directory exedir - file exepath => [exedir] do - release_url = tailwindcss_download_url(filename) - warn "Downloading #{exepath} from #{release_url} ..." - - # lazy, but fine for now. - URI.open(release_url) do |remote| - File.open(exepath, "wb") do |local| - local.write(remote.read) - end - end - FileUtils.chmod(0755, exepath, verbose: true) - end - end -end - -desc "Validate checksums for tailwindcss binaries" -task "check" => exepaths do - sha_filename = File.absolute_path("../package/tailwindcss-#{Tailwindcss::Upstream::VERSION}-checksums.txt", __dir__) - sha_url = if File.exist?(sha_filename) - sha_filename - else - sha_url = tailwindcss_download_url("sha256sums.txt") - end - gemspec = TAILWINDCSS_RAILS_GEMSPEC - - checksums = URI.open(sha_url).each_line.map do |line| - checksum, file = line.split - [File.basename(file), checksum] - end.to_h - - Tailwindcss::Upstream::NATIVE_PLATFORMS.each do |platform, filename| - exedir = File.join(gemspec.bindir, platform) # "exe/x86_64-linux" - exepath = File.join(exedir, "tailwindcss") # "exe/x86_64-linux/tailwindcss" - - local_sha256 = Digest::SHA256.file(exepath).hexdigest - remote_sha256 = checksums.fetch(filename) - - if local_sha256 == remote_sha256 - puts "Checksum OK for #{exepath} (#{local_sha256})" - else - abort "Checksum mismatch for #{exepath} (#{local_sha256} != #{remote_sha256})" - end - end -end - -desc "Download all tailwindcss binaries" -task "download" => :check - -CLOBBER.add(exepaths.map { |p| File.dirname(p) }) diff --git a/tailwindcss-rails.gemspec b/tailwindcss-rails.gemspec index 7535ccc7..8d893029 100644 --- a/tailwindcss-rails.gemspec +++ b/tailwindcss-rails.gemspec @@ -17,8 +17,7 @@ Gem::Specification.new do |spec| spec.required_rubygems_version = ">= 3.2.0" # for Gem::Platform#match_gem? spec.files = Dir["{app,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - spec.bindir = "exe" - spec.executables << "tailwindcss" spec.add_dependency "railties", ">= 7.0.0" + spec.add_dependency "tailwindcss-ruby" end diff --git a/test/integration/user_journey_test.sh b/test/integration/user_journey_test.sh index 1877e871..00818f2d 100755 --- a/test/integration/user_journey_test.sh +++ b/test/integration/user_journey_test.sh @@ -11,9 +11,6 @@ bundle remove actionmailer bundle add rails --skip-install ${RAILSOPTS:-} bundle install -# fetch the upstream executables -bundle exec rake download - # do our work a directory with spaces in the name (#176, #184) rm -rf "My Workspace" mkdir "My Workspace" diff --git a/test/lib/tailwindcss/commands_test.rb b/test/lib/tailwindcss/commands_test.rb index 0be78894..a273e45e 100644 --- a/test/lib/tailwindcss/commands_test.rb +++ b/test/lib/tailwindcss/commands_test.rb @@ -2,209 +2,93 @@ require "minitest/mock" class Tailwindcss::CommandsTest < ActiveSupport::TestCase - def mock_exe_directory(platform) - Dir.mktmpdir do |dir| - FileUtils.mkdir(File.join(dir, platform)) - path = File.join(dir, platform, "tailwindcss") - FileUtils.touch(path) - stub_gem_platform_match_gem(true) do - yield(dir, path) - end - end - end - - def stub_gem_platform_match_gem(value) - assert_respond_to(Gem::Platform, :match_gem?) - Gem::Platform.stub(:match_gem?, value) do - yield - end - end - - def mock_local_tailwindcss_install - Dir.mktmpdir do |dir| - path = File.join(dir, "tailwindcss") - FileUtils.touch(path) - yield(dir, path) - end - end - - 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 - - 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 - stub_gem_platform_match_gem(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 + attr_accessor :executable - test ".executable returns the executable in TAILWINDCSS_INSTALL_DIR when no packaged binary exists" do - mock_local_tailwindcss_install do |local_install_dir, expected| - result = nil - begin - ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir - assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do - result = Tailwindcss::Commands.executable(exe_path: "/does/not/exist") - end - ensure - ENV["TAILWINDCSS_INSTALL_DIR"] = nil - end - assert_equal(expected, result) - end + def setup + super + @executable = Tailwindcss::Ruby.executable end - test ".executable returns the executable in TAILWINDCSS_INSTALL_DIR when we're not on a supported platform" do - stub_gem_platform_match_gem(false) do # nothing is supported - mock_local_tailwindcss_install do |local_install_dir, expected| - result = nil - begin - ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir - assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do - result = Tailwindcss::Commands.executable - end - ensure - ENV["TAILWINDCSS_INSTALL_DIR"] = nil - end - assert_equal(expected, result) - end + test ".compile_command" do + Rails.stub(:root, File) do # Rails.root won't work in this test suite + actual = Tailwindcss::Commands.compile_command + assert_kind_of(Array, actual) + assert_equal(executable, actual.first) + assert_includes(actual, "--minify") + + actual = Tailwindcss::Commands.compile_command(debug: true) + assert_kind_of(Array, actual) + assert_equal(executable, actual.first) + refute_includes(actual, "--minify") end end - test ".executable returns the executable in TAILWINDCSS_INSTALL_DIR even when a packaged binary exists" do - mock_exe_directory("sparc-solaris2.8") do |dir, _executable| - mock_local_tailwindcss_install do |local_install_dir, expected| - result = nil - begin - ENV["TAILWINDCSS_INSTALL_DIR"] = local_install_dir - assert_output(nil, /using TAILWINDCSS_INSTALL_DIR/) do - result = Tailwindcss::Commands.executable(exe_path: dir) - end - ensure - ENV["TAILWINDCSS_INSTALL_DIR"] = nil - end - assert_equal(expected, result) + test ".compile_command when Rails compression is on" do + Rails.stub(:root, File) do # Rails.root won't work in this test suite + Tailwindcss::Commands.stub(:rails_css_compressor?, true) do + actual = Tailwindcss::Commands.compile_command + assert_kind_of(Array, actual) + refute_includes(actual, "--minify") end - end - end - test ".executable raises ExecutableNotFoundException is TAILWINDCSS_INSTALL_DIR is set to a nonexistent dir" do - begin - ENV["TAILWINDCSS_INSTALL_DIR"] = "/does/not/exist" - assert_raises(Tailwindcss::Commands::DirectoryNotFoundException) do - Tailwindcss::Commands.executable + Tailwindcss::Commands.stub(:rails_css_compressor?, false) do + actual = Tailwindcss::Commands.compile_command + assert_kind_of(Array, actual) + assert_includes(actual, "--minify") end - ensure - ENV["TAILWINDCSS_INSTALL_DIR"] = nil 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) + test ".compile_command when postcss.config.js exists" do + Dir.mktmpdir do |tmpdir| + Rails.stub(:root, Pathname.new(tmpdir)) do # Rails.root won't work in this test suite + actual = Tailwindcss::Commands.compile_command assert_kind_of(Array, actual) assert_equal(executable, actual.first) - assert_includes(actual, "--minify") + refute_includes(actual, "--postcss") - actual = Tailwindcss::Commands.compile_command(exe_path: dir, debug: true) + config_file = Rails.root.join("config/postcss.config.js") + FileUtils.mkdir_p(Rails.root.join("config")) + FileUtils.touch(config_file) + actual = Tailwindcss::Commands.compile_command assert_kind_of(Array, actual) assert_equal(executable, actual.first) - refute_includes(actual, "--minify") - end - end - end - - test ".compile_command when Rails compression is on" do - mock_exe_directory("sparc-solaris2.8") do |dir, executable| - Rails.stub(:root, File) do # Rails.root won't work in this test suite - Tailwindcss::Commands.stub(:rails_css_compressor?, true) do - actual = Tailwindcss::Commands.compile_command(exe_path: dir) - assert_kind_of(Array, actual) - refute_includes(actual, "--minify") - end - - Tailwindcss::Commands.stub(:rails_css_compressor?, false) do - actual = Tailwindcss::Commands.compile_command(exe_path: dir) - assert_kind_of(Array, actual) - assert_includes(actual, "--minify") - end - end - end - end - - test ".compile_command when postcss.config.js exists" do - mock_exe_directory("sparc-solaris2.8") do |dir, executable| - Dir.mktmpdir do |tmpdir| - Rails.stub(:root, Pathname.new(tmpdir)) 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) - refute_includes(actual, "--postcss") - - config_file = Rails.root.join("config/postcss.config.js") - FileUtils.mkdir_p(Rails.root.join("config")) - FileUtils.touch(config_file) - actual = Tailwindcss::Commands.compile_command(exe_path: dir) - assert_kind_of(Array, actual) - assert_equal(executable, actual.first) - assert_includes(actual, "--postcss") - postcss_index = actual.index("--postcss") - assert_equal(actual[postcss_index + 1], config_file.to_s) - end + assert_includes(actual, "--postcss") + postcss_index = actual.index("--postcss") + assert_equal(actual[postcss_index + 1], config_file.to_s) 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") - refute_includes(actual, "-p") - assert_includes(actual, "--minify") - - actual = Tailwindcss::Commands.watch_command(exe_path: dir, debug: true) - assert_kind_of(Array, actual) - assert_equal(executable, actual.first) - assert_includes(actual, "-w") - refute_includes(actual, "-p") - refute_includes(actual, "--minify") - - actual = Tailwindcss::Commands.watch_command(exe_path: dir, poll: true) - assert_kind_of(Array, actual) - assert_equal(executable, actual.first) - assert_includes(actual, "-w") - refute_includes(actual, "always") - assert_includes(actual, "-p") - assert_includes(actual, "--minify") - - actual = Tailwindcss::Commands.watch_command(exe_path: dir, always: true) - assert_kind_of(Array, actual) - assert_equal(executable, actual.first) - assert_includes(actual, "-w") - assert_includes(actual, "always") - end + Rails.stub(:root, File) do # Rails.root won't work in this test suite + actual = Tailwindcss::Commands.watch_command + assert_kind_of(Array, actual) + assert_equal(executable, actual.first) + assert_includes(actual, "-w") + refute_includes(actual, "-p") + assert_includes(actual, "--minify") + + actual = Tailwindcss::Commands.watch_command(debug: true) + assert_kind_of(Array, actual) + assert_equal(executable, actual.first) + assert_includes(actual, "-w") + refute_includes(actual, "-p") + refute_includes(actual, "--minify") + + actual = Tailwindcss::Commands.watch_command(poll: true) + assert_kind_of(Array, actual) + assert_equal(executable, actual.first) + assert_includes(actual, "-w") + refute_includes(actual, "always") + assert_includes(actual, "-p") + assert_includes(actual, "--minify") + + actual = Tailwindcss::Commands.watch_command(always: true) + assert_kind_of(Array, actual) + assert_equal(executable, actual.first) + assert_includes(actual, "-w") + assert_includes(actual, "always") end end end