retest 2.0.0.pre4 → 2.0.0.pre5

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: 5ba870b22885e9928d0224cef1147fb2caced390abf7d86777dfc500ac83777c
4
- data.tar.gz: 6aafc91c49b9243590d590a6a0debc3faedd797926a4a34f54b03bf28d4dc74a
3
+ metadata.gz: 754751292557705217a2e6010b5fda60d10fffbdf5a1b66ffe48976841407e09
4
+ data.tar.gz: 2156346b0cd5caa0d5dcf329391a0b84a85fc88342a97fe2e3150ba196fdd7c5
5
5
  SHA512:
6
- metadata.gz: 61b46cf027a29b0c8478ce27d848ebc7086cb2db1b2d7992032d9ebc6bf04e00d7c662c1b1cf73851c6c99404f168c6359d1f6d0bb952afa4655fe93cfd4ed8f
7
- data.tar.gz: 517f06d9b1c65288ae74e6cc459692d9458ae62e03089f7c18e642137bba5180945f210ba7cb5bf458feda0c0fe19887dd91ef6ca864c0306518f5e60d7cfaa1
6
+ metadata.gz: 328df6d6fe4153956230bb4029337f68f20ef8a796337b7c423ce2cd07ddf01ce3c69d531e3daac5babe17dae6c266053919246f6f2e93e69ecf56704cf52cc1
7
+ data.tar.gz: ea86b8e02ddced2b484c780ca8ec673098d23a8e86cde6f0f11b15d903e7206bcb88840b61438aa947cbac4b72c34ad8831bc2d2c76f205c6bcf2f73ff75a97f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- retest (2.0.0.pre4)
4
+ retest (2.0.0.pre5)
5
5
  listen (~> 3.9)
6
6
  observer (~> 0.1)
7
7
  string-similarity (~> 2.1)
@@ -48,4 +48,4 @@ DEPENDENCIES
48
48
  retest!
49
49
 
50
50
  BUNDLED WITH
51
- 2.4.21
51
+ 2.3.27
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+
3
+ docker buildx build \
4
+ --platform linux/amd64,linux/arm64 \
5
+ -t ghcr.io/alexb52/slim-bullseye-watchexec:latest \
6
+ -f builds/dockerfiles/WatchexecSlimBullseye \
7
+ --push .
data/bin/test/ruby-app CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  bundle install
4
4
  bundle exec rake build
5
- cp -R features/support features/ruby-app/retest
5
+ # cp -R features/support features/ruby-app/retest
6
6
  ls -t pkg | head -n1 | xargs -I {} mv pkg/{} features/ruby-app/retest.gem
7
- docker compose -f features/ruby-app/docker-compose.yml up --build --exit-code-from retest
7
+ docker compose -f features/ruby-app/docker-compose.yml up --build --exit-code-from retest
@@ -0,0 +1,12 @@
1
+ # Stage 1: Build watchexec with Rust
2
+ FROM rust:1.83.0-slim-bullseye AS rust-builder
3
+
4
+ # Install necessary dependencies for Rust
5
+ RUN apt-get update -qq && \
6
+ apt-get install --no-install-recommends -y build-essential git
7
+
8
+ # Install watchexec
9
+ RUN cargo install watchexec-cli
10
+
11
+ # Verify installation
12
+ RUN watchexec --version
data/exe/retest CHANGED
@@ -5,7 +5,7 @@ require 'retest'
5
5
  $stdout.sync = true
6
6
  listen_rd, listen_wr = IO.pipe
7
7
  Signal.trap(:INT) do
8
- $stdout.puts "Goodbye"
8
+ puts "Goodbye"
9
9
  listen_rd.close
10
10
  listen_wr.close
11
11
  exit
@@ -14,12 +14,12 @@ end
14
14
  options = Retest::Options.new(ARGV)
15
15
 
16
16
  if options.help?
17
- $stdout.puts options.help
17
+ puts options.help
18
18
  return
19
19
  end
20
20
 
21
21
  if options.version?
22
- $stdout.puts Retest::VERSION
22
+ puts Retest::VERSION
23
23
  return
24
24
  end
25
25
 
@@ -28,6 +28,7 @@ repository = Retest::Repository.new(files: Retest::VersionControl.files, prompt:
28
28
  command = Retest::Command.for_options(options)
29
29
  runner = Retest::Runner.new(command)
30
30
  sounds = Retest::Sounds.for(options)
31
+ watcher = Retest::Watcher.for(options.watcher)
31
32
 
32
33
  sounds.play(:start)
33
34
  runner.add_observer(sounds)
@@ -43,6 +44,12 @@ if options.params[:diff]
43
44
  return
44
45
  end
45
46
 
47
+ if watcher == Retest::Watcher::Watchexec
48
+ puts "Watcher: [WATCHEXEC]"
49
+ else Retest::Watcher::Default
50
+ puts "Watcher: [LISTEN]"
51
+ end
52
+
46
53
  launching_message = "Launching Retest..."
47
54
  if options.force_polling?
48
55
  launching_message = "Launching Retest with polling method..."
@@ -50,18 +57,18 @@ end
50
57
 
51
58
  # Main action
52
59
 
53
- $stdout.puts launching_message
54
- Retest.listen(options) do |modified, added, removed|
60
+ puts launching_message
61
+ Retest.listen(options, listener: watcher) do |modified, added, removed|
55
62
  begin
56
63
  repository.sync(added: added, removed: removed)
57
64
  runner.sync(added: added, removed: removed)
58
65
 
59
66
  listen_wr.puts "file changed: #{(modified + added).first}"
60
67
  rescue => e
61
- $stdout.puts "Something went wrong: #{e.message}"
68
+ puts "Something went wrong: #{e.message}"
62
69
  end
63
70
  end
64
- $stdout.puts "Ready to refactor! You can make file changes now"
71
+ puts "Ready to refactor! You can make file changes now"
65
72
 
66
73
  def run_command(input:, program:)
67
74
  program.clear_terminal
@@ -63,10 +63,19 @@ module Retest
63
63
  long "--diff=git-branch"
64
64
  end
65
65
 
66
- option :ext do
67
- desc "Regex of file extensions to listen to"
68
- long "--ext=regex"
69
- default "\\.rb$"
66
+ option :exts do
67
+ desc "Comma separated of filenames extensions to filter to"
68
+ long "--exts=<EXTENSIONS>"
69
+ default "rb"
70
+ convert :list
71
+ end
72
+
73
+ option :watcher do
74
+ desc "Tool used to watch file events"
75
+ permit %i[listen watchexec]
76
+ long "--watcher=<WATCHER>"
77
+ short "-w"
78
+ convert :sym
70
79
  end
71
80
 
72
81
  flag :all do
@@ -155,8 +164,12 @@ module Retest
155
164
  params[:polling]
156
165
  end
157
166
 
158
- def extension
159
- Regexp.new(params[:ext])
167
+ def extensions
168
+ params[:exts]
169
+ end
170
+
171
+ def watcher
172
+ params[:watcher] || :installed
160
173
  end
161
174
 
162
175
  def merge(options = [])
@@ -1,3 +1,3 @@
1
1
  module Retest
2
- VERSION = "2.0.0.pre4"
2
+ VERSION = "2.0.0.pre5"
3
3
  end
@@ -12,8 +12,12 @@ module Retest
12
12
  'git'
13
13
  end
14
14
 
15
- def files
16
- (untracked_files + tracked_files).sort
15
+ def files(extensions: [])
16
+ result = (untracked_files + tracked_files).sort
17
+ unless extensions.empty?
18
+ result.select! { |file| /\.(?:#{extensions.join('|')})$/.match?(file) }
19
+ end
20
+ result
17
21
  end
18
22
 
19
23
  def diff_files(branch)
@@ -12,8 +12,14 @@ module Retest
12
12
  'default'
13
13
  end
14
14
 
15
- def files
16
- Dir.glob('**/*') - Dir.glob('{tmp,node_modules}/**/*')
15
+ def files(extensions: [])
16
+ result = if extensions.empty?
17
+ Dir.glob('**/*')
18
+ else
19
+ Dir.glob("**/*.{#{extensions.join(',')}}")
20
+ end
21
+
22
+ result - Dir.glob('{tmp,node_modules}/**/*')
17
23
  end
18
24
  end
19
25
  end
@@ -6,8 +6,8 @@ module Retest
6
6
 
7
7
  module_function
8
8
 
9
- def files
10
- [Git, NoVersionControl].find(&:installed?).files
9
+ def files(extensions: [])
10
+ [Git, NoVersionControl].find(&:installed?).files(extensions: extensions)
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,122 @@
1
+ module Retest
2
+ module Watcher
3
+ def self.for(watcher)
4
+ tool = case watcher.to_s
5
+ when 'listen' then Default
6
+ when 'watchexec' then Watchexec
7
+ when '', 'installed' then installed
8
+ else raise ArgumentError, "Unknown #{watcher}"
9
+ end
10
+
11
+ unless tool.installed?
12
+ raise ArgumentError, "#{watcher} not installed on machine"
13
+ end
14
+
15
+ tool
16
+ end
17
+
18
+ def self.installed
19
+ [Watchexec, Default].find(&:installed?)
20
+ end
21
+
22
+ module Default
23
+ def self.installed?
24
+ true
25
+ end
26
+
27
+ def self.watch(dir:, extensions:, polling: false)
28
+ Listen.to(dir, only: extensions_regex(extensions), relative: true, polling: polling) do |modified, added, removed|
29
+ yield modified, added, removed
30
+ end.start
31
+ end
32
+
33
+ def self.extensions_regex(extensions)
34
+ Regexp.new("\\.(?:#{extensions.join("|")})$")
35
+ end
36
+ end
37
+
38
+ module Watchexec
39
+ def self.installed?
40
+ system "watchexec --version > /dev/null 2>&1"
41
+ end
42
+
43
+ def self.watch(dir:, extensions:, polling: false)
44
+ command = "watchexec --exts #{extensions.join(',')} -w #{dir} --emit-events-to stdio --no-meta --only-emit-events"
45
+ files = VersionControl.files(extensions: extensions).zip([]).to_h
46
+
47
+ watch_rd, watch_wr = IO.pipe
48
+ pid = Process.spawn(command, out: watch_wr)
49
+ at_exit do
50
+ Process.kill("TERM", pid) if pid
51
+ watch_rd.close
52
+ watch_wr.close
53
+ end
54
+
55
+ Thread.new do
56
+ loop do
57
+ ready = IO.select([watch_rd])
58
+ readable_connections = ready[0]
59
+ readable_connections.each do |conn|
60
+ data = conn.readpartial(4096)
61
+ change = /^(?:create|remove|rename|modify):(?<path>.*)/.match(data.strip)
62
+
63
+ next unless change
64
+
65
+ path = Pathname(change[:path]).relative_path_from(Dir.pwd).to_s
66
+ file_exist = File.exist?(path)
67
+ file_cached = files.key?(path)
68
+
69
+ modified, added, removed = result = [[], [], []]
70
+ if file_exist && file_cached
71
+ modified << path
72
+ elsif file_exist && !file_cached
73
+ added << path
74
+ files[path] = nil
75
+ elsif !file_exist && file_cached
76
+ removed << path
77
+ files.delete(path)
78
+ end
79
+
80
+ yield result
81
+ end
82
+ end
83
+ end
84
+
85
+ # require 'open3'
86
+ # Thread.new do
87
+ # files = VersionControl.files(extensions: extensions).zip([]).to_h
88
+
89
+ # Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
90
+ # loop do
91
+ # ready = IO.select([stdout])
92
+ # readable_connections = ready[0]
93
+ # readable_connections.each do |conn|
94
+ # data = conn.readpartial(4096)
95
+ # change = /^(?:create|remove|rename|modify):(?<path>.*)/.match(data.strip)
96
+
97
+ # next unless change
98
+
99
+ # path = Pathname(change[:path]).relative_path_from(Dir.pwd).to_s
100
+ # file_exist = File.exist?(path)
101
+ # file_cached = files.key?(path)
102
+
103
+ # modified, added, removed = result = [[], [], []]
104
+ # if file_exist && file_cached
105
+ # modified << path
106
+ # elsif file_exist && !file_cached
107
+ # added << path
108
+ # files[path] = nil
109
+ # elsif !file_exist && file_cached
110
+ # removed << path
111
+ # files.delete(path)
112
+ # end
113
+
114
+ # yield result
115
+ # end
116
+ # end
117
+ # end
118
+ # end
119
+ end
120
+ end
121
+ end
122
+ end
data/lib/retest.rb CHANGED
@@ -15,6 +15,7 @@ require "retest/file_system"
15
15
  require "retest/program"
16
16
  require "retest/prompt"
17
17
  require "retest/sounds"
18
+ require "retest/watcher"
18
19
 
19
20
  Listen.adapter_warn_behavior = :log
20
21
 
@@ -22,9 +23,9 @@ module Retest
22
23
  class Error < StandardError; end
23
24
  class FileNotFound < StandardError; end
24
25
 
25
- def self.listen(options, listener: Listen)
26
- listener.to('.', only: options.extension, relative: true, force_polling: options.force_polling?) do |modified, added, removed|
26
+ def self.listen(options, listener: Watcher::Default)
27
+ listener.watch(dir: '.', extensions: options.extensions, polling: options.force_polling?) do |modified, added, removed|
27
28
  yield modified, added, removed
28
- end.start
29
+ end
29
30
  end
30
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: retest
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre4
4
+ version: 2.0.0.pre5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Barret
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-25 00:00:00.000000000 Z
11
+ date: 2024-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: string-similarity
@@ -97,6 +97,7 @@ files:
97
97
  - README.md
98
98
  - README/demo.gif
99
99
  - Rakefile
100
+ - bin/build/watchexec
100
101
  - bin/console
101
102
  - bin/debug
102
103
  - bin/setup
@@ -109,6 +110,7 @@ files:
109
110
  - bin/test/rspec-ruby
110
111
  - bin/test/ruby-app
111
112
  - bin/test/ruby-bare
113
+ - builds/dockerfiles/WatchexecSlimBullseye
112
114
  - exe/retest
113
115
  - lib/retest.rb
114
116
  - lib/retest/command.rb
@@ -135,6 +137,7 @@ files:
135
137
  - lib/retest/version_control.rb
136
138
  - lib/retest/version_control/git.rb
137
139
  - lib/retest/version_control/no_version_control.rb
140
+ - lib/retest/watcher.rb
138
141
  - retest.gemspec
139
142
  homepage: https://github.com/AlexB52/retest
140
143
  licenses: