headless 2.3.1 → 3.0.0

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
- SHA1:
3
- metadata.gz: 48dcd948b7a967c43fd2755dc78ed357f950543f
4
- data.tar.gz: ee15e1c2c6ab1f026103d2dae5b6785290eed70c
2
+ SHA256:
3
+ metadata.gz: 73b67eca56b8f3e94adeb95432880e74468bf145e91d5c6c72e31d4aa35666a8
4
+ data.tar.gz: adea55f03a50f1d535397e5c26c0c1f5926a86cff454df8c51b359d6ae080d6d
5
5
  SHA512:
6
- metadata.gz: fbef1773c54315ee9c970d9ccbdf61b0a7be03c20c46ec9b1ea57bb26bf6120e06bd356bd192fbd5c9ed19aec259d8dfdb8e3832ed2edaabf319e2dee9afc43b
7
- data.tar.gz: e9e037eb919cec501e19be270f7ef0bb82955a7f15e9fa1fcd04df8f3c65a92fdb02c23de8bd3b7a4d76a07160a1c2a0418ed3b0646a62fd99f46c521606e95b
6
+ metadata.gz: '083d766fb621d8fe7c9efa94b2489c78d8d3a993e697ee066750bec64a502fd46c300107a0a105e2dcaa0d66ed0ed29a797911d821244409defa83dc3d1b1afc'
7
+ data.tar.gz: 8a56cbbe08e1bce612eeccdbd999f88510cf0371799c210f0ce26975a601ad47d361622d14eee769c1335d2ca256efae1ac43e41440c0e3edabd6b519835a39d
@@ -0,0 +1,38 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ matrix:
12
+ ruby:
13
+ - "3.4"
14
+ - "3.3"
15
+ - "3.2"
16
+ - "jruby-10.0.0.1"
17
+ - "jruby-9.4.12.1"
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - name: Set up Ruby
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby }}
24
+ bundler-cache: true
25
+ - name: Install system dependencies
26
+ run: |
27
+ sudo apt-get update
28
+ sudo apt-get install -y ffmpeg imagemagick
29
+ - name: Install geckodriver
30
+ env:
31
+ GECKODRIVER_VERSION: v0.36.0
32
+ run: |
33
+ wget https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz
34
+ mkdir -p geckodriver
35
+ tar -xzf geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz -C geckodriver
36
+ echo "$GITHUB_WORKSPACE/geckodriver" >> $GITHUB_PATH
37
+ - name: Run tests
38
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -1,3 +1,2 @@
1
1
  .bundle
2
- Gemfile.lock
3
2
  pkg/*
data/CHANGELOG CHANGED
@@ -1,73 +1,80 @@
1
+ ## 3.0.0 (2025-05-10)
2
+
3
+ - Better late then never!
4
+ - Support all modern Rubies.
5
+ - Drop support of Ruby before 3.2.
6
+ - Drop `avconv` because it's no longer maintained.
7
+
1
8
  ## 2.3.1 (2016-08-25)
2
9
 
3
- * Full JRuby support
4
- * HOTFIX remove `mkmf` require.
10
+ - Full JRuby support
11
+ - HOTFIX remove `mkmf` require.
5
12
 
6
13
  ## 2.3.0 (2016-08-24)
7
14
 
8
- * Remove dependency on the `which` command (from @skateman)
9
- * Add `devices` options to video recorder (from @atzorvas)
10
- * By default, do not destroy Headless started by a different process (from @marxarelli)
15
+ - Remove dependency on the `which` command (from @skateman)
16
+ - Add `devices` options to video recorder (from @atzorvas)
17
+ - By default, do not destroy Headless started by a different process (from @marxarelli)
11
18
 
12
19
  ## 2.2.3 (2016-03-17)
13
20
 
14
- * Fix race condition when starting Xvfb [#75] (from @NfNitLoop)
21
+ - Fix race condition when starting Xvfb [#75] (from @NfNitLoop)
15
22
 
16
23
  ## 2.2.2 (2016-02-08)
17
24
 
18
- * Fix file permissions issue with gem. No actual changes
25
+ - Fix file permissions issue with gem. No actual changes
19
26
 
20
27
  ## 2.2.0 (2015-07-05)
21
28
 
22
- * Allow reuse of displays started by other user (from @marxarelli)
23
- * Add support for graphicsmagick instead of ImageMagick (from @BlakeMesdag)
24
- * Wait for Xvfb to finish when destroying it, to avoid creating zombie processes (from @samnissen)
29
+ - Allow reuse of displays started by other user (from @marxarelli)
30
+ - Add support for graphicsmagick instead of ImageMagick (from @BlakeMesdag)
31
+ - Wait for Xvfb to finish when destroying it, to avoid creating zombie processes (from @samnissen)
25
32
 
26
33
  ## 2.1.0 (2015-05-10)
27
34
 
28
- * Allow path to video recorder binary to be customized (from @briandamaged)
35
+ - Allow path to video recorder binary to be customized (from @briandamaged)
29
36
 
30
37
  ## 2.0.0 (2015-04-23)
31
38
 
32
- * Rewritten Xvfb launch using Process.spawn and avoiding a shell
33
- * Do not manually remove X11 lock file when stopping Xvfb; this isn’t conventional. Should eliminate some errors with not being able to find Xvfb
34
- * More informative error messages
35
- * Detect situation when Xvfb can’t listen to any sockets and raise corresponding error.
36
- * If video recorder provider is libav, use avconv binary instead of ffmpeg
37
- * Fixes to video recorder launch options (from @gpavlidi, @abotalov, @ynagorny, @WeAreFarmGeek)
38
- * Customize launch timeout (from @ShockwaveNN)
39
- * Properly working integration tests
39
+ - Rewritten Xvfb launch using Process.spawn and avoiding a shell
40
+ - Do not manually remove X11 lock file when stopping Xvfb; this isn’t conventional. Should eliminate some errors with not being able to find Xvfb
41
+ - More informative error messages
42
+ - Detect situation when Xvfb can’t listen to any sockets and raise corresponding error.
43
+ - If video recorder provider is libav, use avconv binary instead of ffmpeg
44
+ - Fixes to video recorder launch options (from @gpavlidi, @abotalov, @ynagorny, @WeAreFarmGeek)
45
+ - Customize launch timeout (from @ShockwaveNN)
46
+ - Properly working integration tests
40
47
 
41
48
  ## 1.0.2 (2014-06-03)
42
49
 
43
- * pass options correctly to ffmpeg (from @abotalov)
44
- * only destroy headless if it was created (from @evandrodp)
50
+ - pass options correctly to ffmpeg (from @abotalov)
51
+ - only destroy headless if it was created (from @evandrodp)
45
52
 
46
53
  ## 1.0.1 (2013-02-20)
47
54
 
48
- * when starting, wait for Xvfb to launch (fixed issue #33)
55
+ - when starting, wait for Xvfb to launch (fixed issue #33)
49
56
 
50
57
  ## 1.0.0 (2013-01-28)
51
58
 
52
- * bugfix release
53
- * version number compliant to the [semantic versioning system](http://semver.org)
59
+ - bugfix release
60
+ - version number compliant to the [semantic versioning system](http://semver.org)
54
61
 
55
62
  ## 0.3.1 (2012-03-29)
56
63
 
57
- * added autopicking of display number, if the requested one is already taken
58
- * fixed plenty of bugs thanks to @recursive, @gshakhn, @masatomo and @mabotelh
64
+ - added autopicking of display number, if the requested one is already taken
65
+ - fixed plenty of bugs thanks to @recursive, @gshakhn, @masatomo and @mabotelh
59
66
 
60
67
  ## 0.2.2 (2011-09-01)
61
68
 
62
- * improve detection of ffmpeg process (from https://github.com/alanshields/headless)
69
+ - improve detection of ffmpeg process (from https://github.com/alanshields/headless)
63
70
 
64
71
  ## 0.2.1 (2011-08-26)
65
72
 
66
- * added ability to capture screenshots (from https://github.com/iafonov/headless)
67
- * added ability to capture video (from https://github.com/iafonov/headless)
68
- * fixed issue with stray pidfile
73
+ - added ability to capture screenshots (from https://github.com/iafonov/headless)
74
+ - added ability to capture video (from https://github.com/iafonov/headless)
75
+ - fixed issue with stray pidfile
69
76
 
70
77
  ## 0.1.0 (2010-08-15)
71
78
 
72
- * introduced options
73
- * make it possible to change virtual screen dimensions and pixel depth
79
+ - introduced options
80
+ - make it possible to change virtual screen dimensions and pixel depth
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in ci_util.gemspec
3
+ # Specify dependencies in headless.gemspec
4
4
  gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,96 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ headless (3.0.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ ast (2.4.3)
10
+ base64 (0.2.0)
11
+ diff-lcs (1.6.1)
12
+ json (2.11.3)
13
+ json (2.11.3-java)
14
+ language_server-protocol (3.17.0.4)
15
+ lint_roller (1.1.0)
16
+ logger (1.7.0)
17
+ parallel (1.27.0)
18
+ parser (3.3.8.0)
19
+ ast (~> 2.4.1)
20
+ racc
21
+ prism (1.4.0)
22
+ racc (1.8.1)
23
+ racc (1.8.1-java)
24
+ rainbow (3.1.1)
25
+ rake (13.2.1)
26
+ regexp_parser (2.10.0)
27
+ rexml (3.4.1)
28
+ rspec (3.13.0)
29
+ rspec-core (~> 3.13.0)
30
+ rspec-expectations (~> 3.13.0)
31
+ rspec-mocks (~> 3.13.0)
32
+ rspec-core (3.13.3)
33
+ rspec-support (~> 3.13.0)
34
+ rspec-expectations (3.13.4)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.13.0)
37
+ rspec-mocks (3.13.4)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.13.0)
40
+ rspec-support (3.13.3)
41
+ rubocop (1.75.5)
42
+ json (~> 2.3)
43
+ language_server-protocol (~> 3.17.0.2)
44
+ lint_roller (~> 1.1.0)
45
+ parallel (~> 1.10)
46
+ parser (>= 3.3.0.2)
47
+ rainbow (>= 2.2.2, < 4.0)
48
+ regexp_parser (>= 2.9.3, < 3.0)
49
+ rubocop-ast (>= 1.44.0, < 2.0)
50
+ ruby-progressbar (~> 1.7)
51
+ unicode-display_width (>= 2.4.0, < 4.0)
52
+ rubocop-ast (1.44.1)
53
+ parser (>= 3.3.7.2)
54
+ prism (~> 1.4)
55
+ rubocop-performance (1.25.0)
56
+ lint_roller (~> 1.1)
57
+ rubocop (>= 1.75.0, < 2.0)
58
+ rubocop-ast (>= 1.38.0, < 2.0)
59
+ ruby-progressbar (1.13.0)
60
+ rubyzip (2.4.1)
61
+ selenium-webdriver (4.32.0)
62
+ base64 (~> 0.2)
63
+ logger (~> 1.4)
64
+ rexml (~> 3.2, >= 3.2.5)
65
+ rubyzip (>= 1.2.2, < 3.0)
66
+ websocket (~> 1.0)
67
+ standard (1.49.0)
68
+ language_server-protocol (~> 3.17.0.2)
69
+ lint_roller (~> 1.0)
70
+ rubocop (~> 1.75.2)
71
+ standard-custom (~> 1.0.0)
72
+ standard-performance (~> 1.8)
73
+ standard-custom (1.0.2)
74
+ lint_roller (~> 1.0)
75
+ rubocop (~> 1.50)
76
+ standard-performance (1.8.0)
77
+ lint_roller (~> 1.1)
78
+ rubocop-performance (~> 1.25.0)
79
+ unicode-display_width (3.1.4)
80
+ unicode-emoji (~> 4.0, >= 4.0.4)
81
+ unicode-emoji (4.0.4)
82
+ websocket (1.2.11)
83
+
84
+ PLATFORMS
85
+ java
86
+ ruby
87
+
88
+ DEPENDENCIES
89
+ headless!
90
+ rake
91
+ rspec (>= 3.7)
92
+ selenium-webdriver (>= 4.32)
93
+ standard
94
+
95
+ BUNDLED WITH
96
+ 2.6.8
data/README.md CHANGED
@@ -1,6 +1,11 @@
1
- # Headless [![Travis CI status](https://secure.travis-ci.org/leonid-shevtsov/headless.png)](http://travis-ci.org/leonid-shevtsov/headless)
1
+ # Headless
2
2
 
3
- Headless is *the* Ruby interface for Xvfb. It allows you to create a headless display straight from Ruby code, hiding the low-level action.
3
+ ![Gem Version](https://img.shields.io/gem/v/headless)
4
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/leonid-shevtsov/headless/test.yml)
5
+
6
+ <a href="https://www.buymeacoffee.com/leonidshevtsov" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
7
+
8
+ Headless is _the_ Ruby interface for Xvfb. It allows you to create a headless display straight from Ruby code, hiding the low-level action.
4
9
  It can also capture images and video from the virtual framebuffer. For example, you can record screenshots and screencasts of your failing integration specs.
5
10
 
6
11
  I created it so I can run Selenium tests in Cucumber without any shell scripting. Even more, you can go headless only when you run tests against Selenium.
@@ -10,7 +15,7 @@ Documentation is available at [rubydoc.info](http://www.rubydoc.info/gems/headle
10
15
 
11
16
  [Changelog](https://github.com/leonid-shevtsov/headless/blob/master/CHANGELOG)
12
17
 
13
- **Note: Headless will NOT hide most applications on OS X. [Here is a detailed explanation](https://github.com/leonid-shevtsov/headless/issues/31#issuecomment-8933108)**
18
+ **Note: Headless will NOT hide most applications on macOS. [Here is a detailed explanation](https://github.com/leonid-shevtsov/headless/issues/31#issuecomment-8933108)**
14
19
 
15
20
  ## Installation
16
21
 
@@ -33,7 +38,7 @@ require 'selenium-webdriver'
33
38
  Headless.ly do
34
39
  driver = Selenium::WebDriver.for :firefox
35
40
  driver.navigate.to 'http://google.com'
36
- puts driver.title
41
+ puts driver.title
37
42
  end
38
43
  ```
39
44
 
@@ -80,11 +85,11 @@ Headless.new(display: 100, destroy_at_exit: false).start
80
85
  # test_suite_that_could_be_ran_multiple_times.rb
81
86
  Headless.new(display: 100, reuse: true, destroy_at_exit: false).start
82
87
 
83
- # reap_headless.rb
88
+ # reap_headless.rb
84
89
  headless = Headless.new(display: 100, reuse: true)
85
90
  headless.destroy
86
91
 
87
- # kill_headless_without_waiting.rb
92
+ # kill_headless_without_waiting.rb
88
93
  headless = Headless.new
89
94
  headless.destroy_without_sync
90
95
  ```
@@ -135,14 +140,13 @@ headless = Headless.new(:video => { :frame_rate => 12, :codec => 'libx264' })
135
140
 
136
141
  Available options:
137
142
 
138
- * :codec - codec to be used by ffmpeg
139
- * :frame_rate - frame rate of video capture
140
- * :provider - ffmpeg provider - either :libav (default) or :ffmpeg
141
- * :provider_binary_path - Explicit path to avconv or ffmpeg. Only required when the binary cannot be discovered on the system $PATH.
142
- * :pid_file_path - path to ffmpeg pid file, default: "/tmp/.headless_ffmpeg_#{@display}.pid"
143
- * :tmp_file_path - path to tmp video file, default: "/tmp/.headless_ffmpeg_#{@display}.mov"
144
- * :log_file_path - ffmpeg log file, default: "/dev/null"
145
- * :extra - array of extra ffmpeg options, default: []
143
+ - :codec - codec to be used by ffmpeg
144
+ - :frame_rate - frame rate of video capture
145
+ - :ffmpeg_path - Explicit path to ffmpeg. Only required when the binary cannot be discovered on the system $PATH.
146
+ - :pid*file_path - path to ffmpeg pid file, default: "/tmp/.headless_ffmpeg*#{@display}.pid"
147
+ - :tmp*file_path - path to tmp video file, default: "/tmp/.headless_ffmpeg*#{@display}.mov"
148
+ - :log_file_path - ffmpeg log file, default: "/dev/null"
149
+ - :extra - array of extra ffmpeg options, default: []
146
150
 
147
151
  ## Taking screenshots
148
152
 
@@ -150,23 +154,39 @@ Call `headless.take_screenshot` to take a screenshot. It needs two arguments:
150
154
 
151
155
  - file_path - path where the image should be stored
152
156
  - options - options, that can be:
153
- :using - :imagemagick or :xwd, :imagemagick is default, if :imagemagick is used, image format is determined by file_path extension
157
+ :using - :imagemagick or :xwd, :imagemagick is default, if :imagemagick is used, image format is determined by file_path extension
154
158
 
155
159
  Screenshots can be taken by either using `import` (part of `imagemagick` library) or `xwd` utility.
156
160
 
157
- `import` captures a screenshot and saves it in the format of the specified file. It is convenient but not too fast as
161
+ `import` captures a screenshot and saves it in the format of the specified file. It is convenient but not too fast as
158
162
  it has to do the encoding synchronously.
159
163
 
160
- `xwd` will capture a screenshot very fast and store it in its own format, which can then be converted to one
164
+ `xwd` will capture a screenshot very fast and store it in its own format, which can then be converted to one
161
165
  of other picture formats using, for example, netpbm utilities - `xwdtopnm <xwd_file> | pnmtopng > capture.png`.
162
166
 
163
167
  To install the necessary libraries on ubuntu:
164
168
 
165
169
  `import` - run `sudo apt-get install imagemagick`
166
170
  `xwd` - run `sudo apt-get install X11-apps` and if you are going to use netpbm utilities for image conversion - `sudo apt-get install netpbm`
167
-
171
+
168
172
  ## Troubleshooting
169
173
 
174
+ ### `/tmp/.X11-unix` is missing
175
+
176
+ Xvfb requires this directory to exist. It cannot be created automatically, because the directory must be owned by the root user. (You will never get this error if running as root - for example, in a Docker container.)
177
+
178
+ On macOS, the directory will be created when you run XQuartz.app. But since `/tmp` is cleared on reboot, you will need to open XQuartz.app after a reboot before running Xvfb. (You don't need to leave it running.)
179
+
180
+ To create this directory manually, on either macOS or Linux:
181
+
182
+ ```
183
+ mkdir /tmp/.X11-unix
184
+ sudo chmod 1777 /tmp/.X11-unix
185
+ sudo chown root /tmp/.X11-unix/
186
+ ```
187
+
188
+ Note that you may need to run these commands after every reboot, too.
189
+
170
190
  ### Display socket is taken but lock file is missing
171
191
 
172
192
  This means that there is an X server that is taking up the chosen display number, but its lock file is missing. This is an exceptional situation. Please stop the server process manually (`pkill Xvfb`) and open an issue.
@@ -175,9 +195,8 @@ This means that there is an X server that is taking up the chosen display number
175
195
 
176
196
  If video is not recording, and there are no visible exceptions, try passing the following option to Headless to figure out the reason: `Headless.new(video: {log_file_path: STDERR})`. In particular, there are some issues with the version of avconv packaged with Ubuntu 12.04 - an outdated release, but still in use on Travis.
177
197
 
178
-
179
198
  ##[Contributors](https://github.com/leonid-shevtsov/headless/graphs/contributors)
180
199
 
181
200
  ---
182
201
 
183
- &copy; 2011-2015 Leonid Shevtsov, released under the MIT license
202
+ &copy; 2011-2025 [Leonid Shevtsov](https://leonid.shevtsov.me), released under the MIT license
data/headless.gemspec CHANGED
@@ -1,21 +1,22 @@
1
1
  Gem::Specification.new do |s|
2
- s.author = 'Leonid Shevtsov'
3
- s.email = 'leonid@shevtsov.me'
2
+ s.author = "Leonid Shevtsov"
3
+ s.email = "leonid@shevtsov.me"
4
4
 
5
- s.name = 'headless'
6
- s.version = '2.3.1'
7
- s.summary = 'Ruby headless display interface'
8
- s.license = 'MIT'
5
+ s.name = "headless"
6
+ s.version = "3.0.0"
7
+ s.summary = "Ruby headless display interface"
8
+ s.license = "MIT"
9
9
 
10
10
  s.description = <<-EOF
11
11
  Headless is a Ruby interface for Xvfb. It allows you to create a headless display straight from Ruby code, hiding some low-level action.
12
12
  EOF
13
- s.requirements = 'Xvfb'
14
- s.homepage = 'http://leonid.shevtsov.me/en/headless'
13
+ s.requirements = "Xvfb"
14
+ s.homepage = "https://github.com/leonid-shevtsov/headless"
15
15
 
16
- s.files = `git ls-files`.split("\n")
16
+ s.files = `git ls-files`.split("\n")
17
17
 
18
- s.add_development_dependency 'rake'
19
- s.add_development_dependency 'rspec', '~> 3'
20
- s.add_development_dependency 'selenium-webdriver'
18
+ s.add_development_dependency "rake"
19
+ s.add_development_dependency "rspec", ">= 3.7"
20
+ s.add_development_dependency "selenium-webdriver", ">=4.32"
21
+ s.add_development_dependency "standard"
21
22
  end
@@ -5,21 +5,21 @@ class Headless
5
5
  end
6
6
 
7
7
  def self.ensure_application_exists!(app, error_message)
8
- if !self.application_exists?(app)
8
+ if !application_exists?(app)
9
9
  raise Headless::Exception.new(error_message)
10
10
  end
11
11
  end
12
12
 
13
13
  # Credit: http://stackoverflow.com/a/5471032/6678
14
14
  def self.path_to(app)
15
- exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
16
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
15
+ exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
16
+ ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
17
17
  exts.each { |ext|
18
18
  exe = File.join(path, "#{app}#{ext}")
19
19
  return exe if File.executable?(exe) && !File.directory?(exe)
20
20
  }
21
21
  end
22
- return nil
22
+ nil
23
23
  end
24
24
 
25
25
  def self.process_mine?(pid)
@@ -35,21 +35,26 @@ class Headless
35
35
  end
36
36
 
37
37
  def self.read_pid(pid_filename)
38
- pid = (File.read(pid_filename) rescue "").strip
38
+ pid = begin
39
+ File.read(pid_filename)
40
+ rescue
41
+ ""
42
+ end.strip
39
43
  pid.empty? ? nil : pid.to_i
40
44
  end
41
45
 
42
- def self.fork_process(command, pid_filename, log_filename='/dev/null')
46
+ def self.fork_process(command, pid_filename, log_filename = File::NULL)
43
47
  pid = Process.spawn(command, err: log_filename)
44
- File.open pid_filename, 'w' do |f|
48
+ File.open pid_filename, "w" do |f|
45
49
  f.puts pid
46
50
  end
47
51
  end
48
52
 
49
- def self.kill_process(pid_filename, options={})
50
- if pid = read_pid(pid_filename)
53
+ def self.kill_process(pid_filename, options = {})
54
+ pid = read_pid(pid_filename)
55
+ if pid
51
56
  begin
52
- Process.kill 'TERM', pid
57
+ Process.kill "TERM", pid
53
58
  Process.wait pid if options[:wait]
54
59
  rescue Errno::ESRCH
55
60
  # no such process; assume it's already killed
@@ -1,16 +1,15 @@
1
- require 'tempfile'
1
+ require "tempfile"
2
2
 
3
3
  class Headless
4
4
  class VideoRecorder
5
- attr_accessor :pid_file_path, :tmp_file_path, :log_file_path, :provider_binary_path
5
+ attr_accessor :pid_file_path, :tmp_file_path, :log_file_path, :ffmpeg_path
6
6
 
7
7
  # Construct a new Video Recorder instance. Typically done from inside Headless, but can be also created manually,
8
8
  # and even used separately from Headless' Xvfb features.
9
9
  # * display - display number to capture
10
10
  # * dimensions - dimensions of the captured video
11
11
  # * options - available options:
12
- # * provider - either :ffmpeg or :libav; default is :libav - switch if your system is provisioned with FFMpeg
13
- # * provider_binary_path - override path to ffmpeg / libav binary
12
+ # * ffmpeg_path - override path to ffmpeg binary
14
13
  # * pid_file_path - override path to PID file, default is placed in /tmp
15
14
  # * tmp_file_path - override path to temp file, default is placed in /tmp
16
15
  # * log_file_path - set log file path, default is /dev/null
@@ -24,19 +23,19 @@ class Headless
24
23
 
25
24
  @pid_file_path = options.fetch(:pid_file_path, "/tmp/.headless_ffmpeg_#{@display}.pid")
26
25
  @tmp_file_path = options.fetch(:tmp_file_path, "/tmp/.headless_ffmpeg_#{@display}.mov")
27
- @log_file_path = options.fetch(:log_file_path, "/dev/null")
26
+ @log_file_path = options.fetch(:log_file_path, File::NULL)
28
27
  @codec = options.fetch(:codec, "qtrle")
29
28
  @frame_rate = options.fetch(:frame_rate, 30)
30
- @provider = options.fetch(:provider, :libav) # or :ffmpeg
31
29
 
32
- # If no provider_binary_path was specified, then
33
- # make a guess based upon the provider.
34
- @provider_binary_path = options.fetch(:provider_binary_path, guess_the_provider_binary_path)
30
+ # If no ffmpeg_path was specified, use the default
31
+ @ffmpeg_path = options.fetch(:ffmpeg_path, options.fetch(:provider_binary_path, "ffmpeg"))
35
32
 
36
33
  @extra = Array(options.fetch(:extra, []))
37
34
  @devices = Array(options.fetch(:devices, []))
38
35
 
39
- CliUtil.ensure_application_exists!(provider_binary_path, "#{provider_binary_path} not found on your system. Install it or change video recorder provider")
36
+ CliUtil.ensure_application_exists!(ffmpeg_path,
37
+ "#{ffmpeg_path} not found on your system. " \
38
+ "Install it or change video recorder provider")
40
39
  end
41
40
 
42
41
  def capture_running?
@@ -45,7 +44,7 @@ class Headless
45
44
 
46
45
  def start_capture
47
46
  CliUtil.fork_process(command_line_for_capture,
48
- @pid_file_path, @log_file_path)
47
+ @pid_file_path, @log_file_path)
49
48
  at_exit do
50
49
  exit_status = $!.status if $!.is_a?(SystemExit)
51
50
  stop_and_discard
@@ -54,9 +53,10 @@ class Headless
54
53
  end
55
54
 
56
55
  def stop_and_save(path)
57
- CliUtil.kill_process(@pid_file_path, :wait => true)
58
- if File.exists? @tmp_file_path
56
+ CliUtil.kill_process(@pid_file_path, wait: true)
57
+ if File.exist? @tmp_file_path
59
58
  begin
59
+ FileUtils.mkdir_p(File.dirname(path))
60
60
  FileUtils.mv(@tmp_file_path, path)
61
61
  rescue Errno::EINVAL
62
62
  nil
@@ -65,7 +65,7 @@ class Headless
65
65
  end
66
66
 
67
67
  def stop_and_discard
68
- CliUtil.kill_process(@pid_file_path, :wait => true)
68
+ CliUtil.kill_process(@pid_file_path, wait: true)
69
69
  begin
70
70
  FileUtils.rm(@tmp_file_path)
71
71
  rescue Errno::ENOENT
@@ -75,32 +75,21 @@ class Headless
75
75
 
76
76
  private
77
77
 
78
- def guess_the_provider_binary_path
79
- @provider== :libav ? 'avconv' : 'ffmpeg'
80
- end
81
-
82
78
  def command_line_for_capture
83
- if @provider == :libav
84
- group_of_pic_size_option = '-g 600'
85
- dimensions = @dimensions
86
- else
87
- group_of_pic_size_option = nil
88
- dimensions = @dimensions.match(/^(\d+x\d+)/)[0]
89
- end
79
+ dimensions = @dimensions.match(/^(\d+x\d+)/)[0]
90
80
 
91
81
  [
92
- CliUtil.path_to(provider_binary_path),
93
- "-y",
94
- "-r #{@frame_rate}",
95
- "-s #{dimensions}",
96
- "-f x11grab",
97
- @devices,
98
- "-i :#{@display}",
99
- group_of_pic_size_option,
100
- "-vcodec #{@codec}",
101
- @extra,
102
- @tmp_file_path
103
- ].flatten.compact.join(' ')
82
+ CliUtil.path_to(ffmpeg_path),
83
+ "-y",
84
+ "-r #{@frame_rate}",
85
+ "-s #{dimensions}",
86
+ "-f x11grab",
87
+ "-i :#{@display}",
88
+ @devices,
89
+ "-vcodec #{@codec}",
90
+ @extra,
91
+ @tmp_file_path
92
+ ].flatten.compact.join(" ")
104
93
  end
105
94
  end
106
95
  end