faster_path 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +1 -1
- data/Cargo.toml +1 -1
- data/README.md +12 -6
- data/Rakefile +7 -0
- data/ext/Rakefile +29 -3
- data/faster_path.gemspec +1 -1
- data/lib/faster_path/build_task.rb +10 -0
- data/lib/faster_path/prebuilt.rb +118 -0
- data/lib/faster_path/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fc913650b2f0738a6fd67abfadedea3bd40b91942a0743ef30e57ec8c976724d
|
|
4
|
+
data.tar.gz: 73316052dfde708cedc6ee10bfc41a63554411a02a8ad10e39bfd94d2280445e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 87fc380b17b8c7ce94a3d5cc1026fc41902257624c058eb4806eab4e6fa2a4b102f6dcc7819304888f8abdbf39f9b45b59ad4aa00ece6fc5622aa25d8404e5b6
|
|
7
|
+
data.tar.gz: '083f2de1d9e2852a56ecd1d44d3232da1b52a5975d9eb6e7de36ece4dcb91e69280daff0091d337d8b03bda33ed3a2a3b48c5334b3049b727c995481602875ac'
|
data/Cargo.lock
CHANGED
data/Cargo.toml
CHANGED
data/README.md
CHANGED
|
@@ -114,12 +114,16 @@ As mentioned earlier Sprockets, which handles assets, changed away from using `P
|
|
|
114
114
|
## Requirements
|
|
115
115
|
|
|
116
116
|
* Ruby 3.2, 3.3 or 3.4 (the Rust extension is built with [Rutie](https://github.com/danielpclark/rutie) 0.13, which supports these)
|
|
117
|
-
* Rust 1.71 or later
|
|
117
|
+
* Rust 1.71 or later, unless a prebuilt extension exists for your platform (see
|
|
118
|
+
[Installation](#installation)): `gem install` builds the extension with Cargo (through the
|
|
118
119
|
[rutie](https://rubygems.org/gems/rutie) gem's Rake task) and keeps only the built library
|
|
119
120
|
|
|
120
121
|
## Installation
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
Each [release](https://github.com/danielpclark/faster_path/releases) carries a prebuilt
|
|
124
|
+
extension for Ruby 3.4 on Linux x86_64, macOS (arm64 and x86_64) and Windows x64. On those,
|
|
125
|
+
`gem install` needs no Rust. Everywhere else (another Ruby version, OS or CPU), ensure Rust is
|
|
126
|
+
installed, with `cargo` on your `PATH`:
|
|
123
127
|
|
|
124
128
|
[Install Rust](https://www.rust-lang.org/tools/install)
|
|
125
129
|
|
|
@@ -130,7 +134,7 @@ curl -sSf https://sh.rustup.rs | sh
|
|
|
130
134
|
Add this line to your application's Gemfile:
|
|
131
135
|
|
|
132
136
|
```ruby
|
|
133
|
-
gem 'faster_path', '~> 0.5.
|
|
137
|
+
gem 'faster_path', '~> 0.5.1'
|
|
134
138
|
```
|
|
135
139
|
|
|
136
140
|
And then execute:
|
|
@@ -143,9 +147,11 @@ Or install it yourself as:
|
|
|
143
147
|
|
|
144
148
|
Installing compiles the Rust extension for the Ruby doing the installing ("Building native
|
|
145
149
|
extensions. This could take a while..."), which takes about a minute the first time while Cargo
|
|
146
|
-
fetches and builds the dependencies.
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
fetches and builds the dependencies. When Cargo is not found, the install downloads the release's
|
|
151
|
+
prebuilt extension for your platform instead (`faster_path-<version>-ruby<XY>-<os>-<cpu>.tar.gz`,
|
|
152
|
+
checked against its SHA-256 file) and fails with a message naming that file if there is none.
|
|
153
|
+
`FASTER_PATH_PREBUILT_URL` points the download at another directory holding the same files, for
|
|
154
|
+
mirrors or machines without access to GitHub.
|
|
149
155
|
|
|
150
156
|
## Visual Benchmarks
|
|
151
157
|
|
data/Rakefile
CHANGED
|
@@ -34,6 +34,13 @@ end
|
|
|
34
34
|
desc 'Build the Rust extension'
|
|
35
35
|
task build_lib: 'rutie:build'
|
|
36
36
|
|
|
37
|
+
desc 'Package the built extension as the prebuilt release asset for this platform, in pkg/'
|
|
38
|
+
task prebuilt: 'rutie:build' do
|
|
39
|
+
require 'faster_path/prebuilt'
|
|
40
|
+
FileUtils.mkdir_p('pkg')
|
|
41
|
+
puts FasterPath::Prebuilt.package(FasterPath::BuildTask.built_library, 'pkg')
|
|
42
|
+
end
|
|
43
|
+
|
|
37
44
|
desc 'Code Quality Check'
|
|
38
45
|
task :lint do
|
|
39
46
|
puts
|
data/ext/Rakefile
CHANGED
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
require 'fileutils'
|
|
2
2
|
require_relative '../lib/faster_path/build_task'
|
|
3
|
+
require_relative '../lib/faster_path/prebuilt'
|
|
3
4
|
|
|
4
5
|
FasterPath::BuildTask.define
|
|
5
6
|
|
|
6
|
-
#
|
|
7
|
-
# and removes the rest of Cargo's output from the
|
|
7
|
+
# Builds the extension, keeps the built library (in lib/faster_path, where
|
|
8
|
+
# FasterPath loads it from) and removes the rest of Cargo's output from the
|
|
9
|
+
# installed gem.
|
|
8
10
|
task install_library: 'rutie:build' do
|
|
9
11
|
FileUtils.mkdir_p(FasterPath::BuildTask::INSTALLED_LIBRARY_DIR)
|
|
10
12
|
FileUtils.cp(FasterPath::BuildTask.built_library, FasterPath::BuildTask::INSTALLED_LIBRARY_DIR)
|
|
11
13
|
Rake::Task['rutie:clean'].invoke
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
NO_PREBUILT = <<~MESSAGE
|
|
17
|
+
****
|
|
18
|
+
Rust's Cargo was not found, and this release of faster_path has no prebuilt
|
|
19
|
+
extension for this platform (%s).
|
|
20
|
+
Install Rust (https://www.rust-lang.org/tools/install) and run the install
|
|
21
|
+
again, or set FASTER_PATH_PREBUILT_URL to a directory holding the asset.
|
|
22
|
+
****
|
|
23
|
+
MESSAGE
|
|
24
|
+
|
|
25
|
+
# Installs the prebuilt library from this version's GitHub release instead.
|
|
26
|
+
task :install_prebuilt do
|
|
27
|
+
library = FasterPath::Prebuilt.install(FasterPath::BuildTask::PROJECT_DIR)
|
|
28
|
+
raise format(NO_PREBUILT, FasterPath::Prebuilt.asset_name) unless library
|
|
29
|
+
|
|
30
|
+
puts "Installed the prebuilt extension #{File.basename(library)}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
task :default do
|
|
34
|
+
if FasterPath::BuildTask.cargo?
|
|
35
|
+
Rake::Task[:install_library].invoke
|
|
36
|
+
else
|
|
37
|
+
puts 'Cargo was not found; downloading the prebuilt extension for this platform instead'
|
|
38
|
+
Rake::Task[:install_prebuilt].invoke
|
|
39
|
+
end
|
|
40
|
+
end
|
data/faster_path.gemspec
CHANGED
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
|
16
16
|
spec.files = [
|
|
17
17
|
'Cargo.lock', 'Cargo.toml', 'Gemfile', 'MIT-LICENSE.txt', 'README.md', 'Rakefile',
|
|
18
18
|
'bin/console', 'bin/setup', 'ext/Rakefile', 'faster_path.gemspec', 'lib/faster_path.rb',
|
|
19
|
-
'lib/faster_path/version.rb', 'lib/faster_path/build_task.rb',
|
|
19
|
+
'lib/faster_path/version.rb', 'lib/faster_path/build_task.rb', 'lib/faster_path/prebuilt.rb',
|
|
20
20
|
'lib/faster_path/optional/monkeypatches.rb', 'lib/faster_path/optional/refinements.rb'
|
|
21
21
|
]
|
|
22
22
|
spec.files += Dir['src/**/*']
|
|
@@ -28,5 +28,15 @@ module FasterPath
|
|
|
28
28
|
def self.built_library
|
|
29
29
|
Rutie.new(:faster_path).ffi_library(File.join(PROJECT_DIR, 'lib'))
|
|
30
30
|
end
|
|
31
|
+
|
|
32
|
+
# Whether Cargo can be run: named by CARGO, or on the PATH
|
|
33
|
+
def self.cargo?
|
|
34
|
+
return true if ENV['CARGO']
|
|
35
|
+
|
|
36
|
+
exts = RbConfig::CONFIG['EXEEXT'].empty? ? [''] : ['', RbConfig::CONFIG['EXEEXT']]
|
|
37
|
+
ENV.fetch('PATH', '').split(File::PATH_SEPARATOR).any? do |dir|
|
|
38
|
+
exts.any? { |ext| File.executable?(File.join(dir, "cargo#{ext}")) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
31
41
|
end
|
|
32
42
|
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'digest/sha2'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'rbconfig'
|
|
5
|
+
require 'rubygems/package'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
require 'uri'
|
|
8
|
+
require 'zlib'
|
|
9
|
+
require_relative 'version'
|
|
10
|
+
|
|
11
|
+
module FasterPath
|
|
12
|
+
# The prebuilt extension that the GitHub release of each version carries
|
|
13
|
+
# for a few platforms, so that the gem installs without Rust there:
|
|
14
|
+
# `gem install` falls back to it when Cargo is not found (see ext/Rakefile),
|
|
15
|
+
# and the release workflow builds it with `rake prebuilt`.
|
|
16
|
+
module Prebuilt
|
|
17
|
+
RELEASES = 'https://github.com/danielpclark/faster_path/releases/download'.freeze
|
|
18
|
+
# Where the library sits in the tarball and, unpacked, in the gem
|
|
19
|
+
LIBRARY_DIR = File.join('lib', 'faster_path').freeze
|
|
20
|
+
MAX_REDIRECTS = 5
|
|
21
|
+
|
|
22
|
+
# The asset for the running Ruby, e.g. "faster_path-0.5.0-ruby34-linux-x86_64.tar.gz":
|
|
23
|
+
# the gem version, the Ruby minor version the library was built for (an
|
|
24
|
+
# extension works with every patch release of it), the OS family and the CPU.
|
|
25
|
+
def self.asset_name(rbconfig = RbConfig::CONFIG, version = FasterPath::VERSION)
|
|
26
|
+
major, minor = rbconfig['ruby_version'].split('.')
|
|
27
|
+
"faster_path-#{version}-ruby#{major}#{minor}-#{os(rbconfig)}-#{cpu(rbconfig)}.tar.gz"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.os(rbconfig)
|
|
31
|
+
case rbconfig['host_os']
|
|
32
|
+
when /darwin/ then 'darwin'
|
|
33
|
+
when /mingw|mswin|cygwin/ then 'windows'
|
|
34
|
+
else rbconfig['host_os'][/\A[a-z]+/]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.cpu(rbconfig)
|
|
39
|
+
{ 'x64' => 'x86_64', 'amd64' => 'x86_64', 'aarch64' => 'arm64' }.fetch(rbconfig['target_cpu'], rbconfig['target_cpu'])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Packs the built `library` as lib/faster_path/<file> into `dir`, with a
|
|
43
|
+
# SHA-256 checksum file next to it, and returns the tarball's path.
|
|
44
|
+
def self.package(library, dir, asset = asset_name)
|
|
45
|
+
path = File.join(dir, asset)
|
|
46
|
+
data = File.binread(library)
|
|
47
|
+
File.open(path, 'wb') do |file|
|
|
48
|
+
Zlib::GzipWriter.wrap(file) do |gz|
|
|
49
|
+
Gem::Package::TarWriter.new(gz) do |tar|
|
|
50
|
+
tar.add_file_simple(File.join(LIBRARY_DIR, File.basename(library)), 0o644, data.bytesize) { |io| io.write(data) }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
File.write("#{path}.sha256", "#{Digest::SHA256.file(path).hexdigest} #{asset}\n")
|
|
55
|
+
path
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Downloads this platform's asset of this version's release, checks it
|
|
59
|
+
# against its checksum file and unpacks the library into `project_dir`.
|
|
60
|
+
# Returns the library's path, or nil when the release has no asset for
|
|
61
|
+
# this platform. FASTER_PATH_PREBUILT_URL replaces the release's URL.
|
|
62
|
+
def self.install(project_dir, base_url = ENV.fetch('FASTER_PATH_PREBUILT_URL', "#{RELEASES}/v#{FasterPath::VERSION}"))
|
|
63
|
+
asset = asset_name
|
|
64
|
+
tarball = fetch("#{base_url}/#{asset}")
|
|
65
|
+
return nil unless tarball
|
|
66
|
+
|
|
67
|
+
checksum = fetch("#{base_url}/#{asset}.sha256")
|
|
68
|
+
raise "#{asset} has no checksum file at #{base_url}" unless checksum
|
|
69
|
+
|
|
70
|
+
verify(tarball, checksum, asset)
|
|
71
|
+
unpack(tarball, project_dir)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The body at `url`, following redirects, or nil if it does not exist.
|
|
75
|
+
def self.fetch(url, redirects = MAX_REDIRECTS)
|
|
76
|
+
uri = URI(url)
|
|
77
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') { |http| http.get(uri.request_uri) }
|
|
78
|
+
case response
|
|
79
|
+
when Net::HTTPSuccess then response.body
|
|
80
|
+
when Net::HTTPNotFound then nil
|
|
81
|
+
when Net::HTTPRedirection
|
|
82
|
+
raise "Too many redirects fetching #{url}" if redirects.zero?
|
|
83
|
+
|
|
84
|
+
fetch(URI.join(url, response['Location']).to_s, redirects - 1)
|
|
85
|
+
else raise "#{url}: #{response.code} #{response.message}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def self.verify(tarball, checksum, asset)
|
|
90
|
+
expected = checksum.split.first.to_s.downcase
|
|
91
|
+
actual = Digest::SHA256.hexdigest(tarball)
|
|
92
|
+
raise "#{asset} does not match its checksum (expected #{expected}, got #{actual})" unless expected == actual
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Unpacks the library of the tarball `data` into `project_dir` and returns its path.
|
|
96
|
+
def self.unpack(data, project_dir)
|
|
97
|
+
installed = nil
|
|
98
|
+
Zlib::GzipReader.wrap(StringIO.new(data)) do |gz|
|
|
99
|
+
Gem::Package::TarReader.new(gz) do |tar|
|
|
100
|
+
tar.each do |entry|
|
|
101
|
+
next unless entry.file? && File.dirname(entry.full_name) == LIBRARY_DIR
|
|
102
|
+
|
|
103
|
+
installed = write_library(project_dir, File.basename(entry.full_name), entry.read)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
installed || raise("No #{LIBRARY_DIR} library in the tarball")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def self.write_library(project_dir, name, data)
|
|
111
|
+
dir = File.join(project_dir, LIBRARY_DIR)
|
|
112
|
+
FileUtils.mkdir_p(dir)
|
|
113
|
+
path = File.join(dir, name)
|
|
114
|
+
File.binwrite(path, data)
|
|
115
|
+
path
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/faster_path/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: faster_path
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel P. Clark
|
|
@@ -157,6 +157,7 @@ files:
|
|
|
157
157
|
- lib/faster_path/build_task.rb
|
|
158
158
|
- lib/faster_path/optional/monkeypatches.rb
|
|
159
159
|
- lib/faster_path/optional/refinements.rb
|
|
160
|
+
- lib/faster_path/prebuilt.rb
|
|
160
161
|
- lib/faster_path/version.rb
|
|
161
162
|
- src/basename.rs
|
|
162
163
|
- src/chop_basename.rs
|