fzf-ruby 0.1.0 → 0.1.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/ext/fzf/extconf.rb +137 -0
- data/lib/fzf/platform.rb +65 -0
- data/lib/fzf/tasks.rb +8 -16
- data/lib/fzf/version.rb +1 -1
- data/lib/fzf.rb +7 -1
- metadata +5 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3219f16fc90118b1bccef8ba71a98faab74a9b8bc007997e4d4ef2904ee652bf
|
|
4
|
+
data.tar.gz: abafdedf74c201202bf79c916f5c536ed12979d651c82198304ae0c45b3b6c68
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ad1d363b716fc4fd20cf43d253c06a56ee81df717748c71bd458f5a3b66b1fe3515339ff5170c3d3e780f51f6fe8c7f7fc73f218bc4942a4f7d4988dc0697bc
|
|
7
|
+
data.tar.gz: f9b0fbe46c078db77f8373586fac96bbd4bffa8c52c8a138bbd94636693b2774789f17562b1c3f065097749fb3a8139e3d2a3c2b27cbceaa82ab7dcc6c618b1d
|
data/ext/fzf/extconf.rb
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Install-time hook: fetch the fzf binary so the gem works straight after
|
|
2
|
+
# `gem install` / `bundle install`, with no follow-up steps for the user.
|
|
3
|
+
#
|
|
4
|
+
# RubyGems runs this file as a "native extension". Nothing is compiled — the
|
|
5
|
+
# official prebuilt release for the host platform is downloaded, checksum
|
|
6
|
+
# verified, and unpacked into the gem's own lib/fzf/bin/ directory, which is
|
|
7
|
+
# where FzfRuby.fzf_binary looks. A no-op Makefile is written at the end
|
|
8
|
+
# because RubyGems always invokes `make` afterwards.
|
|
9
|
+
#
|
|
10
|
+
# Building from source is deliberately not attempted here: it would require Go
|
|
11
|
+
# on every machine that installs the gem. `rake fzf:install` (lib/fzf/tasks.rb)
|
|
12
|
+
# still offers that route for anyone who wants it.
|
|
13
|
+
|
|
14
|
+
require "digest"
|
|
15
|
+
require "fileutils"
|
|
16
|
+
require "open-uri"
|
|
17
|
+
require "tmpdir"
|
|
18
|
+
|
|
19
|
+
require_relative "../../lib/fzf/platform"
|
|
20
|
+
|
|
21
|
+
module FzfRuby
|
|
22
|
+
module Installer
|
|
23
|
+
# Release of fzf to install. Overridable so a project can pin a different
|
|
24
|
+
# version at install time: FZF_VERSION=0.70.0 bundle install
|
|
25
|
+
FZF_VERSION = ENV.fetch("FZF_VERSION", "0.74.1").freeze
|
|
26
|
+
|
|
27
|
+
# Where release assets live.
|
|
28
|
+
RELEASE_BASE = "https://github.com/junegunn/fzf/releases/download".freeze
|
|
29
|
+
|
|
30
|
+
# Upstream installation instructions, cited when we cannot help further.
|
|
31
|
+
FZF_INSTALL_URL = "https://github.com/junegunn/fzf#installation".freeze
|
|
32
|
+
|
|
33
|
+
# Asset name templates. Both are published for every release.
|
|
34
|
+
ASSET_TEMPLATE = "fzf-%<version>s-%<slug>s.tar.gz".freeze
|
|
35
|
+
CHECKSUMS_TEMPLATE = "fzf_%<version>s_checksums.txt".freeze
|
|
36
|
+
|
|
37
|
+
# Final resting place of the binary, inside the installed gem.
|
|
38
|
+
BIN_DIR = File.expand_path("../../lib/fzf/bin", __dir__).freeze
|
|
39
|
+
|
|
40
|
+
# Seconds to wait on each network call before giving up.
|
|
41
|
+
DOWNLOAD_TIMEOUT = 60
|
|
42
|
+
|
|
43
|
+
# Raised when no usable binary can be installed.
|
|
44
|
+
class InstallError < StandardError; end
|
|
45
|
+
|
|
46
|
+
# Download a URL into memory, surfacing network failures as InstallError.
|
|
47
|
+
def self.fetch(url)
|
|
48
|
+
URI.parse(url).open(open_timeout: DOWNLOAD_TIMEOUT, read_timeout: DOWNLOAD_TIMEOUT, &:read)
|
|
49
|
+
rescue StandardError => e
|
|
50
|
+
raise InstallError, <<~MSG
|
|
51
|
+
Could not download #{url}
|
|
52
|
+
#{e.class}: #{e.message}
|
|
53
|
+
|
|
54
|
+
If this machine has no network access, install fzf yourself and point
|
|
55
|
+
the gem at it with FZF_PATH=/path/to/fzf, or see #{FZF_INSTALL_URL}
|
|
56
|
+
MSG
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Expected SHA256 for an asset, read from the release's checksums file.
|
|
60
|
+
# The file lists one "<sha256> <filename>" pair per line.
|
|
61
|
+
def self.expected_checksum(asset)
|
|
62
|
+
checksums = fetch("#{RELEASE_BASE}/v#{FZF_VERSION}/#{format(CHECKSUMS_TEMPLATE, version: FZF_VERSION)}")
|
|
63
|
+
line = checksums.lines.find { |l| l.split(/\s+/).last == asset }
|
|
64
|
+
raise InstallError, "No checksum listed for #{asset}" unless line
|
|
65
|
+
|
|
66
|
+
line.split(/\s+/).first
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Download, verify and unpack the release, leaving the binary at BIN_DIR/fzf.
|
|
70
|
+
def self.install
|
|
71
|
+
slug = FzfRuby::Platform.slug
|
|
72
|
+
raise unsupported_platform_error unless slug
|
|
73
|
+
|
|
74
|
+
asset = format(ASSET_TEMPLATE, version: FZF_VERSION, slug: slug)
|
|
75
|
+
url = "#{RELEASE_BASE}/v#{FZF_VERSION}/#{asset}"
|
|
76
|
+
|
|
77
|
+
puts "fzf-ruby: downloading #{asset}"
|
|
78
|
+
tarball = fetch(url)
|
|
79
|
+
|
|
80
|
+
# Verify before unpacking — never execute an unverified download.
|
|
81
|
+
actual = Digest::SHA256.hexdigest(tarball)
|
|
82
|
+
expected = expected_checksum(asset)
|
|
83
|
+
unless actual == expected
|
|
84
|
+
raise InstallError, "Checksum mismatch for #{asset}\n expected #{expected}\n actual #{actual}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
Dir.mktmpdir("fzf-install") do |tmpdir|
|
|
88
|
+
archive = File.join(tmpdir, asset)
|
|
89
|
+
File.binwrite(archive, tarball)
|
|
90
|
+
|
|
91
|
+
# The release tarballs contain a single `fzf` binary at the root.
|
|
92
|
+
unless system("tar", "-xzf", archive, "-C", tmpdir)
|
|
93
|
+
raise InstallError, "Failed to unpack #{asset}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
extracted = File.join(tmpdir, "fzf")
|
|
97
|
+
raise InstallError, "#{asset} did not contain an fzf binary" unless File.exist?(extracted)
|
|
98
|
+
|
|
99
|
+
FileUtils.mkdir_p(BIN_DIR)
|
|
100
|
+
FileUtils.cp(extracted, File.join(BIN_DIR, "fzf"))
|
|
101
|
+
FileUtils.chmod(0o755, File.join(BIN_DIR, "fzf"))
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
puts "fzf-ruby: installed fzf #{FZF_VERSION} to #{BIN_DIR}/fzf"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# No prebuilt release matches this machine, so there is nothing to install.
|
|
108
|
+
def self.unsupported_platform_error
|
|
109
|
+
InstallError.new(<<~MSG)
|
|
110
|
+
fzf-ruby: no prebuilt fzf release exists for this platform
|
|
111
|
+
host_os: #{RbConfig::CONFIG["host_os"]}
|
|
112
|
+
host_cpu: #{RbConfig::CONFIG["host_cpu"]}
|
|
113
|
+
|
|
114
|
+
Install fzf by hand and point the gem at it:
|
|
115
|
+
export FZF_PATH=/path/to/fzf
|
|
116
|
+
|
|
117
|
+
Installation options, including building from source:
|
|
118
|
+
#{FZF_INSTALL_URL}
|
|
119
|
+
MSG
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
FzfRuby::Installer.install
|
|
125
|
+
|
|
126
|
+
# RubyGems runs `make` and `make install` after this script regardless of what
|
|
127
|
+
# it did, so hand it a Makefile whose targets are all satisfied.
|
|
128
|
+
File.write("Makefile", <<~MAKEFILE)
|
|
129
|
+
all:
|
|
130
|
+
\t@true
|
|
131
|
+
|
|
132
|
+
install:
|
|
133
|
+
\t@true
|
|
134
|
+
|
|
135
|
+
clean:
|
|
136
|
+
\t@true
|
|
137
|
+
MAKEFILE
|
data/lib/fzf/platform.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Host platform detection, in the naming scheme fzf uses.
|
|
2
|
+
#
|
|
3
|
+
# fzf's release assets and Go's own toolchain share one naming convention
|
|
4
|
+
# ("linux_amd64", "darwin_arm64"), so a single set of maps serves both the
|
|
5
|
+
# install-time downloader (ext/fzf/extconf.rb) and the source build
|
|
6
|
+
# (lib/fzf/tasks.rb). This file is the one home for those names.
|
|
7
|
+
#
|
|
8
|
+
# Detection returns nil rather than aborting — callers decide whether an
|
|
9
|
+
# unsupported platform is fatal (source build) or merely a reason to fall
|
|
10
|
+
# back to a system fzf (install-time download).
|
|
11
|
+
|
|
12
|
+
require "rbconfig"
|
|
13
|
+
|
|
14
|
+
module FzfRuby
|
|
15
|
+
module Platform
|
|
16
|
+
# RbConfig host_cpu → fzf/Go architecture name.
|
|
17
|
+
# Keys are matched as prefixes, since host_cpu carries suffixes such as
|
|
18
|
+
# "armv7l" that the release names ("armv7") do not.
|
|
19
|
+
ARCH_MAP = {
|
|
20
|
+
"x86_64" => "amd64",
|
|
21
|
+
"amd64" => "amd64",
|
|
22
|
+
"aarch64" => "arm64",
|
|
23
|
+
"arm64" => "arm64",
|
|
24
|
+
"armv7" => "armv7",
|
|
25
|
+
"armv6" => "armv6",
|
|
26
|
+
"armv5" => "armv5",
|
|
27
|
+
"loong64" => "loong64",
|
|
28
|
+
"ppc64le" => "ppc64le",
|
|
29
|
+
"riscv64" => "riscv64",
|
|
30
|
+
"s390x" => "s390x",
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
# RbConfig host_os → fzf/Go operating system name.
|
|
34
|
+
# Keys are matched as prefixes ("linux-gnu", "darwin23" and so on).
|
|
35
|
+
OS_MAP = {
|
|
36
|
+
"linux" => "linux",
|
|
37
|
+
"darwin" => "darwin",
|
|
38
|
+
"freebsd" => "freebsd",
|
|
39
|
+
"openbsd" => "openbsd",
|
|
40
|
+
}.freeze
|
|
41
|
+
|
|
42
|
+
# Operating system in fzf's naming, or nil when unrecognised.
|
|
43
|
+
def self.os
|
|
44
|
+
host = RbConfig::CONFIG["host_os"]
|
|
45
|
+
OS_MAP.each { |prefix, name| return name if host.start_with?(prefix) }
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Architecture in fzf's naming, or nil when unrecognised.
|
|
50
|
+
def self.arch
|
|
51
|
+
cpu = RbConfig::CONFIG["host_cpu"]
|
|
52
|
+
ARCH_MAP.each { |prefix, name| return name if cpu.start_with?(prefix) }
|
|
53
|
+
nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Platform slug as it appears in a release asset name, e.g. "linux_amd64".
|
|
57
|
+
# nil when either half is unrecognised, meaning no prebuilt asset exists.
|
|
58
|
+
def self.slug
|
|
59
|
+
detected_os, detected_arch = os, arch
|
|
60
|
+
return nil unless detected_os && detected_arch
|
|
61
|
+
|
|
62
|
+
"#{detected_os}_#{detected_arch}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/fzf/tasks.rb
CHANGED
|
@@ -14,6 +14,8 @@ require "fileutils"
|
|
|
14
14
|
require "open-uri"
|
|
15
15
|
require "rbconfig"
|
|
16
16
|
|
|
17
|
+
require_relative "platform"
|
|
18
|
+
|
|
17
19
|
module FzfRuby
|
|
18
20
|
module Tasks
|
|
19
21
|
extend Rake::DSL
|
|
@@ -27,29 +29,19 @@ module FzfRuby
|
|
|
27
29
|
# Go download base URL
|
|
28
30
|
GO_DL_BASE = "https://go.dev/dl"
|
|
29
31
|
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"arm64" => "arm64",
|
|
35
|
-
}.freeze
|
|
36
|
-
|
|
37
|
-
OS_MAP = {
|
|
38
|
-
"linux" => "linux",
|
|
39
|
-
"darwin" => "darwin",
|
|
40
|
-
}.freeze
|
|
32
|
+
# Go and fzf share one platform naming scheme, so the maps live in
|
|
33
|
+
# FzfRuby::Platform and are used by the install-time downloader too.
|
|
34
|
+
# Platform returns nil for anything unrecognised; Go's own downloads are
|
|
35
|
+
# all-or-nothing, so here that is fatal.
|
|
41
36
|
|
|
42
37
|
# Detect the host OS in Go's naming convention
|
|
43
38
|
def self.detect_os
|
|
44
|
-
|
|
45
|
-
OS_MAP.each { |prefix, name| return name if host.start_with?(prefix) }
|
|
46
|
-
abort "Unsupported OS for Go auto-install: #{host}"
|
|
39
|
+
FzfRuby::Platform.os || abort("Unsupported OS for Go auto-install: #{RbConfig::CONFIG["host_os"]}")
|
|
47
40
|
end
|
|
48
41
|
|
|
49
42
|
# Detect the host architecture in Go's naming convention
|
|
50
43
|
def self.detect_arch
|
|
51
|
-
|
|
52
|
-
ARCH_MAP.fetch(cpu) { abort "Unsupported arch for Go auto-install: #{cpu}" }
|
|
44
|
+
FzfRuby::Platform.arch || abort("Unsupported arch for Go auto-install: #{RbConfig::CONFIG["host_cpu"]}")
|
|
53
45
|
end
|
|
54
46
|
|
|
55
47
|
# Fetch the latest stable Go version string (e.g. "go1.26.5")
|
data/lib/fzf/version.rb
CHANGED
data/lib/fzf.rb
CHANGED
|
@@ -34,8 +34,11 @@ module FzfRuby
|
|
|
34
34
|
# Raised when fzf binary is not found in PATH
|
|
35
35
|
class FzfNotFoundError < StandardError; end
|
|
36
36
|
|
|
37
|
+
# Binary installed with the gem itself by ext/fzf/extconf.rb.
|
|
38
|
+
VENDORED_BINARY = File.join(__dir__, "fzf", "bin", "fzf").freeze
|
|
39
|
+
|
|
37
40
|
# Resolve the fzf binary path.
|
|
38
|
-
# Priority: FZF_PATH env var → project bin/fzf → system PATH
|
|
41
|
+
# Priority: FZF_PATH env var → project bin/fzf → gem's own bin → system PATH
|
|
39
42
|
def self.fzf_binary
|
|
40
43
|
# Explicit override via environment variable
|
|
41
44
|
from_env = ENV["FZF_PATH"]
|
|
@@ -45,6 +48,9 @@ module FzfRuby
|
|
|
45
48
|
local = File.join(project_root, "bin", "fzf")
|
|
46
49
|
return local if File.executable?(local)
|
|
47
50
|
|
|
51
|
+
# Binary downloaded when the gem was installed
|
|
52
|
+
return VENDORED_BINARY if File.executable?(VENDORED_BINARY)
|
|
53
|
+
|
|
48
54
|
# Fall back to system PATH
|
|
49
55
|
"fzf"
|
|
50
56
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fzf-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- asmrtfm
|
|
@@ -15,25 +15,19 @@ description: Pipes items into fzf and returns the user's selection. Supports mul
|
|
|
15
15
|
email:
|
|
16
16
|
- asmrtfm@gmail.com
|
|
17
17
|
executables: []
|
|
18
|
-
extensions:
|
|
18
|
+
extensions:
|
|
19
|
+
- ext/fzf/extconf.rb
|
|
19
20
|
extra_rdoc_files: []
|
|
20
21
|
files:
|
|
22
|
+
- ext/fzf/extconf.rb
|
|
21
23
|
- lib/fzf.rb
|
|
24
|
+
- lib/fzf/platform.rb
|
|
22
25
|
- lib/fzf/tasks.rb
|
|
23
26
|
- lib/fzf/version.rb
|
|
24
27
|
homepage: https://github.com/asmrtfm/fzf-ruby
|
|
25
28
|
licenses:
|
|
26
29
|
- MIT
|
|
27
30
|
metadata: {}
|
|
28
|
-
post_install_message: |
|
|
29
|
-
fzf-ruby requires the `fzf` binary.
|
|
30
|
-
|
|
31
|
-
Build from source (requires Go >= 1.23):
|
|
32
|
-
1. Add to your Rakefile: require "fzf/tasks"
|
|
33
|
-
2. Run: rake fzf:install
|
|
34
|
-
|
|
35
|
-
This clones and compiles fzf into your project's bin/ directory.
|
|
36
|
-
Alternatively, install fzf system-wide: https://github.com/junegunn/fzf#installation
|
|
37
31
|
rdoc_options: []
|
|
38
32
|
require_paths:
|
|
39
33
|
- lib
|