cli_chef 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +77 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/cli_chef.gemspec +35 -0
- data/lib/bblib/bbfiles.rb +24 -0
- data/lib/cli_chef.rb +4 -0
- data/lib/cli_chef/apps/hand_brake.rb +149 -0
- data/lib/cli_chef/apps/hand_brake/hand_brake_job.rb +11 -0
- data/lib/cli_chef/apps/media_info.rb +65 -0
- data/lib/cli_chef/apps/sevenzip.rb +138 -0
- data/lib/cli_chef/apps/sevenzip/archive.rb +43 -0
- data/lib/cli_chef/apps/sevenzip/dir.rb +11 -0
- data/lib/cli_chef/apps/sevenzip/file.rb +15 -0
- data/lib/cli_chef/apps/sevenzip/item.rb +35 -0
- data/lib/cli_chef/apps/sevenzip/util.rb +28 -0
- data/lib/cli_chef/cli_chef.rb +6 -0
- data/lib/cli_chef/components/cookbook.rb +104 -0
- data/lib/cli_chef/components/exit_code.rb +19 -0
- data/lib/cli_chef/components/ingredient.rb +46 -0
- data/lib/cli_chef/components/job.rb +103 -0
- data/lib/cli_chef/components/result.rb +11 -0
- data/lib/cli_chef/version.rb +3 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 416dd42c45a904147359ae950761aa5bdfbcdab7bcff5d175ea191f98fe172b2
|
4
|
+
data.tar.gz: 0ea2d4a6b54f39b8861a20028391ebad0b63e8867b8eafddb7131b2b26bbc1c4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c062117a34fadd35f7cf88d1c0b1e6d3cdc27a871eff561b02a22727e6cae6b3530e9ba50344828fe17b6e7c70c43f697e5c458bd3c52bcf6e73b69ecbc4c548
|
7
|
+
data.tar.gz: 97fb7864b53d18eb8bd7718de21e5a38446c8df2ed5c0b9186f2c9e9981bd4ebf14815431abf63e98c8f0f4459d096b7471d8e1b13db0a5ec3dfe364f1865a2f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Brandon
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# CLIChef
|
2
|
+
|
3
|
+
CLI Chef is a simple command line interface wrapper for Ruby. It is made to make writing wrappers an easy and flexible process.
|
4
|
+
Basic examples of how to use CLIChef are included in the wrappers directory.
|
5
|
+
These are also full functional CLI wrappers for the following apps:
|
6
|
+
|
7
|
+
- 7Zip
|
8
|
+
- MediaInfo
|
9
|
+
- Handbrake
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
|
14
|
+
__Note:__ Currently this gem is not available via RubyGems.
|
15
|
+
Once it is the following is how to install it.
|
16
|
+
For now, grab it from github.
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem 'cli_chef'
|
22
|
+
```
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
$ gem install cli_chef
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
CLI Chef is made up of the following components:
|
35
|
+
|
36
|
+
- *Cookbook*: A cookbook is the base wrapper class of CLI Chef. The cookbook handles interaction with the CLI. It stores all possible ingredients. It also contains an exit code map, default application locations and the results of the previously run command.
|
37
|
+
- *Ingredient*: An ingredient is essentially a CLI argument. It contains a name for the argument, its flag (if it has one) and its value (again, if it has one). There are many other properties in ingredients that control how it is constructed. For more detailed information, check out the source code or one of the sample wrappers.
|
38
|
+
|
39
|
+
### Examples
|
40
|
+
|
41
|
+
A few example wrappers comes with this gem. Check them out under the /lib/cli_chef/apps
|
42
|
+
directory. They are complete and showcase how easy it is to setup a basic wrapper.
|
43
|
+
|
44
|
+
## Pre-Built Wrappers
|
45
|
+
|
46
|
+
CLI Chef ships with several pre-made wrappers for 7Zip, HandBrake and MediaInfo. Below is an example of how to include these in your projects.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
# NOTE: You do not have to require cli_chef separately as the wrappers will if it is not already loaded.
|
50
|
+
require 'cli_chef'
|
51
|
+
|
52
|
+
# Load 7Zip
|
53
|
+
require 'cli_chef/apps/sevenzip'
|
54
|
+
|
55
|
+
# Load HandBrake
|
56
|
+
require 'cli_chef/apps/hand_brake'
|
57
|
+
|
58
|
+
# Load MediaInfo
|
59
|
+
require 'cli_chef/apps/media_info'
|
60
|
+
```
|
61
|
+
|
62
|
+
_NOTE: For the wrappers to work you must have the CLI executables for each of the above applications installed._
|
63
|
+
|
64
|
+
## Development
|
65
|
+
|
66
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
67
|
+
|
68
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
69
|
+
|
70
|
+
## Contributing
|
71
|
+
|
72
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/cli_chef. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
73
|
+
|
74
|
+
|
75
|
+
## License
|
76
|
+
|
77
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "cli_chef"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/cli_chef.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cli_chef/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cli_chef"
|
8
|
+
spec.version = CLIChef::VERSION
|
9
|
+
spec.authors = ["Brandon Black"]
|
10
|
+
spec.email = ["d2sm10@hotmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{CLI Chef is a simple and quick CLI wrapper framework for Ruby.}
|
13
|
+
spec.description = %q{CLI Chef makes building command line wrappers easy and simple to incorporate with your Ruby projects.}
|
14
|
+
spec.homepage = "http://github.com/bblack16/cli-chef"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
# if spec.respond_to?(:metadata)
|
20
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
+
# else
|
22
|
+
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
# end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "rspec"
|
33
|
+
|
34
|
+
spec.add_runtime_dependency 'bblib', '~> 1.0'
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BBLib
|
4
|
+
def self.scan_files_and_archives(*args)
|
5
|
+
sz = SevenZip.new
|
6
|
+
BBLib.scan_files(*args).flat_map do |file|
|
7
|
+
if archive?(file)
|
8
|
+
sz.list(file).flat_map { |afile, _data| "#{file}//#{afile}" }
|
9
|
+
else
|
10
|
+
file
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ARCHIVE_EXTENSIONS = %w[bz2 bzip2 tbz2 tbz gz gzip tgz tar wim swm xz txz zip zipx jar xpi odt ods
|
16
|
+
docx xlsx epub apm ar a deb lib arj cab chm chw chi chq msi msp doc xls ppt cpio
|
17
|
+
cramfs dmg ext ext2 ext3 ext4 img fat img hfs hfsx hxs hxi hxr hxq hxw lit ihex
|
18
|
+
iso img lzh lha lzma mbr mslz mub nsis ntfs img mbr rar r00 rpm ppmd qcow qcow2
|
19
|
+
qcow2c 001 squashfs udf iso img scap uefif vdi vhd vmdk wim esd xar pkg z taz ].freeze
|
20
|
+
|
21
|
+
def self.archive?(file)
|
22
|
+
ARCHIVE_EXTENSIONS.any? { |ext| file.to_s.end_with?(".#{ext}") }
|
23
|
+
end
|
24
|
+
end
|
data/lib/cli_chef.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'cli_chef' unless defined?(CLIChef::VERSION)
|
2
|
+
require_relative 'hand_brake/hand_brake_job'
|
3
|
+
|
4
|
+
class HandBrake < CLIChef::Cookbook
|
5
|
+
|
6
|
+
self.description = 'HandBrake is a tool for converting video from nearly any format to a selection of modern, widely supported codecs.'
|
7
|
+
self.default_job_class = HandBrakeJob
|
8
|
+
|
9
|
+
def help
|
10
|
+
run!(help: nil).body
|
11
|
+
end
|
12
|
+
|
13
|
+
def version
|
14
|
+
run!(version: nil).body.scan(/(?<=HandBrake\s)\d+\.\d+\.\d+/i).first
|
15
|
+
end
|
16
|
+
|
17
|
+
def encode(input, output, opts = {})
|
18
|
+
run(opts.merge(input: input, output: output)) do |line, stream, job|
|
19
|
+
job.task_count = line.scan(/(?<=of )\d+/).first.to_i
|
20
|
+
job.task = line.scan(/\d+(?= of)/).first.to_i
|
21
|
+
job.fps = line.scan(/\d+\.\d+(?= fps)/).first.to_f
|
22
|
+
job.average_fps = line.scan(/(?<=avg )\d+\.\d+(?= fps)/).first.to_f
|
23
|
+
job.eta = line.scan(/(?<=ETA ).*?(?=\))/).first.parse_duration rescue nil
|
24
|
+
percent = line.scan(/\d+\.\d+(?= %)/).first.to_f
|
25
|
+
if line.include?('Encode done!')
|
26
|
+
percent = 100.0
|
27
|
+
elsif job.task_count > 2 && percent > 0
|
28
|
+
percent /= job.task_count
|
29
|
+
percent += 50 * job.task
|
30
|
+
end
|
31
|
+
job.percent = percent unless percent < job.percent.to_i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
add_exit_codes(
|
36
|
+
{ code: 0, description: 'Clean exit' },
|
37
|
+
{ code: 1, description: 'Cancelled', error: true },
|
38
|
+
{ code: 2, description: 'Invalid Input', error: true },
|
39
|
+
{ code: 3, description: 'Initialization Error', error: true },
|
40
|
+
{ code: 4, description: 'Unknown Error', error: true }
|
41
|
+
)
|
42
|
+
|
43
|
+
add_default_locations(
|
44
|
+
'handbrakecli.exe',
|
45
|
+
'hanbrakecli',
|
46
|
+
'C:/Program Files/Handbrake/HandBrakeCLI.exe',
|
47
|
+
'C:/Program Files(x86)/Handbrake/HandBrakeCLI.exe',
|
48
|
+
'C:/Handbrake/HandBrakeCLI.exe'
|
49
|
+
)
|
50
|
+
|
51
|
+
add_ingredients(
|
52
|
+
{ name: :help, description: 'Print help', flag: '--help', allowed_values: [nil], aliases: [:h] },
|
53
|
+
{ name: :update, description: 'Check for updates and exit', flag: '--update', allowed_values: [nil], aliases: [] },
|
54
|
+
{ name: :verbose, description: 'Be verbose (optional argument: logging level)', flag: '--verbose', allowed_values: [1, 2, 3], aliases: [] },
|
55
|
+
{ name: :preset, description: 'Use a built-in preset. Capitalization matters, and if the preset name has spaces, surround it with double quotation marks', flag: '--preset', allowed_values: [String], aliases: [] },
|
56
|
+
{ name: :preset_list, description: 'See a list of available built-in presets', flag: '--preset-list', allowed_values: [nil], aliases: [] },
|
57
|
+
{ name: :no_dvd_nav, description: 'Do not use dvdnav for reading DVDs', flag: '--no-dvdnav', allowed_values: [nil], aliases: [] },
|
58
|
+
{ name: :no_open_cl, description: 'Disable use of OpenCL', flag: '--no-opencl', allowed_values: [nil], aliases: [] },
|
59
|
+
{ name: :input, description: 'Set input device', flag: '--input', allowed_values: [String], aliases: [] },
|
60
|
+
{ name: :title, description: 'Select a title to encode (0 to scan all titles only', flag: '--title', allowed_values: [Integer, String], aliases: [] },
|
61
|
+
{ name: :min_duration, description: 'Set the minimum title duration (in seconds). Shorter titles will not be scanned.', flag: '--min-duration', allowed_values: [Integer], aliases: [] },
|
62
|
+
{ name: :scan, description: 'Scan selected title only.', flag: '--scan', allowed_values: [nil], aliases: [] },
|
63
|
+
{ name: :main_feature, description: 'Detect and select the main feature title.', flag: '--main-feature', allowed_values: [nil], aliases: [] },
|
64
|
+
{ name: :chapters, description: 'Select chapters (e.g. \'1-3\' for chapters 1 to 3, or \'3\' for chapter 3 only', flag: '--chapters', allowed_values: [], aliases: [] },
|
65
|
+
{ name: :angle, description: 'Select the video angle (DVD or Blu-ray only)', flag: '--angle', allowed_values: [Integer], aliases: [] },
|
66
|
+
{ name: :previews, description: 'Select how many preview images are generated, and whether or not they\'re stored to disk (0 or 1).', flag: '--previews', allowed_values: [String], aliases: [] },
|
67
|
+
{ name: :start_at_preview, description: 'Start encoding at a given preview.', flag: '--start-at-preview', allowed_values: [(1..30)], aliases: [] },
|
68
|
+
{ name: :start_at, description: 'Start encoding at a given frame, duration (in seconds), or pts (on a 90kHz clock)', flag: '--start-at', allowed_values: [Object], aliases: [] },
|
69
|
+
{ name: :stop_at, description: 'Stop encoding at a given frame, duration (in seconds), or pts (on a 90kHz clock)', flag: '--stop-at', allowed_values: [Object], aliases: [] },
|
70
|
+
{ name: :output, description: 'Set output file name', flag: '--output', allowed_values: [String], aliases: [:out] },
|
71
|
+
{ name: :format, description: 'Set output container format (av_mp4/av_mkv)', flag: '--format', allowed_values: ['mp4', 'mkv', :mp4, :mkv], aliases: [] },
|
72
|
+
{ name: :markers, description: 'Add chapter markers', flag: '--markers', allowed_values: [String], aliases: [] },
|
73
|
+
{ name: :large_file, description: 'Create 64-bit mp4 files that can hold more than 4 GB of data. Note: breaks pre-iOS iPod compatibility.', flag: '--large-file', allowed_values: [nil], aliases: [] },
|
74
|
+
{ name: :optimize, description: 'Optimize mp4 files for HTTP streaming (\'fast start\')', flag: '--optimize', allowed_values: [nil], aliases: [] },
|
75
|
+
{ name: :ipod_atom, description: 'Mark mp4 files so 5.5G iPods will accept them', flag: '--ipod-atom', allowed_values: [nil], aliases: [] },
|
76
|
+
{ name: :use_open_cl, description: 'Use OpenCL where applicable', flag: '--use-opencl', allowed_values: [nil], aliases: [] },
|
77
|
+
{ name: :use_hwd, description: 'Use DXVA2 hardware decoding', flag: '--use-hwd', allowed_values: [nil], aliases: [] },
|
78
|
+
{ name: :encoder, description: 'Set video library encoder. Options: x264/x265/mpeg4/mpeg2/VP8/theora', flag: '--encoder', allowed_values: ['x264', 'x265', 'mpeg4', 'mpeg2', 'VP8', 'theora', :x264, :x265, :mpeg4, :mpeg2, :VP8, :vp8, :theora], aliases: [] },
|
79
|
+
{ name: :encoder_preset, description: 'Adjust video encoding settings for a particular speed/efficiency tradeoff (encoder-specific)', flag: '--encoder-preset', allowed_values: [Object], aliases: [] },
|
80
|
+
{ name: :encoder_preset_list, description: 'List supported --encoder-preset values for the specified video encoder', flag: '--encoder-preset-list', allowed_values: [nil], aliases: [] },
|
81
|
+
{ name: :encoder_tune, description: 'Adjust video encoding settings for a particular type of souce or situation (encoder-specific)', flag: '--encoder-tune', allowed_values: [Object], aliases: [] },
|
82
|
+
{ name: :encoder_tune_list, description: 'List supported --encoder-tune values for the specified video encoder', flag: '--encoder-tune-list', allowed_values: [nil], aliases: [] },
|
83
|
+
{ name: :encopts, description: 'Specify advanced encoding options in the same style as mencoder (all encoders except theora): option1=value1:option2=value2', flag: '--encopts', allowed_values: [Object], aliases: [] },
|
84
|
+
{ name: :encoder_profile, description: 'Ensures compliance with the requested codec profile (encoder-specific)', flag: '--encoder-profile', allowed_values: [Object], aliases: [] },
|
85
|
+
{ name: :encoder_profile_list, description: 'List supported --encoder-profile values for the specified video encoder', flag: '--encoder-profile-list', allowed_values: [nil], aliases: [] },
|
86
|
+
{ name: :encoder_level, description: 'Ensures compliance with the requested codec level (encoder-specific)', flag: '--encoder-level', allowed_values: [Object], aliases: [] },
|
87
|
+
{ name: :encoder_level_list, description: 'List supported --encoder-level values for the specified video encoder', flag: '--encoder-level-list', allowed_values: [nil], aliases: [] },
|
88
|
+
{ name: :quality, description: 'Set video quality', flag: '--quality', allowed_values: [Integer], aliases: [] },
|
89
|
+
{ name: :video_bitrate, description: 'Set video bitrate', flag: '--vb', allowed_values: [Integer], aliases: [:vb, :bitrate] },
|
90
|
+
{ name: :two_pass, description: 'Use two-pass mode', flag: '--two-pass', allowed_values: [nil], aliases: [] },
|
91
|
+
{ name: :turbo, description: 'When using 2-pass use \'turbo\' options on the 1st pass to improve speed (only works with x264)', flag: '--turbo', allowed_values: [nil], aliases: [] },
|
92
|
+
{ name: :video_framerate, description: 'Set video framerate (5/10/12/15/23.976/24/25/29.97/30/50/59.94/60). Be aware that not specifying a framerate lets HandBrake preserve a source\'s time stamps, potentially creating variable framerate video', flag: '--rate', allowed_values: [Float, Integer], aliases: [:framerate] },
|
93
|
+
{ name: :variable_framerate, description: 'VFR preserves the source timing.', flag: '--vfr', allowed_values: [nil], aliases: [] },
|
94
|
+
{ name: :constant_framerate, description: 'CFR makes the output constant rate at the rate given by the -r flag (or the source\'s average rate if no -r is given)', flag: '--cfr', allowed_values: [nil], aliases: [] },
|
95
|
+
{ name: :peak_limited_framerate, description: 'PFR doesn\'t allow the rate to go over the rate specified with the -r flag but won\'t change the source timing if it\'s below that rate.', flag: '--pfr', allowed_values: [nil], aliases: [] },
|
96
|
+
{ name: :audio_tracks, description: 'Select audio track(s), separated by commas', flag: '--audio', allowed_values: [String], aliases: [] },
|
97
|
+
{ name: :audio_encoder, description: 'Audio encoder(s): av_aac, fdk_aac, fdk_haac, copy:aac, ac3, copy:ac3, copy:dts, copy:dtshd, mp3, copy:mp3, vorbis, flac16, flac24, copy. copy:* will passthrough the corresponding audio unmodified to the muxer if it is a supported passthrough audio type. Separated by commas for more than one audio track.', flag: '--aencoder', allowed_values: ['av_aac', 'fdk_aac', 'fdk_haac', 'copy:aac', 'ac3', 'copy:ac3', 'copy:dts', 'copy:dtshd', 'mp3', 'copy:mp3', 'vorbis', 'flac16', 'flac24', 'copy', :av_aac, :fdk_aac, :fdk_haac, :attr_array_removeraac, :ac3, :copy_ac3, :copy_dts, :copy_dtshd, :mp3, :copy_mp3, :vorbis, :flac16, :flac24, :copy], aliases: [] },
|
98
|
+
{ name: :audio_copy_mask, description: 'Set audio codecs that are permitted when the \'copy\' audio encoder option is specified (aac/ac3/dts/dtshd/mp3, default: all).', flag: '--audio-copy-mast', allowed_values: ['all', 'aac', 'ac3', 'dts', 'dtshd', 'mp3', :all, :aac, :ac3, :drs, :dtshd, :mp3], aliases: [] },
|
99
|
+
{ name: :audio_fallback, description: 'Set audio codec to use when it is not possible to copy an audio track without re-encoding.', flag: '--audio-fallback', allowed_values: ['av_aac', 'fdk_aac', 'fdk_haac', 'copy:aac', 'ac3', 'copy:ac3', 'copy:dts', 'copy:dtshd', 'mp3', 'copy:mp3', 'vorbis', 'flac16', 'flac24', 'copy', :av_aac, :fdk_aac, :fdk_haac, :attr_array_removeraac, :ac3, :attr_array_removerac3, :attr_array_removerdts, :attr_array_removerdtshd, :mp3, :attr_array_removermp3, :vorbis, :flac16, :flac24, :copy], aliases: [] },
|
100
|
+
{ name: :audio_bitrate, description: 'Set audio bitrate(s) (default: depends on the selected codec, mixdown and samplerate). Separated by commas for more than one audio track.', flag: '--ab', allowed_values: [String, Integer], aliases: [:ab] },
|
101
|
+
{ name: :audio_quality, description: 'Set audio quality metric (default: depends on the selected codec). Separated by commas for more than one audio track.', flag: '--aq', allowed_values: [String, Integer], aliases: [] },
|
102
|
+
{ name: :audio_compression, description: 'Set audio compression metric (default: depends on the selected codec). Separated by commas for more than one audio track.', flag: '--ac', allowed_values: [String, Integer], aliases: [] },
|
103
|
+
{ name: :mixdown, description: 'Format(s) for audio downmixing/upmixing:, mono, left_only, right_only, stereo, dpl1, dpl2, 5point1, 6point1, 7point1, 5_2_lfe .Separated by commas for more than one audio track.', flag: '--mixdown', allowed_values: ['mono', 'left_only', 'right_only', 'stereo', 'dp11', 'dp12', '5point1', '6point1', '7point1', '5_2_lfe', String, Symbol], aliases: [] },
|
104
|
+
{ name: :normalize_mix, description: 'Normalize audio mix levels to prevent clipping. Separated by commas for more than one audio track. 0 = Disable Normalization (default) 1 = Enable Normalization', flag: '--normalize-mix', allowed_values: [0, 1], aliases: [] },
|
105
|
+
{ name: :audio_samplerate, description: 'Set audio samplerate(s) (8/11.025/12/16/22.05/24/32/44.1/48 kHz). Separated by commas for more than one audio track.', flag: '--arate', allowed_values: [String, Float], aliases: [] },
|
106
|
+
{ name: :dynamic_range_compression, description: 'Apply extra dynamic range compression to the audio, making soft sounds louder. Range is 1.0 to 4.0 (too loud), with 1.5 - 2.5 being a useful range. Separated by commas for more than one audio track.', flag: '--drc', allowed_values: [Float, Integer, String], aliases: [] },
|
107
|
+
{ name: :gain, description: 'Amplify or attenuate audio before encoding. Does NOT work with audio passthru (copy). Values are in dB. Negative values attenuate, positive values amplify. A 1 dB difference is barely audible.', flag: '--gain', allowed_values: [Float, Integer, String], aliases: [] },
|
108
|
+
{ name: :audio_dither, description: 'Apply dithering to the audio before encoding. Separated by commas for more than one audio track. Only supported by some encoders (fdk_aac/fdk_haac/flac16). Options: auto (default), none, rectangular, triangular, triangular_hp, triangular_ns', flag: '--adither', allowed_values: ['auto', 'none', 'rectangular', 'triangular', 'triangular_hp', 'triangular_ns', String, Symbol], aliases: [] },
|
109
|
+
{ name: :audio_track_name, description: 'Audio track name(s). Separated by commas for more than one audio track.', flag: '--aname', allowed_values: [String], aliases: [] },
|
110
|
+
{ name: :width, description: 'Set picture width', flag: '--width', allowed_values: [Integer], aliases: [:w] },
|
111
|
+
{ name: :height, description: 'Set picture height', flag: '--height', allowed_values: [Integer], aliases: [:h] },
|
112
|
+
{ name: :crop, description: 'Set cropping values (default: autocrop)', flag: '--crop', allowed_values: [String, Symbol], aliases: [] },
|
113
|
+
{ name: :loose_crop, description: 'Always crop to a multiple of the modulus. Specifies the maximum number of extra pixels which may be cropped (default: 15)', flag: '--loose-crop', allowed_values: [String], aliases: [] },
|
114
|
+
{ name: :max_height, description: 'Set maximum height', flag: '--maxHeight', allowed_values: [Integer], aliases: [] },
|
115
|
+
{ name: :max_width, description: 'Set maximum width', flag: '--maxWidth', allowed_values: [Integer], aliases: [] },
|
116
|
+
{ name: :strict_anamorphic, description: 'Store pixel aspect ratio in video stream', flag: '--strict-anamorphic', allowed_values: [nil], aliases: [] },
|
117
|
+
{ name: :loose_anamorphic, description: 'Store pixel aspect ratio with specified width', flag: '--loose-anamorphic', allowed_values: [nil], aliases: [] },
|
118
|
+
{ name: :custom_anamorphic, description: 'Store pixel aspect ratio in video stream and directly control all parameters.', flag: '--custom-anamorphic', allowed_values: [nil], aliases: [] },
|
119
|
+
{ name: :display_width, description: 'Set the width to scale the actual pixels to at playback, for custom anamorphic.', flag: '--display-width', allowed_values: [Integer], aliases: [] },
|
120
|
+
{ name: :keep_display_aspect, description: 'Preserve the source\'s display aspect ratio when using custom anamorphic', flag: '--keep-display-aspect', allowed_values: [nil], aliases: [] },
|
121
|
+
{ name: :pixel_aspect, description: 'Set a custom pixel aspect for custom anamorphic (--display-width and --pixel-aspect are mutually exclusive and the former will override the latter)', flag: '--pixel-aspect', allowed_values: [String], aliases: [] },
|
122
|
+
{ name: :itu_par, description: 'Use wider, ITU pixel aspect values for loose and custom anamorphic, useful with underscanned sources', flag: '--itu-par', allowed_values: [nil], aliases: [] },
|
123
|
+
{ name: :modulus, description: 'Set the number you want the scaled pixel dimensions to divide cleanly by. Does not affect strict anamorphic mode, which is always mod 2 (default: 16)', flag: '--modulus', allowed_values: [Integer], aliases: [] },
|
124
|
+
{ name: :color_matrix, description: 'Set the color space signaled by the output. Values: 709, pal, ntsc, 601 (same as ntsc) (default: detected from source)', flag: '--color-matrix', allowed_values: [709, 'pal', 'ntsc', 601, :pal, :ntsc], aliases: [] },
|
125
|
+
{ name: :deinterlace, description: 'Unconditionally deinterlaces all frames <fast/slow/slower/bob> or omitted (default settings) or <YM:FD> (default 0:-1)', flag: '--deinterlace', allowed_values: ['omitted', 'fast', 'slow', 'slower', 'bob', :omitted, :fast, :slow, :slower, :bob], aliases: [] },
|
126
|
+
{ name: :decomb, description: 'Selectively deinterlaces when it detects combing <fast/bob> or omitted (default settings) or <MO:ME:MT:ST:BT:BX:BY:MG:VA:LA:DI:ER:NO:MD:PP:FD> (default: 7:2:6:9:80:16:16:10:20:20:4:2:50:24:1:-1)', flag: '--decomb', allowed_values: [String], aliases: [] },
|
127
|
+
{ name: :detelecine, description: 'Detelecine (ivtc) video with pullup filter. Note: this filter drops duplicate frames to restore the pre-telecine framerate, unless you specify a constant framerate (--rate 29.97) <L:R:T:B:SB:MP:FD> (default 1:1:4:4:0:0:-1)', flag: '--detelecine', allowed_values: [String], aliases: [] },
|
128
|
+
{ name: :denoise, description: 'Denoise video with hqdn3d filter <ultralight/light/medium/strong> or omitted (default settings) or <SL:SCb:SCr:TL:TCb:TCr> (default: 4:3:3:6:4.5:4.5)', flag: '--denoise', allowed_values: [String], aliases: [] },
|
129
|
+
{ name: :nlmeans, description: 'Denoise video with nlmeans filter <ultralight/light/medium/strong> or omitted or <SY:OTY:PSY:RY:FY:PY:Sb:OTb:PSb:Rb:Fb:Pb:Sr:OTr:PSr:Rr:Fr:Pr> (default 8:1:7:3:2:0)', flag: '--nlmeans', allowed_values: [String], aliases: [] },
|
130
|
+
{ name: :nimeans_tune, description: 'Tune nlmeans filter to content type. Note: only works in conjunction with presets ultralight/light/medium/strong. <none/film/grain/highmotion/animation> or omitted (default none)', flag: '--nlmeans-tune', allowed_values: ['none', 'film', 'grain', 'highmotion', 'animation', 'omitted', :none, :film, :grain, :highmotion, :animation, :omitted], aliases: [] },
|
131
|
+
{ name: :deblock, description: 'Deblock video with pp7 filter (default 5:2)', flag: '--deblock', allowed_values: [String], aliases: [] },
|
132
|
+
{ name: :rotate, description: 'Rotate image or flip its axes. Modes: (can be combined) 1 vertical flip, 2 horizontal flip, 4 rotate clockwise 90 degrees, Default: 3 (vertical and horizontal flip)', flag: '--rotate', allowed_values: [1, 2, 3, 4], aliases: [] },
|
133
|
+
{ name: :grayscale, description: 'Grayscale encoding', flag: '--grayscale', allowed_values: [nil], aliases: [] },
|
134
|
+
{ name: :subtitle_track, description: 'Select subtitle track(s), separated by commas. More than one output track can be used for one input. Example: \'1,2,3\' for multiple tracks. A special track name \'scan\' adds an extra 1st pass. This extra pass scans subtitles matching the language of the first audio or the language selected by --native-language. The one that\'s only used 10 percent of the time or less is selected. This should locate subtitles for short foreign language segments. Best used in conjunction with --subtitle-forced.', flag: '--subtitle', allowed_values: [String, Integer], aliases: [] },
|
135
|
+
{ name: :subtitle_forced, description: 'Only display subtitles from the selected stream if the subtitle has the forced flag set. The values in \'string\' are indexes into the subtitle list specified with \'--subtitle\'. Separated by commas for more than one subtitle track. Example: \'1,2,3\' for multiple tracks. If \'string\' is omitted, the first track is forced.', flag: '--subtitle-forced', allowed_values: [String, Integer], aliases: [] },
|
136
|
+
{ name: :subtitle_burned, description: 'Burn\' the selected subtitle into the video track. If \'number\' is omitted, the first track is burned. \'number\' is an index into the subtitle list specified with \'--subtitle\'.', flag: '--subtitle-burned', allowed_values: [String, Integer], aliases: [] },
|
137
|
+
{ name: :subtitle_default, description: 'Flag the selected subtitle as the default subtitle to be displayed upon playback. Setting no default means no subtitle will be automatically displayed. If \'number\' is omitted, the first track is default. \'number\' is an index into the subtitle list specified with \'--subtitle\'.', flag: '--subtitle-default', allowed_values: [String, Integer], aliases: [] },
|
138
|
+
{ name: :native_language, description: 'Specifiy your language preference. When the first audio track does not match your native language then select the first subtitle that does. When used in conjunction with --native-dub the audio track is changed in preference to subtitles. Provide the language\'s iso639-2 code (fre, eng, spa, dut, et cetera)', flag: '--native-language', allowed_values: [String], aliases: [] },
|
139
|
+
{ name: :native_dub, description: 'Used in conjunction with --native-language requests that if no audio tracks are selected the default selected audio track will be the first one that matches the --native-language. If there are no matching audio tracks then the first matching subtitle track is used instead.', flag: '--native-dub', allowed_values: [String], aliases: [] },
|
140
|
+
{ name: :srt_file, description: 'SubRip SRT filename(s), separated by commas.', flag: '--srt-file', allowed_values: [String], aliases: [] },
|
141
|
+
{ name: :srt_codeset, description: 'Character codeset(s) that the SRT file(s) are encoded in, separated by commas. Use \'iconv -l\' for a list of valid codesets. If not specified, \'latin1\' is assumed', flag: '--srt-codeset', allowed_values: [String], aliases: [] },
|
142
|
+
{ name: :srt_offset, description: 'Offset (in milliseconds) to apply to the SRT file(s), separated by commas. If not specified, zero is assumed. Offsets may be negative.', flag: '--srt-offset', allowed_values: [String], aliases: [] },
|
143
|
+
{ name: :srt_lang, description: 'Language as an iso639-2 code fra, eng, spa et cetera) for the SRT file(s), separated by commas. If not specified, then \'und\' is used.', flag: '--srt-lang', allowed_values: [String], aliases: [] },
|
144
|
+
{ name: :srt_default, description: 'Flag the selected srt as the default subtitle to be displayed upon playback. Setting no default means no subtitle will be automatically displayed. If \'number\' is omitted, the first srt is default. \'number\' is an 1 based index into the srt-file list', flag: '--srt-default', allowed_values: [String], aliases: [] },
|
145
|
+
{ name: :srt_burn, description: 'Burn\' the selected srt subtitle into the video track. If \'number\' is omitted, the first srt is burned. \'number\' is an 1 based index into the srt-file list', flag: '--srt-burn', allowed_values: [String], aliases: [] },
|
146
|
+
{ name: :version, description: 'Display the version number.', flag: '--version', allowed_values: [nil], aliases: [:v] }
|
147
|
+
)
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'cli_chef' unless defined?(CLIChef::VERSION)
|
2
|
+
|
3
|
+
class MediaInfo < CLIChef::Cookbook
|
4
|
+
self.description = 'MediaInfo is a convenient unified display of the most relevant technical and tag data for video and audio files.'
|
5
|
+
|
6
|
+
add_exit_codes(
|
7
|
+
{ code: 0, description: 'No error' },
|
8
|
+
{ code: 1, description: 'Failure' }
|
9
|
+
)
|
10
|
+
|
11
|
+
add_default_locations(
|
12
|
+
'C:/Program Files/MediaInfo/MediaInfo.exe',
|
13
|
+
'C:/Program Files(x86)/MediaInfo/MediaInfo.exe'
|
14
|
+
)
|
15
|
+
|
16
|
+
add_ingredients(
|
17
|
+
{ name: :help, description: 'Display the CLI help.', flag: '--help', allowed_values: [nil], aliases: [:h], boolean_argument: true },
|
18
|
+
{ name: :version, description: 'Display MediaInfo version and exit', flag: '--Version', allowed_values: [nil], aliases: [:v], boolean_argument: true },
|
19
|
+
{ name: :full, description: 'Full information Display (all internal tags)', flag: '-f', allowed_values: [nil], aliases: [:verbose], boolean_argument: true },
|
20
|
+
{ name: :output_html, description: 'Full information Display with HTML tags', flag: '--Output=HTML', allowed_values: [nil], aliases: [:html], boolean_argument: true },
|
21
|
+
{ name: :output_xml, description: 'Full information Display with XML tags', flag: '--Output=XML', allowed_values: [nil], aliases: [:xml], boolean_argument: true },
|
22
|
+
{ name: :file, description: 'The file to get tags out of', flag: '', allowed_values: [String], aliases: [:input] }
|
23
|
+
)
|
24
|
+
|
25
|
+
def help
|
26
|
+
run!(help: true).body
|
27
|
+
end
|
28
|
+
|
29
|
+
def version
|
30
|
+
run!(version: true).body.scan(/(?<= v)\d+\.\d+.*/).first
|
31
|
+
end
|
32
|
+
|
33
|
+
def info(file, full = false)
|
34
|
+
run!(file: file, full: full).body.split("\n\n").hmap do |category|
|
35
|
+
lines = category.split("\n")
|
36
|
+
next if lines.empty?
|
37
|
+
[
|
38
|
+
lines.shift.strip.downcase.method_case,
|
39
|
+
lines.hmap do |line|
|
40
|
+
key, value = line.split(':', 2)
|
41
|
+
key = key.downcase.method_case.to_sym
|
42
|
+
[
|
43
|
+
key,
|
44
|
+
convert_value(key, value.strip)
|
45
|
+
]
|
46
|
+
end
|
47
|
+
]
|
48
|
+
end.keys_to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def convert_value(key, value)
|
54
|
+
case key
|
55
|
+
when :file_size
|
56
|
+
value.parse_file_size
|
57
|
+
when :duration
|
58
|
+
value.parse_duration
|
59
|
+
when :width, :height
|
60
|
+
value.to_i
|
61
|
+
else
|
62
|
+
value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'cli_chef' unless defined?(CLIChef::VERSION)
|
2
|
+
require_relative 'sevenzip/archive'
|
3
|
+
require_relative 'sevenzip/util'
|
4
|
+
|
5
|
+
class SevenZip < CLIChef::Cookbook
|
6
|
+
|
7
|
+
SUPPORTED_ARCHIVES = [
|
8
|
+
'001', '7z', 'a', 'apm', 'ar', 'arj', 'bz2', 'bzip2', 'cab', 'chi', 'chm',
|
9
|
+
'chq', 'chw', 'cpio', 'cramfs', 'deb', 'dmg', 'doc', 'docx', 'epub', 'esd',
|
10
|
+
'ext', 'ext2', 'ext3', 'ext4', 'fat', 'gz', 'gzip', 'hfs', 'hfsx', 'hxi',
|
11
|
+
'hxq', 'hxr', 'hxs', 'hxw', 'ihex', 'img', 'iso', 'jar', 'lha', 'lib',
|
12
|
+
'lit', 'lzh', 'lzma', 'mbr', 'msi', 'mslz', 'msp', 'mub', 'nsis', 'ntfs',
|
13
|
+
'ods', 'odt', 'pkg', 'ppmd', 'ppt', 'qcow', 'qcow2', 'qcow2c', 'r00', 'rar',
|
14
|
+
'rpm', 'scap', 'squashfs', 'swm', 'tar', 'taz', 'tbz', 'tbz2', 'tgz', 'txz',
|
15
|
+
'udf', 'uefif', 'vdi', 'vhd', 'vmdk', 'wim', 'xar', 'xls', 'xlsx', 'xpi',
|
16
|
+
'xz', 'z', 'zip', 'zipx'
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
self.description = '7-Zip is a file archiver with a high compression ratio.'
|
20
|
+
|
21
|
+
add_exit_codes(
|
22
|
+
{ code: 0, description: 'No error' },
|
23
|
+
{ code: 1, description: 'Warning (Non fatal error(s)). For example, one or more files were locked by some other application, so they were not compressed.' },
|
24
|
+
{ code: 2, description: 'Fatal error', error: true },
|
25
|
+
{ code: 7, description: 'Command line error', error: true },
|
26
|
+
{ code: 8, description: 'Not enough memory for operation', error: true },
|
27
|
+
{ code: 255, description: 'User stopped the process', error: true }
|
28
|
+
)
|
29
|
+
|
30
|
+
add_default_locations(
|
31
|
+
'C:/Program Files/7-Zip/7z.exe',
|
32
|
+
'C:/Program Files(x86)/7-Zip/7z.exe',
|
33
|
+
'C:/7-Zip/7z.exe',
|
34
|
+
'7za',
|
35
|
+
'7z'
|
36
|
+
)
|
37
|
+
|
38
|
+
add_ingredients(
|
39
|
+
{ name: :add, description: 'Adds files to archive.', flag: 'a', allowed_values: [nil], aliases: [:a], boolean_argument: true, flag_delimiter: '' },
|
40
|
+
{ name: :extract, description: 'Extracts files from an archive to the current directory or to the output directory.', flag: 'e', allowed_values: [nil], aliases: [:e], boolean_argument: true, flag_delimiter: '' },
|
41
|
+
{ name: :extract_full_paths, description: 'Extracts files from an archive with their full paths in the current directory, or in an output directory if specified.', flag: 'x', allowed_values: [nil], aliases: [:x], boolean_argument: true, flag_delimiter: '' },
|
42
|
+
{ name: :benchmark, description: 'Measures speed of the CPU and checks RAM for errors.', flag: 'b', allowed_values: [nil], aliases: [:b], boolean_argument: true, flag_delimiter: '' },
|
43
|
+
{ name: :delete, description: 'Deletes files from archive.', flag: 'd', allowed_values: [nil], aliases: [:d], boolean_argument: true, flag_delimiter: '' },
|
44
|
+
{ name: :list, description: 'Lists contents of archive.', flag: 'l', allowed_values: [nil], aliases: [:l], boolean_argument: true, flag_delimiter: '' },
|
45
|
+
{ name: :test, description: 'Tests archive files.', flag: 't', allowed_values: [nil], aliases: [:t], boolean_argument: true, flag_delimiter: '' },
|
46
|
+
{ name: :update, description: 'Update older files in the archive and add files that are not already in the archive.', flag: 'u', allowed_values: [nil], aliases: [:u], boolean_argument: true, flag_delimiter: '' },
|
47
|
+
{ name: :archive, description: 'Specifies the name of the archive', flag: nil, allowed_values: [String, Array], aliases: [:file], flag_delimiter: '' },
|
48
|
+
{ name: :include, description: 'Specifies additional include filenames and wildcards.', flag: '-i', allowed_values: [String], aliases: [], flag_delimiter: '' },
|
49
|
+
{ name: :method, description: 'Specifies the compression method.', flag: '-m', allowed_values: [String], aliases: [], flag_delimiter: '' },
|
50
|
+
{ name: :password, description: 'Specifies password.', flag: '-p', allowed_values: [String], aliases: [], flag_delimiter: '' },
|
51
|
+
{ name: :recurse, description: 'Specifies the method of treating wildcards and filenames on the command line. -r Enable recurse subdirectories. -r- Disable recurse subdirectories. This option is default for all commands. -r0 Enable recurse subdirectories only for wildcard names.', flag: '-r', allowed_values: [nil, '-', '0', 0], aliases: [], flag_delimiter: '' },
|
52
|
+
{ name: :create_sfx, description: 'Creates self extracting archive.', flag: '-sfx', allowed_values: [nil, '7z.sfx', 'tzCon.sfx', '7zS.sfx', '7zSD.sfx'], aliases: [], flag_delimiter: '' },
|
53
|
+
{ name: :stdin, description: 'Causes 7-Zip to read data from stdin (standard input) instead of from disc files.', flag: '-si', allowed_values: [nil, String], aliases: [], flag_delimiter: '' },
|
54
|
+
{ name: :stdout, description: 'Causes 7-Zip to write output data to stdout (standard output stream).', flag: '-so', allowed_values: [nil, String], aliases: [], flag_delimiter: '' },
|
55
|
+
{ name: :compress_shared_files, description: 'Compresses files open for writing by another applications.', flag: '-ssw', allowed_values: [nil], aliases: [], flag_delimiter: '' },
|
56
|
+
{ name: :type, description: 'Specifies the type of archive.', flag: '-t', allowed_values: ['*', '7z', 'xz', 'split', 'zip', 'gzip', 'bzip2', 'tar', 'mbr', 'vhd', 'udf'], aliases: [], flag_delimiter: '' },
|
57
|
+
{ name: :update_switch, description: 'Specifies how to update files in an archive and (or) how to create new archives.', flag: '-u', allowed_values: [], aliases: [], flag_delimiter: '' },
|
58
|
+
{ name: :volumes, description: 'Specifies volume sizes.', flag: '-v', allowed_values: [/\d+[bkmg]/i], aliases: [], flag_delimiter: '' },
|
59
|
+
{ name: :working_dir, description: 'Sets the working directory for the temporary base archive.', flag: '-w', allowed_values: [String], aliases: [], flag_delimiter: '' },
|
60
|
+
{ name: :exclude, description: 'Specifies which filenames or wildcarded names must be excluded from the operation.', flag: '-x', allowed_values: [String], aliases: [], flag_delimiter: '' },
|
61
|
+
{ name: :include_archives, description: 'Specifies additional include archive filenames and wildcards.', flag: '-ai', allowed_values: [String], aliases: [], flag_delimiter: '' },
|
62
|
+
{ name: :disable_parsing, description: 'Disables parsing of the archive_name field on the command line.', flag: '-an', allowed_values: [nil], aliases: [], flag_delimiter: '' },
|
63
|
+
{ name: :overwrite, description: 'Specifies the overwrite mode during extraction, to overwrite files already present on disk.', flag: '-ao', allowed_values: %w(s a u t), aliases: [:overwrite_mode], flag_delimiter: '' },
|
64
|
+
{ name: :exclude_archives, description: 'Specifies archives to be excluded from the operation.', flag: '-ax', allowed_values: [String], aliases: [], flag_delimiter: '' },
|
65
|
+
{ name: :output_dir, description: 'Specifies a destination directory where files are to be extracted.', flag: '-o', allowed_values: [String], aliases: [:output_directory, :output], flag_delimiter: '' },
|
66
|
+
{ name: :assume_yes, description: 'Disables most of the normal user queries during 7-Zip execution.', flag: '-y', allowed_values: [nil], aliases: [:yes, :assume, :answer_yes], boolean_argument: true, flag_delimiter: '' },
|
67
|
+
{ name: :show_technical_information, description: 'Sets technical mode for l (List) command.', flag: '-slt', allowed_values: [nil], aliases: [:slt, :technical, :show_technical], boolean_argument: true, flag_delimiter: '' },
|
68
|
+
{ name: :help, description: 'Display the CLI help.', flag: '-h', allowed_values: [nil], aliases: [:h], boolean_argument: true, flag_delimiter: '' },
|
69
|
+
{ name: :show_progress, description: 'Print progress to stdout.', flag: '-bsp1', allowed_values: [nil], aliases: [], boolean_argument: true, flag_delimiter: '' }
|
70
|
+
)
|
71
|
+
|
72
|
+
def help
|
73
|
+
run!(help: true).body
|
74
|
+
end
|
75
|
+
|
76
|
+
def version
|
77
|
+
help.scan(/(?<=7-zip )\d+\.\d+\s?\w*/i).first
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.archive(path)
|
81
|
+
SevenZip::Archive.new(path: path)
|
82
|
+
end
|
83
|
+
|
84
|
+
bridge_method :archive
|
85
|
+
|
86
|
+
def list(archive, **opts)
|
87
|
+
args = { list: true, archive: archive, show_technical: true }.merge(opts.except(:list, :archive, :show_technical))
|
88
|
+
run!(args).body.split('----------', 2).last.split("\n\n").map do |details|
|
89
|
+
hash = details.split("\n").hmap do |attribute|
|
90
|
+
next if attribute.empty?
|
91
|
+
key, value = attribute.split(' = ', 2)
|
92
|
+
[key.downcase.gsub(/\s+/, '_').to_sym, value]
|
93
|
+
end
|
94
|
+
Archive::Item.new(hash)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def list_files(archive, **opts)
|
99
|
+
list(archive, **opts).select { |i| i.is_a?(SevenZip::Archive::File) }
|
100
|
+
end
|
101
|
+
|
102
|
+
def list_dirs(archive, **opts)
|
103
|
+
list(archive, **opts).select { |i| i.is_a?(SevenZip::Archive::Dir) }
|
104
|
+
end
|
105
|
+
|
106
|
+
def extract(archive, **opts)
|
107
|
+
type = opts[:full_path] == false ? :extract : :extract_full_paths
|
108
|
+
args = { type => true, file: archive, yes: true, show_progress: true }.merge(opts.except(type, :file, :yes))
|
109
|
+
run(**args) do |line, stream, job|
|
110
|
+
job.percent = line.extract_numbers.first if line =~ /\d+\%/
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def extract!(archive, **opts)
|
115
|
+
extract(archive, opts.merge(synchronous: true))
|
116
|
+
end
|
117
|
+
|
118
|
+
[:add, :update, :delete].each do |type|
|
119
|
+
define_method(type) do |archive, file, **opts|
|
120
|
+
args = { type => true, archive: [archive, file], yes: true }.merge(opts.except(type, :archive, :yes))
|
121
|
+
run(**args)
|
122
|
+
end
|
123
|
+
|
124
|
+
define_method("#{type}!") do |archive, file, **opts|
|
125
|
+
send(type, archive, file, opts.merge(synchronous: true))
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# TODO Have test return something better
|
130
|
+
def test(archive, **opts)
|
131
|
+
args = { test: true, file: archive, yes: nil }.merge(opts.except(:test, :file, :yes))
|
132
|
+
run(**args)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test!(archive, **opts)
|
136
|
+
test(archive, opts.merge(synchronous: true))
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'item'
|
2
|
+
require_relative 'file'
|
3
|
+
require_relative 'dir'
|
4
|
+
|
5
|
+
class SevenZip < CLIChef::Cookbook
|
6
|
+
class Archive
|
7
|
+
include BBLib::Effortless
|
8
|
+
|
9
|
+
attr_file :path, required: true
|
10
|
+
attr_ary_of File, :files
|
11
|
+
attr_ary_of Dir, :dirs
|
12
|
+
|
13
|
+
after :path=, :load_archive
|
14
|
+
|
15
|
+
def size
|
16
|
+
::File.size(path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def extract(**opts)
|
20
|
+
SevenZip.extract(path, **opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
def add(file, **opts)
|
24
|
+
SevenZip.add(path, file, **opts)
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete(file, **opts)
|
28
|
+
SevenZip.delete(path, file, **opts)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def load_archive
|
34
|
+
self.files.clear
|
35
|
+
items = SevenZip.list(self.path)
|
36
|
+
items.map { |i| i.archive = self }
|
37
|
+
self.dirs = items.find_all { |i| i.is_a?(Dir) }
|
38
|
+
self.files = items.find_all { |i| !i.is_a?(Dir) }
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class SevenZip < CLIChef::Cookbook
|
2
|
+
class Archive
|
3
|
+
class Item
|
4
|
+
include BBLib::Effortless
|
5
|
+
|
6
|
+
attr_str :path, required: true
|
7
|
+
attr_of Archive, :archive, serialize: false
|
8
|
+
attr_int :size, :packed_size, :volume_index, :offset
|
9
|
+
attr_time :modified, :created, :accessed
|
10
|
+
attr_str :comment, :crc, :archive_method, :characteristics
|
11
|
+
attr_str :host_os, :version
|
12
|
+
attr_bool :encrypted, pre_proc: proc { |x| x == '-' }
|
13
|
+
|
14
|
+
init_type :loose
|
15
|
+
|
16
|
+
def self.folder
|
17
|
+
''
|
18
|
+
end
|
19
|
+
|
20
|
+
setup_init_foundation(:folder) do |a, b|
|
21
|
+
a.to_s[0] == b.to_s[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def extract(**opts)
|
25
|
+
raise RunTimeError, "No archive has been set for this #{self.class} so it cannot be extracted." unless archive
|
26
|
+
SevenZip.extract([archive.path, self.path], **opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(**opts)
|
30
|
+
raise RunTimeError, "No archive has been set for this #{self.class} so it cannot be deleted." unless archive
|
31
|
+
archive.delete(self.path)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module BBLib
|
2
|
+
def self.scan_files_and_archives(path, *filters, recursive: false, archive_types: SevenZip::SUPPORTED_ARCHIVES, &block)
|
3
|
+
matches = []
|
4
|
+
filters = filters.map { |filter| filter.is_a?(Regexp) ? filter : /^#{Regexp.quote(filter).gsub('\\*', '.*')}$/ }
|
5
|
+
archive_filters = archive_types.map { |type| /\.#{Regexp.quote(type)}$/i }
|
6
|
+
|
7
|
+
scan_files(path, *(filters + archive_filters), recursive: recursive) do |file|
|
8
|
+
if archive_filters.any? { |filter| filter =~ file } && !filters.any? { |filter| filter =~ file }
|
9
|
+
match = false
|
10
|
+
begin
|
11
|
+
SevenZip.list_files(file).select do |archive|
|
12
|
+
match = true if filters.any? { |filter| filter =~ archive.path }
|
13
|
+
end
|
14
|
+
rescue => _e
|
15
|
+
# Nothing, archive check failed
|
16
|
+
end
|
17
|
+
if match
|
18
|
+
matches << file
|
19
|
+
yield file if block_given?
|
20
|
+
end
|
21
|
+
else
|
22
|
+
matches << file
|
23
|
+
yield file if block_given?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
matches
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module CLIChef
|
2
|
+
class Cookbook
|
3
|
+
include BBLib::Effortless
|
4
|
+
|
5
|
+
attr_ary_of String, :default_locations, singleton: true, add_rem: true
|
6
|
+
attr_ary_of ExitCode, :exit_codes, singleton: true, add_rem: true
|
7
|
+
attr_ary_of Ingredient, :ingredients, singleton: true, add_rem: true
|
8
|
+
attr_str :description, singleton: true
|
9
|
+
attr_of Class, :default_job_class, default: CLIChef::Job, singleton: true
|
10
|
+
|
11
|
+
attr_str :path, allow_nil: true, default_proc: proc { |x| x.class.path }
|
12
|
+
attr_of Result, :result, default: nil, allow_nil: true, serialize: false
|
13
|
+
|
14
|
+
before :path, :check_default_locations
|
15
|
+
|
16
|
+
bridge_method :default_job_class, :default_locations, :exit_codes, :ingredients, :description, :ingredient
|
17
|
+
|
18
|
+
# Returns true if the path is either set to a valid file or can be found in the
|
19
|
+
# environment
|
20
|
+
def ready?
|
21
|
+
path && (File.exist?(path) || BBLib::OS.which(path))
|
22
|
+
end
|
23
|
+
|
24
|
+
# Executes a string as a command to this CLI wrapper in a job (threaded)
|
25
|
+
def execute(string, opts = {}, &block)
|
26
|
+
raise RuntimeError, "A valid path is currently not set for #{self.class}. Please set a valid path to the executable first." unless path
|
27
|
+
return execute!(string, opts.except(:synchronous), &block) if opts[:synchronous]
|
28
|
+
string = "#{clean_path} #{string}"
|
29
|
+
BBLib.logger.debug("About to run cmd: #{string}")
|
30
|
+
(opts.delete(:job_class) || default_job_class).new(opts.merge(command: string, parent: self)).tap do |job|
|
31
|
+
job.run(&block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Synchonous version of execute
|
36
|
+
def execute!(string, opts = {}, &block)
|
37
|
+
while (job ||= execute(string, opts, &block)).running?
|
38
|
+
# Nothing
|
39
|
+
end
|
40
|
+
job.result
|
41
|
+
end
|
42
|
+
|
43
|
+
# Runs a command within a Job (seperate thread)
|
44
|
+
# For when a command should be run asynchronously
|
45
|
+
def run(**args, &block)
|
46
|
+
return run!(args.except(:synchronous), &block) if args[:synchronous]
|
47
|
+
execute(prepare_args(args), &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Blocking version of run that is not executed within a thread.
|
51
|
+
# For when a command should be run synchronously
|
52
|
+
def run!(**args, &block)
|
53
|
+
execute!(prepare_args(args), &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the full command line that would be run based on the given arguments
|
57
|
+
def prepare(**args)
|
58
|
+
"#{clean_path} #{prepare_args(args)}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def prepare_args(**args)
|
62
|
+
args.map do |name, arg|
|
63
|
+
ingredient = self.ingredient(name)
|
64
|
+
raise ArgumentError, "Unknown parameter #{name} for #{self.class}." unless ingredient
|
65
|
+
ingredient.to_s(arg)
|
66
|
+
end.join(' ')
|
67
|
+
end
|
68
|
+
|
69
|
+
# Produces a dynamic help menu for this wrapper. Useful mostly for console or
|
70
|
+
# command line based interactions.
|
71
|
+
def menu
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.prototype
|
76
|
+
@prototype ||= self.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.method_missing(method, *args, &block)
|
80
|
+
prototype.respond_to?(method) ? prototype.send(method, *args, &block) : super
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.respond_to_missing?(method, include_private = false)
|
84
|
+
prototype.respond_to?(method) || super
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.ingredient(name)
|
88
|
+
ingredients.find { |i| i.match?(name) }
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def check_default_locations
|
94
|
+
return if @path
|
95
|
+
return unless found = default_locations.find { |path| File.exist?(path) || BBLib::OS.which(path) }
|
96
|
+
self.path = found
|
97
|
+
end
|
98
|
+
|
99
|
+
def clean_path
|
100
|
+
path.to_s.match?(/\s/) ? "\"#{path}\"" : path
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CLIChef
|
2
|
+
class ExitCode
|
3
|
+
include BBLib::Effortless
|
4
|
+
|
5
|
+
attr_int :code, required: true, arg_at: 0
|
6
|
+
attr_str :description, default_proc: proc { |x| x.code == 0 ? 'Success' : 'Undefined Exit Code' }, arg_at: 1
|
7
|
+
attr_bool :error, default: false, arg_at: 2
|
8
|
+
|
9
|
+
def describe
|
10
|
+
"#{error? ? 'ERROR: ' : nil}#{description} (#{code})"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ExitError < StandardError
|
15
|
+
def initialize(msg = 'The application returned an exit code that indicates an error')
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CLIChef
|
2
|
+
class Ingredient
|
3
|
+
include BBLib::Effortless
|
4
|
+
attr_sym :name
|
5
|
+
attr_ary_of Symbol, :aliases, pre_proc: proc { |x| [x].flatten.map { |i| i.to_s.to_sym } }
|
6
|
+
attr_str :flag, default: nil, allow_nil: true
|
7
|
+
attr_of Object, :argument, serialize: false
|
8
|
+
attr_str :delimiter, :flag_delimiter, default: ' '
|
9
|
+
attr_str :description
|
10
|
+
attr_bool :boolean_argument, default: false
|
11
|
+
attr_ary :allowed_values, add_rem: true
|
12
|
+
|
13
|
+
before :argument=, :allowed!, send_arg: true
|
14
|
+
|
15
|
+
def to_s(value = nil)
|
16
|
+
return '' if boolean_argument? && value == false
|
17
|
+
cleaned_arg = cleaned_argument(value)
|
18
|
+
argument == false ? '' : "#{flag}#{flag && !cleaned_arg.empty? ? flag_delimiter : nil}#{cleaned_arg}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def cleaned_argument(value = nil)
|
22
|
+
allowed!(value)
|
23
|
+
return '' if boolean_argument?
|
24
|
+
[value].flatten(1).map(&:to_s).map do |arg|
|
25
|
+
arg.match?(/\s/) && !arg.encap_by?('"') ? "\"#{arg.gsub('"','\\"')}\"" : arg
|
26
|
+
end.join(delimiter)
|
27
|
+
end
|
28
|
+
|
29
|
+
def match?(name)
|
30
|
+
self.name == name || aliases.include?(name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def allowed?(value)
|
34
|
+
return true if allowed_values.empty?
|
35
|
+
allowed_values.any? do |av|
|
36
|
+
av === value || av.nil? && (value == true || value == false)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def allowed!(value)
|
43
|
+
raise ArgumentError, "#{name} does not accept the value passed to it: #{value} (#{value.class})" unless allowed?(value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module CLIChef
|
2
|
+
class Job
|
3
|
+
include BBLib::Effortless
|
4
|
+
|
5
|
+
attr_str :command
|
6
|
+
attr_of Thread, :thread, protected: true
|
7
|
+
attr_of Result, :result, default: nil, allow_nil: true
|
8
|
+
attr_float :percent, default: 0
|
9
|
+
attr_float :eta, default: nil, allow_nil: true
|
10
|
+
attr_of BBLib::TaskTimer, :timer, default: BBLib::TaskTimer.new, serialize: false
|
11
|
+
attr_of Object, :parent, default: nil, allow_nil: true, serialize: false
|
12
|
+
attr_hash :arguments, default: {}
|
13
|
+
|
14
|
+
setup_init_foundation(:type)
|
15
|
+
|
16
|
+
def self.type
|
17
|
+
self.class.to_s.split('::').last.method_case.to_sym
|
18
|
+
end
|
19
|
+
|
20
|
+
serialize_method :type
|
21
|
+
bridge_method :type
|
22
|
+
|
23
|
+
def run(&block)
|
24
|
+
timer.start
|
25
|
+
self.percent = 0.0
|
26
|
+
self.thread = Thread.new do
|
27
|
+
self.result = Result.new(body: '')
|
28
|
+
# TODO Have command killed when parent process dies
|
29
|
+
Open3.popen3(command) do |sin, out, err, pr|
|
30
|
+
self.result.pid = pr.pid
|
31
|
+
{ stdout: out, stderr: err }.each do |name, stream|
|
32
|
+
stream.each do |line|
|
33
|
+
block ? yield(line, name, self) : process_line(line, name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
self.result.exit_code = code_for(pr.value.exitstatus)
|
37
|
+
end
|
38
|
+
self.percent = 100.0
|
39
|
+
self.timer.stop
|
40
|
+
self.result
|
41
|
+
end
|
42
|
+
running?
|
43
|
+
end
|
44
|
+
|
45
|
+
def code_for(code)
|
46
|
+
exit_codes.find do |ec|
|
47
|
+
ec.code == code
|
48
|
+
end || ExitCode.new(code)
|
49
|
+
end
|
50
|
+
|
51
|
+
def exit_codes
|
52
|
+
parent ? parent.exit_codes : []
|
53
|
+
end
|
54
|
+
|
55
|
+
def running?
|
56
|
+
thread && thread.alive?
|
57
|
+
end
|
58
|
+
|
59
|
+
def done?
|
60
|
+
!running?
|
61
|
+
end
|
62
|
+
|
63
|
+
def duration
|
64
|
+
timer.current || timer.last
|
65
|
+
end
|
66
|
+
|
67
|
+
def kill
|
68
|
+
return true unless thread
|
69
|
+
thread.kill
|
70
|
+
end
|
71
|
+
|
72
|
+
def error?
|
73
|
+
result && result.exit_code.error?
|
74
|
+
end
|
75
|
+
|
76
|
+
def success?
|
77
|
+
!error?
|
78
|
+
end
|
79
|
+
|
80
|
+
def eta
|
81
|
+
@eta || estimate_eta
|
82
|
+
end
|
83
|
+
|
84
|
+
def estimate_eta
|
85
|
+
return 0 unless percent && timer.current && percent.positive?
|
86
|
+
(100 - percent) / timer.current
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
def process_line(line, stream = :stdout)
|
92
|
+
self.result.body = self.result.body + line
|
93
|
+
case stream
|
94
|
+
when :stderr
|
95
|
+
STDERR.puts line unless line.to_s.empty?
|
96
|
+
else
|
97
|
+
# Nothing happens with stdout in the default job class
|
98
|
+
# puts line
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CLIChef
|
2
|
+
class Result
|
3
|
+
include BBLib::Effortless
|
4
|
+
|
5
|
+
attr_of Object, :body, default: nil, allow_nil: true
|
6
|
+
attr_str :cmd, default: nil, allow_nil: true
|
7
|
+
attr_of ExitCode, :exit_code, default: nil, allow_nil: true
|
8
|
+
attr_int :pid, default: 0
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cli_chef
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brandon Black
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bblib
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
description: CLI Chef makes building command line wrappers easy and simple to incorporate
|
70
|
+
with your Ruby projects.
|
71
|
+
email:
|
72
|
+
- d2sm10@hotmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
80
|
+
- CODE_OF_CONDUCT.md
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- bin/console
|
86
|
+
- bin/setup
|
87
|
+
- cli_chef.gemspec
|
88
|
+
- lib/bblib/bbfiles.rb
|
89
|
+
- lib/cli_chef.rb
|
90
|
+
- lib/cli_chef/apps/hand_brake.rb
|
91
|
+
- lib/cli_chef/apps/hand_brake/hand_brake_job.rb
|
92
|
+
- lib/cli_chef/apps/media_info.rb
|
93
|
+
- lib/cli_chef/apps/sevenzip.rb
|
94
|
+
- lib/cli_chef/apps/sevenzip/archive.rb
|
95
|
+
- lib/cli_chef/apps/sevenzip/dir.rb
|
96
|
+
- lib/cli_chef/apps/sevenzip/file.rb
|
97
|
+
- lib/cli_chef/apps/sevenzip/item.rb
|
98
|
+
- lib/cli_chef/apps/sevenzip/util.rb
|
99
|
+
- lib/cli_chef/cli_chef.rb
|
100
|
+
- lib/cli_chef/components/cookbook.rb
|
101
|
+
- lib/cli_chef/components/exit_code.rb
|
102
|
+
- lib/cli_chef/components/ingredient.rb
|
103
|
+
- lib/cli_chef/components/job.rb
|
104
|
+
- lib/cli_chef/components/result.rb
|
105
|
+
- lib/cli_chef/version.rb
|
106
|
+
homepage: http://github.com/bblack16/cli-chef
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.7.4
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: CLI Chef is a simple and quick CLI wrapper framework for Ruby.
|
130
|
+
test_files: []
|