uprb 0.1.0 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5935681ab015986fc8fa6aa5aad5d660da25e6126602888b95929f8456216f8b
4
- data.tar.gz: c59b6d98633c40d506852dca47e4bf1895baaece4fcb596c4bf1e2cf62392dea
3
+ metadata.gz: 47c673bd86d084d70c17fdbf40a0b37752901835da0c7be9ca22e88a6800ea37
4
+ data.tar.gz: 518ba4cfa3fe746297837a9309091e9bc00d51ea0aa72856a1a32b43d1c16c15
5
5
  SHA512:
6
- metadata.gz: cfeb194da679b6b6826c21f7207128869d835496268051d27e292e09f74edaaff60ca04381c5db3b63e268770924904d5cbfa0bca84055460fe4ef934e09f568
7
- data.tar.gz: f09e358a5ffd2b2d22c1ca1dc26669be9d21d8bdc141aa59ed13e6480203c4e1b97c246944495d88a7e8cf80a53fb9029baa3e41f33bdfea7d4e44d8821f770f
6
+ metadata.gz: b5b3ec5ab5f74dcbc48f4ddc731f3a0ce84bfc2d3ec8a44a4189e4c45281e143492c1500f88bfd525be0ed5a7ed2cefa4e1717ba9b021001346ad13da19f9f7a
7
+ data.tar.gz: 425d5e42fb25f92c8405aea0f0b22d952a379925ca5a5760587e43c35f2d2da2a6bd2fa799ae5f191d12e3e9b1f515e96e5d2561d539b2f3d13bf301177fffd0
data/README.md CHANGED
@@ -1,36 +1,25 @@
1
1
  # uprb
2
2
 
3
- uprb is a Ruby script packer. It builds a single executable from a Ruby
4
- script with a fast, deterministic startup.
3
+ [![Test](https://github.com/hogelog/uprb/actions/workflows/test.yml/badge.svg)](https://github.com/hogelog/uprb/actions/workflows/test.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/uprb.svg)](http://badge.fury.io/rb/uprb)
5
5
 
6
- This is not a native binary compiler. The packed executable still needs
7
- a Ruby interpreter on the machine that runs it, and it is tied to the
8
- Ruby and gems that were active when you packed.
6
+ uprb packs a Ruby script into a single executable with fast, deterministic startup.
9
7
 
10
- The packed executable starts Ruby with `--disable-gems` by default.
11
- Gems that depend on rubygems at load time will not work as-is — use
12
- `--with-rubygems` to embed rubygems into the output, or
13
- `--skip-disable-gems` to drop the flag entirely (vendoring only; gives
14
- up the fast-startup headline).
8
+ The output still requires a Ruby interpreter and is tied to the Ruby and gems active at pack time. The default shebang runs Ruby with `--disable-gems`; flags below can change this.
15
9
 
16
- ## Usage
17
-
18
- Pack a script into a single executable:
10
+ ## Install
19
11
 
20
12
  ```bash
21
- uprb pack path/to/script.rb path/to/output
13
+ gem install uprb
22
14
  ```
23
15
 
24
- Options:
16
+ ## Usage
25
17
 
26
- - `-f`, `--force`: overwrite the destination without prompting
27
- - `-r`, `--require LIB`: pre-`require` `LIB` so it is embedded and loaded before the script runs. Repeatable.
28
- - `--with-rubygems`: shortcut for `--require rubygems`. Needed when the script references `Gem::Version` / `Gem::Requirement` / `Gem::Platform` etc. Trade-off: larger output.
29
- - `--dynamic`: execute the entry script at pack time so runtime-only requires (e.g. interpolated `require`s) are captured. The entry actually runs, which is a problem for scripts that do I/O on startup — arguments after `--` are forwarded as `ARGV` so you can steer into a safe path (e.g. `-- --help`).
30
- - `--skip-disable-gems`: drop `--disable-gems` from the shebang. The output then behaves like a normal Ruby invocation — rubygems, `RUBYOPT`, and Bundler's Gemfile autodetection all run as usual. Use this when you want single-file vendoring of `.rb` dependencies and don't care about startup latency.
31
- - `--skip-ruby-path-replace`: keep the source file's shebang ruby invocation (e.g. `/usr/bin/env ruby`) instead of rewriting it to an absolute `RbConfig.ruby` path. `--disable-gems` is still appended (unless `--skip-disable-gems` is also passed), so this is orthogonal to `--skip-disable-gems`. Use for vendoring when you want a portable Ruby reference in the output.
18
+ Pack a script:
32
19
 
33
- If the source has no shebang, the packed output also has no shebang and is not chmod'd executable — invoke via `ruby packed_file`. This applies regardless of flags.
20
+ ```bash
21
+ uprb pack path/to/script.rb path/to/output
22
+ ```
34
23
 
35
24
  Pack executables from an installed gem:
36
25
 
@@ -44,16 +33,20 @@ Install a gem and pack its executables:
44
33
  uprb gem install GEM_NAME
45
34
  ```
46
35
 
47
- Both `gem` subcommands accept `--path DIR` (destination directory),
48
- `-f`/`--force`, `-r`/`--require LIB`, `--with-rubygems`, `--dynamic`,
49
- `--skip-disable-gems`, and `--skip-ruby-path-replace`.
36
+ ## Options
50
37
 
51
- By default, `uprb` asks `overwrite? [y/N]` on stderr when the
52
- destination already exists. When stdin is not a TTY (e.g. CI), `uprb`
53
- refuses to overwrite unless `--force` is given.
38
+ - `-f`, `--force` overwrite destination
39
+ - `-r`, `--require LIB` pre-`require` `LIB` (repeatable)
40
+ - `--with-rubygems` embed rubygems; needed when the script references `Gem::Version` etc.
41
+ - `--dynamic` — run the entry script at pack time to capture runtime `require`s. Arguments after `--` become `ARGV` (e.g. `-- --help` to avoid side effects)
42
+ - `--skip-disable-gems` — drop `--disable-gems` from the shebang (vendoring mode; gives up fast startup)
43
+ - `--skip-ruby-path-replace` — keep the source shebang's ruby invocation instead of rewriting to an absolute path
44
+ - `--path DIR` — destination directory (`gem` subcommands only)
54
45
 
55
- ## Install
46
+ ## Gemspec metadata
56
47
 
57
- ```bash
58
- gem install uprb
48
+ `uprb gem pack` / `uprb gem install` honors `uprb.requires` (comma-separated) in `Gem::Specification#metadata` as additional pre-`require` libraries, merged with `-r`:
49
+
50
+ ```ruby
51
+ spec.metadata["uprb.requires"] = "openssl,json"
59
52
  ```
data/lib/uprb/cli.rb CHANGED
@@ -155,6 +155,13 @@ module Uprb
155
155
  raise Uprb::Error, "no executables for gem: #{gem_name}" if executables.empty?
156
156
  bindir = spec.bindir
157
157
 
158
+ metadata_result = Uprb::GemspecMetadata.read(spec)
159
+ metadata_result.warnings.each { |w| $stderr.puts(w) }
160
+ unless metadata_result.requires.empty?
161
+ $stderr.puts("uprb: applying gemspec metadata uprb.requires: #{metadata_result.requires.inspect}")
162
+ end
163
+ requires = (metadata_result.requires + options[:requires]).uniq
164
+
158
165
  dest_dir = options[:path] ? File.expand_path(options[:path]) : Gem.bindir
159
166
  FileUtils.mkdir_p(dest_dir)
160
167
 
@@ -166,7 +173,7 @@ module Uprb
166
173
 
167
174
  next unless confirm_overwrite(dest_path, options)
168
175
 
169
- Uprb::RequireReplacer.pack(source_path, dest_path:, requires: options[:requires], dynamic: options[:dynamic], script_argv: options[:script_argv], skip_disable_gems: options[:skip_disable_gems], skip_ruby_path_replace: options[:skip_ruby_path_replace])
176
+ Uprb::RequireReplacer.pack(source_path, dest_path:, requires:, dynamic: options[:dynamic], script_argv: options[:script_argv], skip_disable_gems: options[:skip_disable_gems], skip_ruby_path_replace: options[:skip_ruby_path_replace])
170
177
  $stdout.puts("Packed #{dest_path}")
171
178
  end
172
179
  rescue Gem::LoadError => e
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uprb
4
+ module GemspecMetadata
5
+ KNOWN_KEYS = %w[uprb.requires].freeze
6
+ REQUIRES_KEY = "uprb.requires"
7
+ REQUIRE_ENTRY_PATTERN = %r{\A[A-Za-z0-9_.][A-Za-z0-9_./-]*\z}
8
+
9
+ Result = Struct.new(:requires, :warnings, keyword_init: true)
10
+
11
+ def self.read(spec)
12
+ metadata = spec.metadata || {}
13
+ warnings = []
14
+ requires = []
15
+
16
+ metadata.each do |key, value|
17
+ next unless key.start_with?("uprb.")
18
+
19
+ unless KNOWN_KEYS.include?(key)
20
+ warnings << "uprb: ignoring unknown gemspec metadata key #{key.inspect}"
21
+ next
22
+ end
23
+
24
+ if key == REQUIRES_KEY
25
+ parsed, entry_warnings = parse_requires(value)
26
+ requires.concat(parsed)
27
+ warnings.concat(entry_warnings)
28
+ end
29
+ end
30
+
31
+ Result.new(requires:, warnings:)
32
+ end
33
+
34
+ def self.parse_requires(value)
35
+ warnings = []
36
+ entries = value.to_s.split(",").map(&:strip).reject(&:empty?)
37
+ kept = entries.select do |entry|
38
+ if REQUIRE_ENTRY_PATTERN.match?(entry)
39
+ true
40
+ else
41
+ warnings << "uprb: ignoring gemspec metadata #{REQUIRES_KEY} entry #{entry.inspect}"
42
+ false
43
+ end
44
+ end
45
+ [kept, warnings]
46
+ end
47
+ end
48
+ end
data/lib/uprb/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Uprb
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/uprb.rb CHANGED
@@ -13,3 +13,4 @@ require_relative "uprb/version"
13
13
  require_relative "uprb/require_tracker"
14
14
  require_relative "uprb/static_require_tracker"
15
15
  require_relative "uprb/require_replacer"
16
+ require_relative "uprb/gemspec_metadata"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uprb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - hogelog
@@ -31,44 +31,17 @@ executables:
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - CLAUDE.md
35
34
  - LICENSE.txt
36
35
  - README.md
37
- - Rakefile
38
- - examples/rls/.gitignore
39
- - examples/rls/Gemfile
40
- - examples/rls/README.md
41
- - examples/rls/Rakefile
42
- - examples/rls/bin/console
43
- - examples/rls/bin/setup
44
- - examples/rls/exe/rls
45
- - examples/rls/lib/rls.rb
46
- - examples/rls/lib/rls/cli.rb
47
- - examples/rls/lib/rls/version.rb
48
- - examples/rls/rls.gemspec
49
- - examples/rls/sig/rls.rbs
50
- - examples/s3-ls/.gitignore
51
- - examples/s3-ls/Gemfile
52
- - examples/s3-ls/Gemfile.lock
53
- - examples/s3-ls/README.md
54
- - examples/s3-ls/Rakefile
55
- - examples/s3-ls/bin/console
56
- - examples/s3-ls/bin/setup
57
- - examples/s3-ls/exe/s3-ls
58
- - examples/s3-ls/lib/s3/ls.rb
59
- - examples/s3-ls/lib/s3/ls/cli.rb
60
- - examples/s3-ls/lib/s3/ls/version.rb
61
- - examples/s3-ls/s3-ls.gemspec
62
- - examples/s3-ls/sig/s3/ls.rbs
63
36
  - exe/uprb
64
37
  - lib/uprb.rb
65
38
  - lib/uprb/cli.rb
39
+ - lib/uprb/gemspec_metadata.rb
66
40
  - lib/uprb/require_replacer.rb
67
41
  - lib/uprb/require_tracker.rb
68
42
  - lib/uprb/static_require_tracker.rb
69
43
  - lib/uprb/version.rb
70
44
  - sig/uprb.rbs
71
- - tmp/.keep
72
45
  homepage: https://github.com/hogelog/uprb
73
46
  licenses:
74
47
  - MIT
@@ -82,14 +55,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
82
55
  requirements:
83
56
  - - ">="
84
57
  - !ruby/object:Gem::Version
85
- version: 3.1.0
58
+ version: 3.3.0
86
59
  required_rubygems_version: !ruby/object:Gem::Requirement
87
60
  requirements:
88
61
  - - ">="
89
62
  - !ruby/object:Gem::Version
90
63
  version: '0'
91
64
  requirements: []
92
- rubygems_version: 4.0.3
65
+ rubygems_version: 3.6.9
93
66
  specification_version: 4
94
67
  summary: Pack Ruby scripts into deterministic, fast-starting executables.
95
68
  test_files: []
data/CLAUDE.md DELETED
@@ -1,55 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. User-facing docs live in `README.md`.
4
-
5
- ## Commands
6
-
7
- - `bin/setup` — `bundle install`.
8
- - `bundle exec rake` — run the full test suite.
9
- - `bundle exec ruby -Itest test/test_uprb_cli.rb -n test_pack_builds_executable` — run a single test by name.
10
- - `bundle exec exe/uprb pack path/to/script.rb path/to/out` — run the CLI from the working tree.
11
-
12
- Ruby 3.1+ (`uprb.gemspec`). CI: 3.4.7.
13
-
14
- ## What uprb does
15
-
16
- Packs a Ruby script into a deterministic, fast-starting executable by **freezing every observed `require` at pack time**. At runtime, the frozen mapping is preferred; anything else falls through to Ruby's normal `require`. If the environment changes, the executable is expected to break — the only remediation is repack.
17
-
18
- ## Architecture
19
-
20
- - `lib/uprb/require_tracker.rb` — aliases `Kernel#require` / `Kernel#require_relative` and records `name => $LOADED_FEATURES` path on every successful call.
21
- - `lib/uprb/static_require_tracker.rb` — the **default** tracer. Two passes: (1) parse the entry with Prism and actually `require` each literal require/autoload target — libraries load normally but the entry's other top-level code (e.g. `App.start(ARGV)`) does not run, and everything pulled in transitively is recorded via `RequireTracker`; (2) `StaticWalker` recursively parses every reachable `.rb` file to pick up literal requires and autoload paths that the runtime never hit (rescued `LoadError` alternates, unused autoloads, feature-flag branches). The merged map uses dynamic results on conflict since those reflect the actually-resolved path. Interpolated-string requires triggered only by runtime execution (e.g. `require "foo/#{name}"` inside a method called by the entry) are still missed — those need `--dynamic`.
22
- - `lib/uprb/require_replacer.rb` — `pack` builds the mapping via `build_mapping` (default: `StaticRequireTracker.trace`; `--dynamic`: `execute_with_tracker` + `StaticWalker` as a second pass so the runtime-only captures are augmented with literal/autoload paths not exercised by the execution). Then compiles the main script and every `.rb` entry into `RubyVM::InstructionSequence` binaries and appends a `Marshal` payload after `__END__`. A prepended `FixedRequire` module serves embedded ISeqs; non-`.rb` requires (C extensions etc.) are resolved via a `REQUIRE_MAP` of original absolute paths; unknown names defer to `super`. `execute_with_tracker` captures stdout/stderr to `Tempfile`, clears `ARGV`, sets `$PROGRAM_NAME`, and `Kernel#load`s the source in-process.
23
- - `lib/uprb/cli.rb`, `exe/uprb` — CLI: `pack`, `gem install`, `gem pack`. Options: `--path DIR` (gem subcommands; default `Gem.bindir`).
24
-
25
- The output gets a shebang only when the source does. With a source shebang, the wrapper's shebang is the absolute `RbConfig.ruby` path plus `--disable-gems` by default. Two orthogonal opt-outs:
26
-
27
- - `--skip-disable-gems` drops the `--disable-gems` flag so the output starts Ruby normally (rubygems / `RUBYOPT` / Bundler Gemfile autodetection all active) — intended for vendoring-only use cases that accept normal startup cost.
28
- - `--skip-ruby-path-replace` keeps the source file's shebang ruby invocation verbatim (e.g. `/usr/bin/env ruby`) instead of rewriting it to `RbConfig.ruby` — intended for vendoring that wants a portable Ruby reference in the output.
29
-
30
- The two flags can be combined (e.g. `#!/usr/bin/env ruby` with no `--disable-gems`). When the source has no shebang, the packed output also has none and is not chmod'd executable — invoke via `ruby packed_file`. This is uniform across all flag combinations.
31
-
32
- ## Hard constraints on the generated executable
33
-
34
- Any change to the output generator must preserve these — violating any is a bug:
35
-
36
- - Absolute `RbConfig.ruby` path in the shebang by default; never `/usr/bin/env ruby`, never a PATH lookup. `--skip-ruby-path-replace` is the one documented opt-out, for vendoring-only outputs that preserve the source's shebang ruby invocation
37
- - `--disable-gems` in the shebang by default; rubygems is not available at runtime. `--skip-disable-gems` is the one documented opt-out, for vendoring-only outputs that accept normal Ruby startup cost
38
- - No `-I`, no `$LOAD_PATH` modification, no `RUBYLIB`, no Bundler
39
- - `.rb` dependencies are always embedded as ISeq binaries inside the `Marshal` payload; C extensions and other non-`.rb` requires are always referenced by their **original absolute path** via `REQUIRE_MAP` — never copied, never relocated
40
-
41
- ## Non-goals
42
-
43
- Declining these is a design choice, not a todo:
44
-
45
- - Bundling Ruby itself; vendoring C extensions; cross-machine portability
46
- - Surviving Ruby/gem upgrades, graceful degradation
47
- - Plugin systems or dynamic resolution beyond the frozen mapping
48
-
49
- (Compiled `.rb` sources are embedded in the output, so it is *partially* self-contained for pure-Ruby deps. C extensions and the Ruby interpreter are still referenced by absolute path, so the output remains tied to the machine it was packed on.)
50
-
51
- The output is expected to break when the Ruby path moves, C extension paths change, gems are up/downgraded, or new code paths hit unseen `require`s. The only remediation is `uprb pack <src> <dest>`.
52
-
53
- ## Testing notes
54
-
55
- `test/test_uprb_cli.rb` shells out to `exe/uprb` via `Open3` and writes artifacts under `./tmp/` (gitignored). `aws-sdk-core` is a dev dependency so the suite can verify that a library pulling in rubygems vendored stdlib still packs successfully; the packed output itself is not runnable under `--disable-gems` and is not executed by the test. `examples/rls` and `examples/s3-ls` are sample gems, not part of the suite. `examples/s3-ls` depends on `aws-sdk-s3` and is kept as a reference — with a bare `uprb gem pack` it won't run under `--disable-gems`, but `uprb gem pack s3-ls --with-rubygems --dynamic` runs it up to the AWS credential/region resolution path (see `examples/s3-ls/README.md`).
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "minitest/test_task"
5
-
6
- Minitest::TestTask.create
7
-
8
- task default: :test
@@ -1,8 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
data/examples/rls/Gemfile DELETED
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in rls.gemspec
6
- gemspec
7
-
8
- gem "irb"
9
- gem "rake", "~> 13.0"
@@ -1,9 +0,0 @@
1
- # rls
2
-
3
- Example ls command written by ruby.
4
-
5
- ## Usage
6
-
7
- ```bash
8
- rls
9
- ```
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- task default: %i[]
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "rls"
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- require "irb"
11
- IRB.start(__FILE__)
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
data/examples/rls/exe/rls DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
- require "rls"
6
-
7
- Rls::CLI.start(ARGV)
@@ -1,48 +0,0 @@
1
- module Rls
2
- class CLI
3
- USAGE = <<~USAGE.chomp
4
- Usage:
5
- rls [path]
6
- USAGE
7
-
8
- class << self
9
- def start(argv)
10
- new(argv).start
11
- end
12
- end
13
-
14
- def initialize(argv)
15
- @argv = argv.dup
16
- end
17
-
18
- def start
19
- arg = @argv.shift
20
-
21
- case arg
22
- when "--help", "-h"
23
- STDOUT.puts(USAGE)
24
- when nil
25
- ls_command
26
- else
27
- ls_command(arg)
28
- end
29
- rescue Rls::Error => e
30
- STDERR.puts("rls: #{e.message}")
31
- rescue StandardError => e
32
- STDERR.puts("rls: #{e.class}: #{e.message}")
33
- end
34
-
35
- private
36
-
37
- def ls_command(path = ".")
38
- raise Rls::Error, "unexpected arguments: #{@argv.join(' ')}" unless @argv.empty?
39
-
40
- abs_path = File.expand_path(path)
41
- raise Rls::Error, "not a directory: #{path}" unless File.directory?(abs_path)
42
-
43
- Dir.children(abs_path).sort.each do |entry|
44
- STDOUT.puts(entry)
45
- end
46
- end
47
- end
48
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rls
4
- VERSION = "0.1.0"
5
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "rls/version"
4
- require_relative "rls/cli"
5
-
6
- module Rls
7
- class Error < StandardError; end
8
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/rls/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "rls"
7
- spec.version = Rls::VERSION
8
- spec.authors = ["hogelog"]
9
- spec.email = ["konbu.komuro@gmail.com"]
10
-
11
- spec.summary = "Example ls command gem"
12
- spec.description = "Example ls command gem"
13
- spec.homepage = "https://github.com/hogelog/uprb"
14
- spec.required_ruby_version = ">= 3.2.0"
15
-
16
- spec.metadata["homepage_uri"] = spec.homepage
17
-
18
- gemspec = File.basename(__FILE__)
19
- spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
20
- ls.readlines("\x0", chomp: true).reject do |f|
21
- (f == gemspec) ||
22
- f.start_with?(*%w[bin/ Gemfile .gitignore])
23
- end
24
- end
25
- spec.bindir = "exe"
26
- spec.executables = spec.files.grep(%r{\Aexe/}) {|f| File.basename(f) }
27
- spec.require_paths = ["lib"]
28
- end
@@ -1,4 +0,0 @@
1
- module Rls
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end
@@ -1,8 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in s3-ls.gemspec
6
- gemspec
7
-
8
- gem "irb"
9
- gem "rake", "~> 13.0"
@@ -1,91 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- s3-ls (0.1.0)
5
- aws-sdk-s3 (>= 1.0)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- aws-eventstream (1.4.0)
11
- aws-partitions (1.1202.0)
12
- aws-sdk-core (3.241.3)
13
- aws-eventstream (~> 1, >= 1.3.0)
14
- aws-partitions (~> 1, >= 1.992.0)
15
- aws-sigv4 (~> 1.9)
16
- base64
17
- bigdecimal
18
- jmespath (~> 1, >= 1.6.1)
19
- logger
20
- aws-sdk-kms (1.120.0)
21
- aws-sdk-core (~> 3, >= 3.241.3)
22
- aws-sigv4 (~> 1.5)
23
- aws-sdk-s3 (1.211.0)
24
- aws-sdk-core (~> 3, >= 3.241.3)
25
- aws-sdk-kms (~> 1)
26
- aws-sigv4 (~> 1.5)
27
- aws-sigv4 (1.12.1)
28
- aws-eventstream (~> 1, >= 1.0.2)
29
- base64 (0.3.0)
30
- bigdecimal (4.0.1)
31
- date (3.5.1)
32
- erb (6.0.1)
33
- io-console (0.8.2)
34
- irb (1.16.0)
35
- pp (>= 0.6.0)
36
- rdoc (>= 4.0.0)
37
- reline (>= 0.4.2)
38
- jmespath (1.6.2)
39
- logger (1.7.0)
40
- pp (0.6.3)
41
- prettyprint
42
- prettyprint (0.2.0)
43
- psych (5.3.1)
44
- date
45
- stringio
46
- rake (13.3.1)
47
- rdoc (7.0.3)
48
- erb
49
- psych (>= 4.0.0)
50
- tsort
51
- reline (0.6.3)
52
- io-console (~> 0.5)
53
- stringio (3.2.0)
54
- tsort (0.2.0)
55
-
56
- PLATFORMS
57
- arm64-darwin-25
58
- ruby
59
-
60
- DEPENDENCIES
61
- irb
62
- rake (~> 13.0)
63
- s3-ls!
64
-
65
- CHECKSUMS
66
- aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b
67
- aws-partitions (1.1202.0) sha256=c8aa0f134a23464c61cfd00edfb4b6d968b01847a8b591d4dcc0c63a4897c301
68
- aws-sdk-core (3.241.3) sha256=c7c445ecf1c601c860fd537458b2eb8df0c5df01e63c371849e6594e6b1d4f47
69
- aws-sdk-kms (1.120.0) sha256=a206ac6f62efbe971f802e8399d2702496a5c5bc800abcf94ead87bdddfdfd80
70
- aws-sdk-s3 (1.211.0) sha256=2ae5feb09ff4862462824f267b76601ed16922a15de56cf51e4fa99bc5b3f519
71
- aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00
72
- base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
73
- bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
74
- date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
75
- erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5
76
- io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
77
- irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806
78
- jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1
79
- logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
80
- pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
81
- prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
82
- psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
83
- rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
84
- rdoc (7.0.3) sha256=dfe3d0981d19b7bba71d9dbaeb57c9f4e3a7a4103162148a559c4fc687ea81f9
85
- reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
86
- s3-ls (0.1.0)
87
- stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
88
- tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
89
-
90
- BUNDLED WITH
91
- 4.0.3
@@ -1,19 +0,0 @@
1
- # s3-ls
2
-
3
- Example S3 ls command gem.
4
-
5
- ## Usage
6
-
7
- ```bash
8
- s3-ls s3://bucket[/prefix]
9
- ```
10
-
11
- ## Packing with uprb
12
-
13
- `aws-sdk-core` pulls in rubygems vendored stdlib, so embed rubygems with `--with-rubygems`. Its credential provider chain uses runtime-only interpolated requires (e.g. `aws-sdk-core/json/#{name}_engine`), so pack in `--dynamic` mode so the entry actually runs and those requires fire:
14
-
15
- ```bash
16
- uprb gem pack s3-ls --with-rubygems --dynamic --path ~/local/bin/
17
- ```
18
-
19
- `--dynamic` also augments its trace with a static walk of every reachable `.rb`, so literal requires in unexecuted credential-provider branches get embedded too. If a runtime path still falls through to something that wasn't observed or statically reachable, repack with additional `-r` flags for the missing libs.
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- task default: %i[]
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "s3/ls"
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- require "irb"
11
- IRB.start(__FILE__)
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
- require "s3/ls/cli"
6
-
7
- S3::Ls::CLI.start(ARGV)
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "uri"
4
- require "aws-sdk-s3"
5
- require_relative "../ls"
6
-
7
- module S3
8
- module Ls
9
- class CLI
10
- USAGE = <<~USAGE.chomp
11
- Usage:
12
- s3-ls s3://bucket[/prefix]
13
- s3-ls -h | --help
14
- USAGE
15
-
16
- def self.start(argv)
17
- new(argv).start
18
- end
19
-
20
- def initialize(argv)
21
- @argv = argv.dup
22
- end
23
-
24
- def start
25
- if @argv.first == "-h" || @argv.first == "--help"
26
- $stdout.puts USAGE
27
- return
28
- end
29
-
30
- client = Aws::S3::Client.new
31
-
32
- if @argv.empty?
33
- list_buckets(client)
34
- else
35
- uri = @argv.shift
36
- bucket, prefix = parse_s3_uri(uri)
37
- list_objects(client, bucket, prefix)
38
- end
39
- rescue S3::Ls::Error => e
40
- $stderr.puts "s3-ls: #{e.message}"
41
- exit 1
42
- rescue StandardError => e
43
- $stderr.puts "s3-ls: #{e.class}: #{e.message}"
44
- exit 1
45
- end
46
-
47
- private
48
-
49
- def list_objects(client, bucket, prefix)
50
- client.list_objects_v2(bucket: bucket, prefix: prefix).each_page do |page|
51
- page.contents.each do |object|
52
- $stdout.puts "s3://#{bucket}/#{object.key}"
53
- end
54
- end
55
- end
56
-
57
- def list_buckets(client)
58
- client.list_buckets.buckets.each do |bucket|
59
- $stdout.puts "s3://#{bucket.name}"
60
- end
61
- end
62
-
63
- def parse_s3_uri(input)
64
- uri = URI.parse(input)
65
- raise S3::Ls::Error, "invalid s3 uri: #{input}" unless uri.scheme == "s3"
66
- raise S3::Ls::Error, "missing bucket in s3 uri: #{input}" if uri.host.to_s.empty?
67
-
68
- bucket = uri.host
69
- prefix = uri.path
70
- prefix = prefix.sub(%r{\A/}, "")
71
- prefix = nil if prefix.empty?
72
- [bucket, prefix]
73
- rescue URI::InvalidURIError
74
- raise S3::Ls::Error, "invalid s3 uri: #{input}"
75
- end
76
- end
77
- end
78
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module S3
4
- module Ls
5
- VERSION = "0.1.0"
6
- end
7
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "ls/version"
4
- require_relative "ls/cli"
5
-
6
- module S3
7
- module Ls
8
- class Error < StandardError; end
9
- end
10
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/s3/ls/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "s3-ls"
7
- spec.version = S3::Ls::VERSION
8
- spec.authors = ["hogelog"]
9
- spec.email = ["konbu.komuro@gmail.com"]
10
-
11
- spec.summary = "Example S3 ls command gem"
12
- spec.description = "Example S3 ls command gem"
13
- spec.homepage = "https://github.com/hogelog/uprb"
14
- spec.required_ruby_version = ">= 3.2.0"
15
-
16
- spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = spec.homepage
18
-
19
- # Specify which files should be added to the gem when it is released.
20
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
- gemspec = File.basename(__FILE__)
22
- spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
23
- ls.readlines("\x0", chomp: true).reject do |f|
24
- (f == gemspec) ||
25
- f.start_with?(*%w[bin/ Gemfile .gitignore])
26
- end
27
- end
28
- spec.bindir = "exe"
29
- spec.executables = spec.files.grep(%r{\Aexe/}) {|f| File.basename(f) }
30
- spec.require_paths = ["lib"]
31
-
32
- spec.add_dependency "aws-sdk-s3", ">= 1.0"
33
-
34
- # For more information and examples about making a new gem, check out our
35
- # guide at: https://bundler.io/guides/creating_gem.html
36
- end
@@ -1,6 +0,0 @@
1
- module S3
2
- module Ls
3
- VERSION: String
4
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
- end
6
- end
data/tmp/.keep DELETED
File without changes