diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a8a13d5..e8db012f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,14 +11,10 @@ jobs: fail-fast: false matrix: ruby: - - "2.3" - - "2.4" - - "2.5" - - "2.6" - - "2.7" - "3.0" - "3.1" - "3.2" + - "3.3" env: BUNDLE_WITHOUT: development steps: diff --git a/.gitignore b/.gitignore index 02160624..04969ed2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,3 @@ /man/*.markdown /pkg/ /vendor -Gemfile.lock diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..34c5164d --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--format documentation +--color +--require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..d9cdc7bd --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,120 @@ +--- +inherit_mode: + merge: + - Exclude + +require: + - standard + - standard-custom + - standard-performance + - rubocop-performance + - rubocop-rake + - rubocop-rspec + - rubocop-capybara + +inherit_gem: + standard: config/base.yml + standard-performance: config/base.yml + standard-custom: config/base.yml + +# custom enables/disables +Layout/LineLength: + Enabled: false +Layout/EmptyLineBetweenDefs: + AllowAdjacentOneLineDefs: true +Style/DisableCopsWithinSourceCodeDirective: + Enabled: true +Rake/Desc: + Enabled: false +RSpec/MultipleExpectations: + Enabled: false +RSpec/ExampleLength: + Enabled: false + +# +# Ignore differences from Rails autogeneration +# +Layout/SpaceInsideHashLiteralBraces: + Exclude: + - 'config/environments/*' +Layout/ExtraSpacing: + Exclude: + - 'config/environments/*' +Style/GlobalStdStream: + Exclude: + - 'config/environments/*' +Layout/SpaceInsideArrayLiteralBrackets: + Exclude: + - 'config/environments/*' + +# +# Ignore differences from RSpec autogeneration +# +Style/StringLiterals: + Exclude: + - 'spec/rails_helper.rb' + +AllCops: + NewCops: enable + Include: + - '**/*.rb' + - '**/*.arb' + - '**/*.axlsx' + - '**/*.builder' + - '**/*.fcgi' + - '**/*.gemfile' + - '**/*.gemspec' + - '**/*.god' + - '**/*.jb' + - '**/*.jbuilder' + - '**/*.mspec' + - '**/*.opal' + - '**/*.pluginspec' + - '**/*.podspec' + - '**/*.rabl' + - '**/*.rake' + - '**/*.rbuild' + - '**/*.rbw' + - '**/*.rbx' + - '**/*.ru' + - '**/*.ruby' + - '**/*.schema' + - '**/*.spec' + - '**/*.thor' + - '**/*.watchr' + - '**/.irbrc' + - '**/.pryrc' + - '**/.simplecov' + - '**/buildfile' + - '**/Appraisals' + - '**/Berksfile' + - '**/Brewfile' + - '**/Buildfile' + - '**/Capfile' + - '**/Cheffile' + - '**/Dangerfile' + - '**/Deliverfile' + - '**/Fastfile' + - '**/*Fastfile' + - '**/Gemfile' + - '**/Guardfile' + - '**/Jarfile' + - '**/Mavenfile' + - '**/Podfile' + - '**/Puppetfile' + - '**/Rakefile' + - '**/rakefile' + - '**/Schemafile' + - '**/Snapfile' + - '**/Steepfile' + - '**/Thorfile' + - '**/Vagabondfile' + - '**/Vagrantfile' + Exclude: + - 'target/**/*' + - 'node_modules/**/*' + - 'src/**/*' + - 'tmp/**/*' + - 'vendor/**/*' + - '.git/**/*' + - 'db/migrate/*.active_storage.rb' diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..fa7adc7a --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.3.5 diff --git a/.solargraph.yml b/.solargraph.yml new file mode 100644 index 00000000..1ef86eb8 --- /dev/null +++ b/.solargraph.yml @@ -0,0 +1,24 @@ +--- +include: +- "**/*.rb" +exclude: +- spec/**/* +- test/**/* +- vendor/**/* +- ".bundle/**/*" +require: [] +domains: [] +reporters: +- rubocop +- require_not_found +- typecheck +- update_errors +formatter: + rubocop: + cops: safe + except: [] + only: [] + extra_args: [] +require_paths: [] +plugins: [] +max_files: 5000 diff --git a/.standard.yml b/.standard.yml new file mode 100644 index 00000000..b02384f4 --- /dev/null +++ b/.standard.yml @@ -0,0 +1,4 @@ +# For available configuration options, see: +# https://github.com/testdouble/standard +--- +ruby_version: 3.3 diff --git a/Changelog.md b/Changelog.md deleted file mode 100644 index c1cf4048..00000000 --- a/Changelog.md +++ /dev/null @@ -1,712 +0,0 @@ -## 0.88.1 (2024-04-12) - -* update master to main [David Dollar] - -## 0.88.0 (2024-04-12) - -* use actions/checkout@v4 [David Dollar] -* remove Gemfile.lock from repo because it's too strict [David Dollar] -* update for ci [David Dollar] -* handle empty procfile exception in cli [David Dollar] -* Update man page to reflect recent changes in systemd export [Lukáš Konarovský] -* [engine/cli.rb] Handle nil name_padding [Nick LaMuro] -* [Foreman::Procfile#load] Fail when empty [Nick LaMuro] -* spec_helper: don't try to remove /tmp [Antonio Terceiro] -* Fix misleading comment at the top of procfile.rb that indicates that hyphens "-" are not allowed in process names. [Ben Wilber] -* Rename usage of Dir/File.exists to exist [Qiu Chaofan] -* remove codeclimate [David Dollar] -* clean up and autoformat [David Dollar] -* Add GitHub token permissions for workflow [mishina] -* Migrate from Travis CI to GitHub Actions [mishina] -* Pass a block rather than an argument to `expect` [mishina] -* Replace `File.exists?` with `File.exist?` [mishina] -* Use the latest fakefs [mishina] -* Remove and ignore Gemfile.lock [mishina] -* Add GitHub Actions workflow [mishina] -* GitHub is HTTPS by default [Akira Matsuda] - -## 0.87.2 (2020-08-07) - -* update json for CVE-2020-10663 [David Dollar] - -## 0.87.1 (2020-04-02) - -* update rake for CVE-2020-8130 [David Dollar] - -## 0.87.0 (2020-01-07) - -* Update specs for systemd export [Robin Daugherty] -* Allow processes to be stopped using the app target [Robin Daugherty] -* Wait to restart [Robin Daugherty] -* systemd sets process name [Robin Daugherty] - -## 0.86.0 (2019-10-09) - -* bundle (but don't use) real thor to ensure we still get vulnerability notifications from github. [Micah Geisel] -* we don't need automatiek loaded to boot. [Micah Geisel] -* inline thor dependency. [Micah Geisel] -* CI: Use ruby 2.5.6, 2.6.4 in the matrix [Olle Jonsson] -* add wiki page with reason for not bundling to readme [David Dollar] -* CI: Use 2.4.6, 2.5.5, 2.6.3 [Olle Jonsson] -* update yard for GHSA-xfhh-rx56-rxcr [David Dollar] - -## 0.85.0 (2018-06-18) - -* updates rubies in travis - ensures only running with PID would be killed - updates dependencies; runs `codeclimate-test-reporter` after successful build - updates rubies for travis - squashes commits [LeFnord] -* Deprecate safe_level of ERB.new in Ruby 2.6 [Koichi ITO] -* gitignore [David Dollar] -* update yard [David Dollar] -* Don't upcase env names for daemon processes [Matthew Savage] -* Don't upcase env names in Launchd [Matthew Savage] -* No upcase for env name in Systemd [Matthew Savage] -* Don't force env var names to be upcased [Matthew Savage] -* Test that invalid Procfile entries are ignored [Kevin Litchfield] -* Remove unused block parameter [Kevin Litchfield] - -## 0.84.0 (2017-03-28) - -* add test for systemd template (closes: #664) [Timur Batyrshin] -* quote env vars as was suggested in https://github.com/ddollar/foreman/pull/652 [Timur Batyrshin] -* update specs [Koen Punt] -* update specs [Koen Punt] -* forward user signals (SIGUSR1, SIGUSR2) [Tilo Prütz] -* make systemctl stop/restart/reload work [Koen Punt] -* 0.83.0 [David Dollar] -* use default stop signal for supervisord [Chris Blättermann] -* updated fakefs to silence warnings during tests [Chris Blättermann] -* Add option to suppress timestamps [Glenn Oppegard] -* Add ruby 2.3.3 to travis [Tejas Bubane] -* Change systemd KillMode to "mixed" [Reto Kaiser] -* Relax systemd template spec matcher for env var [Reto Kaiser] -* Don't print newline in systemd template if no ENV vars given [Reto Kaiser] -* pp must be required before fakefs [Reto Kaiser] -* Typo [Lin] -* Fixed empty Environment line for Travis [Lin] -* More compact and escaped environment variable names [Lin] -* Add spm (go port) [Ömer Ufuk Efendioğlu] -* Port to rspec 3 [Antonio Terceiro] -* README: Use fancy SVG badges [ci skip] [Olle Jonsson] -* defined process filename format only once [Koen Punt] -* clean all upstart process files [Koen Punt] -* Fix small typo in man page [Dov Murik] -* Foreman Export Upstart should not duplicate ports [Steven Daniels] - -## 0.82.0 (2016-05-21) - -* Fixes #626. Use -m for concurrency when using the export command. [Jori Hardman] -* Add stop timeout to systemd services [Christian Haase] -* systemd exporter creates target dependencies via symlinks [Christian Haase] -* Update systemd exporter to generate instantiated services [Christian Haase] -* changelog [David Dollar] - -## 0.81.0 (2016-04-26) - -* Revert "Create a new process group when spawning a new process. This should prevent from SIGINT propagating to spawned processes. (#528)" [David Dollar] -* Fix cleaning up unrelated configuration files (#617) [Per-Henrik Lundblom] - -## 0.80.2 (2016-04-24) - -* fix nil status error [David Dollar] - -## 0.80.1 (2016-04-23) - -* ignore gems [David Dollar] -* add package dir [David Dollar] - -## 0.80.0 (2016-04-23) - -* Update README.md (#614) [Hernan Y.Ke] -* Fix Windows crash, caused by read_nonblock (#576) [Igor Antonov] -* update gems [David Dollar] -* Propagate process failure [4r2r] -* update gems [David Dollar] -* remove win32console dependency [Takumi IINO] -* Added possible fix for pkg install on El Capitan. (#585) [Jeroen Visser] -* use proper check to see if file exists (#577) [Mateusz Byczkowski] -* Allow supervisord environment vars to have "=" (#572) [Stephen Yeargin] -* Document $PORT and $PS (#562) [Mike Burns] -* An location -> A location (#543) [Eliot Sykes] -* Fix signal exception name (#530) [Oleksiy Kovyrin] -* Make a single thread responsible for handling graceful shutdown (#529) [Oleksiy Kovyrin] -* Create a new process group when spawning a new process. This should prevent from SIGINT propagating to spawned processes. (#528) [Oleksiy Kovyrin] -* use the latest bundler [David Dollar] -* check all the rubies [David Dollar] -* Revert "test on 2.x releases" [David Dollar] -* test on 2.x releases [David Dollar] -* remove dotenv as it's not worth the dependency hell. closes #505, #538 [David Dollar] -* Port tests to fakefs 0.4 [Antonio Terceiro] -* add documentation to cli (formation options describtion) (#523) [Leonid Batizhevsky] -* Replaces 'concurrency' with 'formation' in manpage (#524) [Piers Mainwaring] -* Work around potential nil $? (#526) [David Zülke] -* update gems [David Dollar] -* remove ruby 1.9 support [David Dollar] -* Update README URLs based on HTTP redirects [ReadmeCritic] -* Add port to Haskell to README [Daisuke Fujimura] -* Adds 'Crank' to README.md: a port of Foreman to Crystal [arktisklada] -* fix specs [Pierpaolo Frasa] -* Fixed erb tags in systemd process.service template. [Tomasz Łoszko] -* use PartOf [Pierpaolo Frasa] -* don't stop systemd master target immediately [Pierpaolo Frasa] -* Add goreman (go port) [Francois] -* Strip non-quoted whitespace [pik] -* Procfile#[] return nil for non-existing entries [Simon Rozet] -* update changeling [David Dollar] - -## 0.78.0 (2015-03-13) - -* remove dotenv as it's not worth the dependency hell [David Dollar] -* Do not parse options after "run" argument, to avoid conflicts. [Giovanni Bajo] -* Update docs with --timeout [Stephen Bussey] - -## 0.77.0 (2015-01-01) - -* 0.77.0 [David Dollar] -* Do not change the output of clean [Łukasz Korecki] -* Only delete upstart files matching application name. [Łukasz Korecki] -* Add failling test for case where app.conf and app-worker.conf would be deleted [Łukasz Korecki] -* Test against Ruby 2.2 on Travis CI [Ryunosuke SATO] -* Nicer formatting for exported supervisord files [Marc Abramowitz] - -## 0.76.0 (2014-11-25) - -* 0.76.0 [David Dollar] -* Merge pull request #501 from dylanegan/tech/update_dotenv [David Dollar] -* Update dotenv. :v: [Dylan Egan] -* Merge pull request #498 from dgouldin/master [David Dollar] -* Preventing SIGINT from killing `foreman run` directly [David Gouldin] -* see travis.yml [David Dollar] -* Merge pull request #495 from formigarafa/patch-4 [David Dollar] -* Updated Readme [Rafael Santos] -* testing under latest versions of ruby 2.1 [Rafael Santos] -* remove noreman and alphabetize, closes #482 [David Dollar] -* Merge pull request #481 from formigarafa/patch-1 [David Dollar] -* Merge pull request #479 from rrrene/patch-1 [David Dollar] -* Updated Readme to specify supported ruby 2.1 series [Rafael Santos] -* Update travis.yml to include ruby 2.1 series [Rafael Santos] -* added ruby 2.1 series to supported versions [Rafael Santos] -* Add docs badge to README [René Föhring] -* update docs [David Dollar] -* update docs [David Dollar] - -## 0.75.0 (2014-08-27) - -* 0.75.0 [David Dollar] -* Merge pull request #478 from sergeyromanov/patch-1 [David Dollar] -* add Perl port (proclet) [Сергей Романов] -* Merge pull request #477 from dickeyxxx/windows-compat [David Dollar] -* prevent windows from crashing on startup [dickeyxxx] -* Merge pull request #474 from jingweno/patch-1 [David Dollar] -* Add `gaffer` [Jingwen Owen Ou] -* ignore .env [David Dollar] -* clean up gitignore [David Dollar] -* update docs [David Dollar] - -## 0.74.0 (2014-06-19) - -* 0.74.0 [David Dollar] -* fix gemfile.lock [David Dollar] -* Revert "Merge pull request #461 from nearapogee/master" [David Dollar] -* use FOREMAN_ for releases [David Dollar] -* update docs [David Dollar] - -## 0.73.0 (2014-06-19) - -* 0.73.0 [David Dollar] - -## 0.72.0 (2014-06-19) - -* add concurrency example to docs [David Dollar] -* update docs [David Dollar] - -## 0.71.0 (2014-06-02) - -* 0.71.0 [David Dollar] -* update release task to do everything [David Dollar] -* update docs [David Dollar] - -## 0.70.0 (2014-06-02) - -* 0.70.0 [David Dollar] -* handle interrupts during run [David Dollar] -* update thor and dotenv [David Dollar] -* excise jruby [David Dollar] -* update docs [David Dollar] -* 0.69.0 [David Dollar] -* bring all versions into execution parity [David Dollar] -* remove unused code [David Dollar] -* expand test coverage [David Dollar] -* make test more reliable [David Dollar] -* upgrade rspec [David Dollar] -* not used [David Dollar] -* Merge pull request #461 from nearapogee/master [David Dollar] -* add logging back into upstart exports. [Matt Smith] -* fix typo [David Dollar] -* add code climate test coverage [David Dollar] -* refactor a bit [David Dollar] -* Merge pull request #460 from TiuTalk/add-badges [David Dollar] -* Add CodeClimate badge [Thiago Belem] -* Add Travis badge [Thiago Belem] -* update docs [David Dollar] - -## 0.68.0 (2014-05-22) - -* 0.68.0 [David Dollar] -* tweak docs [David Dollar] -* remove jruby [David Dollar] -* separate development and test gems [David Dollar] -* tweak bundler args [David Dollar] -* excise ruby 1.8 and posix-spawn [David Dollar] -* update travis.yml for builds [David Dollar] -* fix up specs [David Dollar] -* updated rspec tests from old `should` syntax to newer `expect` syntax [irmiller22] -* updated RSpec to 2.14 [irmiller22] -* Merge pull request #454 from kevin-cantwell/master [David Dollar] -* allows project path to contain spaces [Kevin Cantwell] -* tweak readme wording [David Dollar] -* Merge pull request #444 from seamusabshere/patch-3 [David Dollar] -* hey Rubyists, don't put foreman in Gemfile [Seamus Abshere] -* update docs [David Dollar] - -## 0.67.0 (2014-04-24) - -* 0.67.0 [David Dollar] -* use thor 0.17.0 [David Dollar] -* update docs [David Dollar] - -## 0.66.0 (2014-04-23) - -* 0.66.0 [David Dollar] -* Merge pull request #439 from ssendev/patch-1 [David Dollar] -* don't fail if chown dir dosn't exist [ssendev] -* don't fail export if log/run dosn't exist [ssendev] -* update docs [David Dollar] - -## 0.65.0 (2014-04-23) - -* 0.65.0 [David Dollar] -* bump and freeze thor [David Dollar] -* Merge pull request #438 from phemmer/native_upstart [David Dollar] -* Clean up upstart export to use native upstart features [Patrick Hemmer] -* Merge pull request #364 from shokai/replace_PORT_launchd_export [David Dollar] -* Merge pull request #368 from avtobiff/remove-taskman-script [David Dollar] -* Don't make log and run dirs on export [Omar Khan] -* Merge pull request #395 from brandonhilkert/supervisor-export-env [David Dollar] -* Merge pull request #396 from phemmer/systemd-dependencies [David Dollar] -* Merge pull request #400 from toooooooby/patch-1 [David Dollar] -* Merge pull request #401 from ahawkins/patch-1 [David Dollar] -* Merge pull request #421 from JonRowe/test_writable_if_no_chown [David Dollar] -* Merge pull request #428 from beeblebrox/fix-process-exec [David Dollar] -* Merge pull request #432 from comron/fix-runit-log-permissions [David Dollar] -* Merge pull request #433 from charliesome/fix-relative-path [David Dollar] -* fix changelog [David Dollar] -* update docs [David Dollar] -* add an extra ../ when dealing with relative paths [Charlie Somerville] -* Fix mkdir mode flag when creating runit log directories [Comron Sattari] -* export: fix systemd dependencies [Patrick Hemmer] -* Exec process, otherwise only the shell receives signal. [James N. Hart] -* Test to see if we can already write to chowned dir's if chown fails [Jon Rowe] -* Use %Q{} to allow commands with quotes [Adam Hawkins] -* Improve the runit exporter to log with the stderr [TOBY] -* Quotes the values of ENV in supervisor export to guard against non-numeric values. Fixes #394. [Brandon Hilkert] -* Remove taskman script [Per Andersson] -* replace $PORT in launchd export [Sho Hashimoto] - -## 0.64.0 (2014-04-22) - -* 0.64.0 [David Dollar] -* 0.63.1 [David Dollar] -* be more specific with dotenv dependency [David Dollar] -* Merge pull request #388 from brixen/patch-1 [David Dollar] -* Update README.md [Brian Shirai] -* Merge pull request #366 from wfarr/tgz-install-foreman-to-bin [David Dollar] -* Install tgz/foreman to bin/foreman in tgz package [Will Farrington] -* Merge pull request #305 from marclennox/master [David Dollar] -* Merge pull request #360 from kjwierenga/feature/require-posix-spawn [David Dollar] -* Fail with an error on Ruby 1.8 when posix-spawn is not present. [Klaas Jan Wierenga] -* Require and use 'posix/spawn' when running ruby 1.8 without using Foreman.ruby_18? (which is the subject under test). [Klaas Jan Wierenga] -* Added start-stop-daemon support. [Marc Lennox] -* Merge pull request #353 from austiniam/master [David Dollar] -* fixed conflicts [Austin Cherry] -* modified to use shellescape instead of gsub [Austin] -* added support for directories with single quotes. fixes #315 [Austin] -* kill the children, not self [David Dollar] -* fix docs, thanks to @Invizory [David Dollar] -* not sure how this snuck in, not in the exporter format [David Dollar] -* update docs [David Dollar] -* Merge pull request #340 from ldmosquera/set_env_var_with_process_name [David Dollar] -* Merge pull request #355 from JoeyButler/fix_typo_in_man [David Dollar] -* Merge pull request #359 from kjwierenga/feature/make-ruby-18-compatible [David Dollar] -* The wrapped_command has spaces which triggers Ruby to fork a system shell (with /bin/sh -c). This causes orphaned processes on some systems (i.e. Linux). Fix this by splitting the command using String#shellsplit and using ruby's splat operator (*) to pass discrete arguments to spawn. [Klaas Jan Wierenga] -* Enable ruby 1.8.7 building on Travis. All specs should pass now on ruby 1.8.7. [Klaas Jan Wierenga] -* Use POSIX::Spawn to make foreman ruby 1.8 compatible and have all specs passing. [Klaas Jan Wierenga] -* Use pipe factory method to handle 1.8 incompatible signature for IO.pipe. [Klaas Jan Wierenga] -* Ruby 1.8 doesn't have the concept of string encodings. Compare to the string as is. [Klaas Jan Wierenga] -* Merge pull request #294 from bfulton/master [David Dollar] -* updated systemd export spec after rebasing included 5ef8bbdb [Bright Fulton] -* Fix typo in manual page. [Joey Butler] -* Add unit test for PS env var [Leonardo Mosquera] -* Change FOREMAN_PROCESS_NAME to just PS [Leonardo Mosquera] -* changelog [David Dollar] -* fix spec after d4ab495 [Bright Fulton] -* better default for things which intentionally daemonize child processes, the default KillMode is control-group which survives daemonization [Bright Fulton] -* rough draft for systemd export support [bfulton] -* modified to use shellescape instead of gsub [Austin] -* third time is the charm. :) [Austin] -* fixes #315 [Austin] -* added support for directories with single quotes. fixes #315 [Austin] -* Set FOREMAN_PROCESS_NAME env var for spawned procs [Leonardo Mosquera] - -## 0.63.0 (2013-04-15) - -* Revert "Ensure foreman is the process group leader" [John Griffin] -* remove posix-spawn dependency as it does not work in jruby 1.7.3 [Andrew Brown & Corey Downing] -* Replace Foreman::Env with dotenv [Brandon Keepers] -* [foreman-runner] fix sourcing as . is rarely in PATH [Barry Allard] -* Fixed specs to pass. [Kentaro Kuribayashi] -* Permit underscore for command name in Procfile. [Kentaro Kuribayashi] -* Update man/foreman.1 [Patrick Ellis] -* Remove tmux option from man page [Donald Plummer] -* Prevent upstart export from deleting similarly named upstart files [Andy Morris] -* Add MIT license text [Per Andersson] -* use "start|stop\ on runlevel [x]" for upstart config [Nick Messick] - -## 0.62.0 (2013-03-08) - -* Merge pull request #334 from ged/reentrant_signal_handlers [David Dollar] -* Merge pull request #335 from ged/20_encoding_fix [David Dollar] -* Try to allow children to shut down gracefully [Michael Granger] -* Add deferred signal-handling (fixes #332). [Michael Granger] -* Fix spec encoding problem under Ruby 2.0.0. [Michael Granger] -* add ruby 2.0 to travis [David Dollar] -* Merge pull request #327 from patheticpat/master [David Dollar] -* Fixed a typo in cli options description [Michael Kaiser] -* handled by mingw now [David Dollar] - -## 0.61.0 (2013-01-14) - -* Fix bug in color definitons [nseo] -* Fix for high CPU load when processes close output [Pavel Forkert] -* Ensure foreman is the process group leader [Christos Trochalakis] -* Don't ignore blank lines in the output [Matt Venables] -* Add license to gemspec [petedmarsh] -* Since JRuby 1.9 doesn't require posix/spawn, only follow that path if JRuby is loaded and running in 1.8 mode. [Adam Hutchison] -* Remove explicit requirement on rubygems. [Cyril Rohr] -* Dont use shared_path variable before multistage has a chance at it [Aditya Sanghi] -* Strip Windows Line Endings [Paul Morton] -* Fix man page: --directory is actually --root. [Evan Jones] -* Add timeout switch to CLI [Paulo Luis Franchini Casaretto] -* Remove expectation of double quotes around environment variables from test comparisons [Kevin McAllister] -* Remove explicit wrapping of Shellwords.escape in double quotes [Kevin McAllister] - -## 0.60.2 (2012-10-08) - -* Fix for nil value on io select loop, fixes #260 [Silvio Relli] - -## 0.60.1 (2012-10-08) - -* sleep on select() to avoid spinning the cpu [Silvio Relli] - -## 0.60.0 (2012-09-25) - -* foreman run can run things from the Procfile like heroku run. [Dan Peterson] - -## 0.59.0 (2012-09-15) - -* Use /bin/sh instead of bash for foreman-runner [Jeremy Evans] - -## 0.58.0 (2012-09-14) - -* dont set HOME [David Dollar] -* Add StandardOutPath to launchd export [Aaron Kalin] -* Add command argument string splitting [Aaron Kalin] -* Cleanup launchd exporter [Aaron Kalin] -* Enable trim_mode via '-' in ERB templates [Aaron Kalin] -* Add support for setting environment variables [Aaron Kalin] -* foreman run should exit with the same code as its command [Omar Khan] -* Handle multiline strings in .env file [Szymon Nowak] -* Use path and env variables in the inittab export [Indrek Juhkam] -* fixed the directory option [Arnaud Lachaume] -* Add capistrano export support [Daniel Farrell] - -## 0.57.0 (2012-08-21) - -* fix startup checks for upstart exporter [Aditya Sanghi] - -## 0.56.0 (2012-08-19) - -* read .profile, not .profile.d [David Dollar] - -## 0.55.0 (2012-08-14) - -* use a forked process to exec a run with environment [David Dollar] - -## 0.54.0 (2012-08-14) - -* use Foreman::Process to extract command running [David Dollar] -* changed to check env for bash [brntbeer] - -## 0.53.0 (2012-07-24) - -* put app root in $HOME [David Dollar] - -## 0.52.0 (2012-07-24) - -* wrap command in a runner that sources .profile.d scripts [David Dollar] -* fix upstart export specs [David Dollar] -* Make upstart export start/stop with network [Daniel Farrell] - -## 0.51.0 (2012-07-11) - -* dont try to colorize windows [David Dollar] - -## 0.50.0 (2012-07-11) - -* handle windows [David Dollar] - -## 0.49.0 (2012-07-11) - -* 1.8 compatibility [David Dollar] -* use one pgroup for all of foreman and kill that since ruby 1.8 sucks at pgroups [David Dollar] -* better debugging [David Dollar] - -## 0.48.0 (2012-07-10) - -* allow old exporter format to work, but with deprecation warning [David Dollar] -* remove debugging code [David Dollar] -* Merge pull request #219 from MarkDBlackwell/patch-1 [David Dollar] -* Avoid crash by verifying the existence of SIGHUP before accessing it. [Mark D. Blackwell] -* allow color to be forced on [David Dollar] -* terminate gracefully if stdout goes away [David Dollar] -* always flush output [David Dollar] -* Merge pull request #212 from morgoth/added-version-command [David Dollar] -* added command for displaying foreman version [Wojciech Wnętrzak] -* Merge pull request #211 from morgoth/fixed-yaml-usage [David Dollar] -* fixed using YAML [Wojciech Wnętrzak] -* test on more things, but don't fail [David Dollar] -* changelog [David Dollar] -* 0.48.0.pre1 [David Dollar] -* foreman doesn't work on ruby 1.8, may try to fix later [David Dollar] -* use bash [David Dollar] -* massive refactoring for programmatic control and stability [David Dollar] -* Merge pull request #164 from hsume2/master [David Dollar] -* Only run tmux specs if tmux is installed [Henry Hsu] -* Do not assume BUNDLE_GEMFILE [Henry Hsu] -* Add support for starting procfile in tmux session [Henry Hsu] - -## 0.47.0 (2012-06-07) - -* Fix multi-word argument handling in `foreman run`. [Daniel Brockman] -* Make 'PORT=5000 foreman start' work [Koen Van der Auwera] -* Terminate gracefully upon SIGHUP [Stefan Schüßler] -* Set port from .env if specified [Koen Van der Auwera] -* Updated bluepill exporter to use environment variables from .env [Aneeth] -* Added launchd exporter [Maxwell Swadling] -* Quote and escape environment variables in upstart templates [Matt Griffin] -* Added list of ports to other languages to README [elf Pavlik] - -## 0.46.0 (2012-05-02) - -* Add Profile load/write/append API [Michael Granger] -* Guard against missing Procfile in engine.rb [Brian Kaney] - -## 0.45.0 (2012-04-26) - -* create and chown log dir in upstart export. [Phil Hagelberg] -* remove parka from dist files [David Dollar] - -## 0.44.0 (2012-04-23) - -* make var output order repeatable in supervisord export [David Dollar] -* make --procfile and --app-root influence each other in a more intuitive way [David Dollar] -* Look for .env and app_root in the same dir as the Procfile. [Phil Hagelberg] - -## 0.43.0 (2012-04-20) - -* wrap supervisord env vars in quotes [Raphael Randschau] - -## 0.42.0 (2012-04-18) - -* Move read_environment to a public class method. [Phil Hagelberg] -* Drop parka dependency [Phil Hagelberg] -* add group support for supervisord [Raphael Randschau] -* fix enviroment export [Raphael Randschau] - -## 0.41.0 (2012-03-16) - -* replace term-ansicolor with built-in colorization [David Dollar] -* supervisord export template [Raphael Randschau] - -## 0.40.0 (2012-02-24) - -* support various quoting styles in .env [David Dollar] -* remove load_env! as it's made unnecessary by foreman run [David Dollar] -* Provide a useful error if `foreman check` fails to find a Procfile [R. Tyler Croy] -* update docs [David Dollar] - -## 0.39.0 (2012-02-07) - -* rename bin/runner to bin/foreman-runner [David Dollar] -* fix tgz release [David Dollar] -* bundle update hpricot [John Firebaugh] -* touch up .pkg release tasks [David Dollar] - -## 0.38.0 (2012-02-02) - -* bring back single process starting [David Dollar] -* more attempts at getting ci working with jruby [David Dollar] -* ignore .rbenv-version [David Dollar] -* force to binary encoding if supported [David Dollar] - -## 0.37.2 (2012-01-29) - -* handle directories with spaces in runner [David Dollar] -* update docs [David Dollar] - -## 0.37.1 (2012-01-29) - -* use binary pipes to better handle UTF-8 data [David Dollar] -* set up example procfile with UTF-8 item [David Dollar] -* remove autotest [David Dollar] -* fix up authors generation [David Dollar] -* fix up packaging after moving tasks [David Dollar] -* fix up changelog tasks [David Dollar] - -## 0.37.0 (2012-01-29) - -* put an entire line of output inside a single mutex so we don't cross the streams [David Dollar] -* fix race condition with process termination [David Dollar] -* allow external custom exporters [Chris Lowder] -* fix the test for an empty string in bin/runner [Florian Apolloner] -* ensure we have non-nil data, fixes #111 [David Dollar] -* make sure error method exists, fixes #104 [David Dollar] -* clean up chdir usage [David Dollar] -* normalize platform names [David Dollar] -* add windows support [David Dollar] -* add jruby support [David Dollar] -* pass basedir along to the runner script [David Dollar] -* harden runner script [David Dollar] -* add many missing specs [brainopia] -* clean up fakefs usage in specs [brainopia] -* runit creates a full path to export directory. [Fletcher Nichol] - -## 0.36.1 (2012-01-18) - -* 0.36.1 [David Dollar] -* bump term-ansicolor in gemspec [David Dollar] - -## 0.36.0 (2012-01-17) - -* 0.36.0 [David Dollar] -* sync the writer stream [David Dollar] -* capture stderr as well [David Dollar] - -## 0.35.0 (2012-01-16) - -* update rake [David Dollar] -* 0.35.0 [David Dollar] -* Merge pull request #132 from Viximo/feature/concurrency [David Dollar] -* Fix export specs [Matt Griffin] -* Merge branch 'master' of https://github.com/michaeldwan/foreman into feature/concurrency [Matt Griffin] -* default process concurrency is 0 when concurrency options specified, otherwise default concurrency is 1 [Michael Dwan] - -## 0.34.1 (2012-01-16) - -* 0.34.1 [David Dollar] -* fix missing start desc [David Dollar] - -## 0.34.0 (2012-01-16) - -* 0.34.0 [David Dollar] -* update man page [David Dollar] -* update docs for -d [David Dollar] -* Merge pull request #101 from ndbroadbent/foreman [David Dollar] -* Wrap around to the first colour when all the colours are used [Craig R Webster] -* run specs in random order [David Dollar] -* update rspec [David Dollar] -* pedantry [David Dollar] -* Set executable bit on runit run scripts. [Matthijs Langenberg] -* Merge pull request #114 from gburt/master [David Dollar] -* add more colors [Gabriel Burt] -* Added option to specify app_root, if executing a Procfile from a shared location [Nathan Broadbent] - -## 0.33.1 (2012-01-16) - -* 0.33.1 [David Dollar] -* Merge pull request #129 from fnichol/resolve-home-template [David Dollar] -* Expand template path under user's home directory. [Fletcher Nichol] - -## 0.33.0 (2012-01-15) - -* 0.33.0 [David Dollar] -* Revert "Merge pull request #125 from brainopia/master" [David Dollar] - -## 0.32.0 (2012-01-12) - -* 0.32.0 [David Dollar] -* Merge pull request #125 from brainopia/master [David Dollar] -* Merge pull request #121 from Viximo/feature/run [David Dollar] -* Return some whitespace that was accidentally removed [Matt Griffin] -* Steal the run method back from Thor so that it can be used in place for exec for running commands in the foreman environment. [Matt Griffin] -* Remove old cruft [brainopia] -* In case someone wants to use bin/runner directly [brainopia] -* Fix for double fork [brainopia] -* Use ruby exec which works with escaped cmd and replaces shell [brainopia] -* Fix foreman to work with cmds containing pipes and redirects [brainopia] -* Add "exec" action to allow execution of arbitrary commands with the app's environment. [Matt Griffin] -* tweak readme [David Dollar] - -## 0.31.0 (2012-01-04) - -* 0.31.0 [David Dollar] -* make fork more robust [David Dollar] -* remove unnecessary debug [David Dollar] -* add more information when shutting down [David Dollar] -* Merge pull request #110 from lstoll/master [David Dollar] -* Use different port ranges for each process type [Lincoln Stoll] - -## 0.30.1 (2011-12-23) - -* 0.30.1 [David Dollar] -* require thread for mutex [David Dollar] - -## 0.30.0 (2011-12-22) - -* 0.30.0 [David Dollar] -* compatibility with ruby 1.8 [David Dollar] - -## 0.29.0 (2011-12-22) - -* 0.29.0 [David Dollar] -* 0.28.0.pre2 [David Dollar] -* fix pipe error [David Dollar] -* 0.28.0.pre1 [David Dollar] -* Merge branch 'fork' [David Dollar] -* wip [David Dollar] -* wip [David Dollar] -* wip [David Dollar] -* wip [David Dollar] -* wip [David Dollar] - -## 0.27.0 (2011-12-05) - -* 0.27.0 [David Dollar] -* add changelog [David Dollar] -* Merge pull request #103 from csquared/load_env_from_irb [David Dollar] -* refactor load_env to apply_environment [Chris Continanza] -* rename load! to load_env! [Chris Continanza] -* use ./.env as default [Chris Continanza] -* load contents from env file [Chris Continanza] -* refactor engine to expose env methods [Chris Continanza] -* disable email notifications [David Dollar] -* add travis config [David Dollar] - -## 0.26.1 2011-12-05 - -* Merge pull request #103 from csquared/load_env_from_irb [David Dollar] -* refactor load_env to apply_environment [Chris Continanza] -* rename load! to load_env! [Chris Continanza] -* use ./.env as default [Chris Continanza] -* load contents from env file [Chris Continanza] -* refactor engine to expose env methods [Chris Continanza] -* disable email notifications [David Dollar] -* add travis config [David Dollar] diff --git a/Gemfile b/Gemfile index 462036bc..7c5f8073 100644 --- a/Gemfile +++ b/Gemfile @@ -2,19 +2,22 @@ source "http://rubygems.org" gemspec -gem 'thor', '0.19.4', :require => false - group :test do - gem 'rake' - gem 'fakefs' - gem 'rspec', '~> 3.5' - gem "simplecov", :require => false - gem 'timecop' + gem "fakefs" + gem "rspec", "~> 3.5" + gem "simplecov", require: false + gem "timecop" end group :development do - gem 'aws-s3' - gem 'ronn-ng' - gem 'yard', '~> 0.9.11' - gem 'automatiek' + gem "aws-s3" + gem "ronn-ng" + gem "yard", "~> 0.9.11" + gem "automatiek" end + + +gem "thor", "~> 1.3" + +gem "rake", "~> 13.2", :groups => [:development, :test] +gem "peppermint", "~> 0.1.14", :groups => [:development, :test] diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..4bb6019a --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,228 @@ +PATH + remote: . + specs: + foreman (0.88.1) + +GEM + remote: http://rubygems.org/ + specs: + activesupport (7.2.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + ast (2.4.2) + automatiek (0.3.0) + aws-s3 (0.6.3) + builder + mime-types + xml-simple + backport (1.2.0) + base64 (0.2.0) + benchmark (0.3.0) + bigdecimal (3.1.8) + builder (3.3.0) + byebug (11.1.3) + coderay (1.1.3) + concurrent-ruby (1.3.4) + connection_pool (2.4.1) + diff-lcs (1.5.1) + docile (1.4.1) + drb (2.2.1) + e2mmap (0.1.0) + fakefs (2.5.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) + jaro_winkler (1.6.0) + json (2.7.2) + kramdown (2.4.0) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + language_server-protocol (3.17.0.3) + lint_roller (1.1.0) + logger (1.6.1) + method_source (1.1.0) + mime-types (3.5.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2024.0903) + minitest (5.25.1) + mustache (1.1.1) + nokogiri (1.16.7-aarch64-linux) + racc (~> 1.4) + nokogiri (1.16.7-arm-linux) + racc (~> 1.4) + nokogiri (1.16.7-arm64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86-linux) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-linux) + racc (~> 1.4) + parallel (1.26.3) + parser (3.3.5.0) + ast (~> 2.4.1) + racc + peppermint (0.1.14) + pry-byebug (~> 3.10) + rake (~> 13.2) + rdoc (~> 6.7) + rspec (~> 3.13) + rubocop (~> 1.65) + rubocop-capybara (~> 2.21) + rubocop-rails (~> 2.26) + rubocop-rake (~> 0.6) + rubocop-rspec (~> 3.0, >= 3.0.5) + rubocop-rspec_rails (~> 2.30) + solargraph (~> 0.50) + standard (~> 1.40) + standard-rails (~> 1.2) + yard (~> 0.9.37) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.10.1) + byebug (~> 11.0) + pry (>= 0.13, < 0.15) + psych (5.1.2) + stringio + racc (1.8.1) + rack (3.1.7) + rainbow (3.1.1) + rake (13.2.1) + rbs (2.8.4) + rdoc (6.7.0) + psych (>= 4.0.0) + regexp_parser (2.9.2) + reverse_markdown (2.1.1) + nokogiri + rexml (3.3.7) + ronn-ng (0.10.1) + kramdown (~> 2, >= 2.1) + kramdown-parser-gfm (~> 1, >= 1.0.1) + mustache (~> 1) + nokogiri (~> 1, >= 1.14.3) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.1) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.1) + rubocop (1.65.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.4, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.32.3) + parser (>= 3.3.1.0) + rubocop-capybara (2.21.0) + rubocop (~> 1.41) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails (2.26.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.52.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rake (0.6.0) + rubocop (~> 1.0) + rubocop-rspec (3.0.5) + rubocop (~> 1.61) + rubocop-rspec_rails (2.30.0) + rubocop (~> 1.61) + rubocop-rspec (~> 3, >= 3.0.1) + ruby-progressbar (1.13.0) + securerandom (0.3.1) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.13.0) + simplecov_json_formatter (0.1.4) + solargraph (0.50.0) + backport (~> 1.2) + benchmark + bundler (~> 2.0) + diff-lcs (~> 1.4) + e2mmap + jaro_winkler (~> 1.5) + kramdown (~> 2.3) + kramdown-parser-gfm (~> 1.1) + parser (~> 3.0) + rbs (~> 2.0) + reverse_markdown (~> 2.0) + rubocop (~> 1.38) + thor (~> 1.0) + tilt (~> 2.0) + yard (~> 0.9, >= 0.9.24) + standard (1.40.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.65.0) + standard-custom (~> 1.0.0) + standard-performance (~> 1.4) + standard-custom (1.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.50) + standard-performance (1.4.0) + lint_roller (~> 1.1) + rubocop-performance (~> 1.21.0) + standard-rails (1.2.0) + lint_roller (~> 1.0) + rubocop-rails (~> 2.26.0) + stringio (3.1.1) + thor (1.3.2) + tilt (2.4.0) + timecop (0.9.10) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (2.5.0) + xml-simple (1.1.9) + rexml + yard (0.9.37) + +PLATFORMS + aarch64-linux + arm-linux + arm64-darwin + x86-linux + x86_64-darwin + x86_64-linux + +DEPENDENCIES + automatiek + aws-s3 + fakefs + foreman! + peppermint (~> 0.1.14) + rake (~> 13.2) + ronn-ng + rspec (~> 3.5) + simplecov + thor (~> 1.3) + timecop + yard (~> 0.9.11) + +BUNDLED WITH + 2.5.18 diff --git a/LICENSE b/LICENSE index a6d17d11..2f4b7262 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,5 @@ +This is a fork of [Foreman](https://github.com/ddollar/foreman), which is licensed as follows: + Copyright (c) 2012 David Dollar Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/README.md b/README.md index 4b981135..b6877340 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,10 @@ -# Foreman +# Thorman -[![CI](https://github.com/ddollar/foreman/actions/workflows/ci.yml/badge.svg)](https://github.com/ddollar/foreman/actions/workflows/ci.yml) +[Foreman](https://github.com/ddollar/foreman) with updated +[Thor](https://rubygems.org/gems/thor). -Manage Procfile-based applications +How to install? -## Installation - - $ gem install foreman - -Ruby users should take care _not_ to install foreman in their project's `Gemfile`. See this [wiki article](https://github.com/ddollar/foreman/wiki/Don't-Bundle-Foreman) for more details. - -## Getting Started - -- http://blog.daviddollar.org/2011/05/06/introducing-foreman.html - -## Supported Ruby versions - -See [ci.yml](.github/workflows/ci.yml) for a list of Ruby versions against which Foreman is tested. - -## Documentation - -- [man page](http://ddollar.github.io/foreman/) -- [wiki](https://github.com/ddollar/foreman/wiki) -- [changelog](https://github.com/ddollar/foreman/blob/main/Changelog.md) - -## Ports - -- [forego](https://github.com/ddollar/forego) - Go -- [node-foreman](https://github.com/strongloop/node-foreman) - Node.js -- [gaffer](https://github.com/jingweno/gaffer) - Java/JVM -- [goreman](https://github.com/mattn/goreman) - Go -- [honcho](https://github.com/nickstenning/honcho) - python -- [proclet](https://github.com/kazeburo/Proclet) - Perl -- [shoreman](https://github.com/chrismytton/shoreman) - shell -- [crank](https://github.com/arktisklada/crank) - Crystal -- [houseman](https://github.com/fujimura/houseman) - Haskell -- [spm](https://github.com/bytegust/spm) - Go - -## Authors - -#### Created and maintained by - -David Dollar - -#### Patches contributed by - -[Contributor List](https://github.com/ddollar/foreman/contributors) - -## License - -Foreman is licensed under the MIT license. - -See LICENSE for the full license text. +```shell +bundle add thorman +``` diff --git a/Rakefile b/Rakefile index 8f701152..a3ee19bd 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +require "peppermint/rake" + $:.unshift File.expand_path("../lib", __FILE__) require "foreman" diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..77af17e5 --- /dev/null +++ b/biome.json @@ -0,0 +1,17 @@ +{ + "css": { + "formatter": { + "indentStyle": "space" + } + }, + "json": { + "formatter": { + "indentStyle": "space" + } + }, + "javascript": { + "formatter": { + "indentStyle": "space" + } + } +} diff --git a/data/example/ticker b/data/example/ticker index fe0d6290..99a7009f 100755 --- a/data/example/ticker +++ b/data/example/ticker @@ -2,7 +2,7 @@ $stdout.sync = true -%w( SIGINT SIGTERM ).each do |signal| +%w[SIGINT SIGTERM].each do |signal| trap(signal) do puts "received #{signal} but i'm ignoring it!" end diff --git a/foreman.gemspec b/foreman.gemspec index 708bd112..2a7f9ca5 100644 --- a/foreman.gemspec +++ b/foreman.gemspec @@ -1,15 +1,13 @@ -$:.unshift File.expand_path("../lib", __FILE__) +$:.unshift File.expand_path("lib", __dir__) require "foreman/version" Gem::Specification.new do |gem| - gem.name = "foreman" - gem.license = "MIT" - gem.version = Foreman::VERSION + gem.name = "foreman" + gem.license = "MIT" + gem.version = Foreman::VERSION - gem.author = "David Dollar" - gem.email = "ddollar@gmail.com" - gem.homepage = "https://github.com/ddollar/foreman" - gem.summary = "Process manager for applications with multiple components" + gem.author = "Jane Davis" + gem.summary = "Process manager for applications with multiple components" gem.description = gem.summary diff --git a/lib/foreman.rb b/lib/foreman.rb index ca3f754f..d068c078 100644 --- a/lib/foreman.rb +++ b/lib/foreman.rb @@ -1,7 +1,6 @@ require "foreman/version" module Foreman - def self.runner File.expand_path("../../bin/foreman-runner", __FILE__) end @@ -13,5 +12,4 @@ def self.ruby_18? def self.windows? defined?(RUBY_PLATFORM) and RUBY_PLATFORM =~ /(win|w)32$/ end - end diff --git a/lib/foreman/cli.rb b/lib/foreman/cli.rb index f0affefb..38bbb2e5 100644 --- a/lib/foreman/cli.rb +++ b/lib/foreman/cli.rb @@ -6,25 +6,24 @@ require "foreman/version" require "shellwords" require "yaml" -require "foreman/vendor/thor/lib/thor" - -class Foreman::CLI < Foreman::Thor +require "thor" +class Foreman::CLI < Thor include Foreman::Helpers map ["-v", "--version"] => :version - class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile" - class_option :root, :type => :string, :aliases => "-d", :desc => "Default: Procfile directory" + class_option :procfile, type: :string, aliases: "-f", desc: "Default: Procfile" + class_option :root, type: :string, aliases: "-d", desc: "Default: Procfile directory" desc "start [PROCESS]", "Start the application (or a specific PROCESS)" - method_option :color, :type => :boolean, :aliases => "-c", :desc => "Force color to be enabled" - method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env" - method_option :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"', :desc => 'Specify what processes will run and how many. Default: "all=1"' - method_option :port, :type => :numeric, :aliases => "-p" - method_option :timeout, :type => :numeric, :aliases => "-t", :desc => "Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5." - method_option :timestamp, :type => :boolean, :default => true, :desc => "Include timestamp in output" + method_option :color, type: :boolean, aliases: "-c", desc: "Force color to be enabled" + method_option :env, type: :string, aliases: "-e", desc: "Specify an environment file to load, defaults to .env" + method_option :formation, type: :string, aliases: "-m", banner: '"alpha=5,bar=3"', desc: 'Specify what processes will run and how many. Default: "all=1"' + method_option :port, type: :numeric, aliases: "-p" + method_option :timeout, type: :numeric, aliases: "-t", desc: "Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5." + method_option :timestamp, type: :boolean, default: true, desc: "Include timestamp in output" class << self # Hackery. Take the run method away from Thor so that we can redefine it. @@ -34,7 +33,7 @@ def is_thor_reserved_word?(word, type) end end - def start(process=nil) + def start(process = nil) check_procfile! load_environment! engine.load_procfile(procfile) @@ -46,17 +45,17 @@ def start(process=nil) desc "export FORMAT LOCATION", "Export the application to another process management format" - method_option :app, :type => :string, :aliases => "-a" - method_option :log, :type => :string, :aliases => "-l" - method_option :run, :type => :string, :aliases => "-r", :desc => "Specify the pid file directory, defaults to /var/run/" - method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env" - method_option :port, :type => :numeric, :aliases => "-p" - method_option :user, :type => :string, :aliases => "-u" - method_option :template, :type => :string, :aliases => "-t" - method_option :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"', :desc => 'Specify what processes will run and how many. Default: "all=1"' - method_option :timeout, :type => :numeric, :aliases => "-t", :desc => "Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5." - - def export(format, location=nil) + method_option :app, type: :string, aliases: "-a" + method_option :log, type: :string, aliases: "-l" + method_option :run, type: :string, aliases: "-r", desc: "Specify the pid file directory, defaults to /var/run/" + method_option :env, type: :string, aliases: "-e", desc: "Specify an environment file to load, defaults to .env" + method_option :port, type: :numeric, aliases: "-p" + method_option :user, type: :string, aliases: "-u" + method_option :template, type: :string, aliases: "-t" + method_option :formation, type: :string, aliases: "-m", banner: '"alpha=5,bar=3"', desc: 'Specify what processes will run and how many. Default: "all=1"' + method_option :timeout, type: :numeric, aliases: "-t", desc: "Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5." + + def export(format, location = nil) check_procfile! load_environment! engine.load_procfile(procfile) @@ -71,14 +70,14 @@ def export(format, location=nil) def check check_procfile! engine.load_procfile(procfile) - puts "valid procfile detected (#{engine.process_names.join(', ')})" + puts "valid procfile detected (#{engine.process_names.join(", ")})" rescue Foreman::Procfile::EmptyFileError error "no processes defined" end desc "run COMMAND [ARGS...]", "Run a command using your application's environment" - method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env" + method_option :env, type: :string, aliases: "-e", desc: "Specify an environment file to load, defaults to .env" stop_on_unknown_option! :run def run(*args) @@ -89,18 +88,16 @@ def run(*args) end pid = fork do - begin - engine.env.each { |k,v| ENV[k] = v } - if args.size == 1 && process = engine.process(args.first) - process.exec(:env => engine.env) - else - exec args.shelljoin - end - rescue Errno::EACCES - error "not executable: #{args.first}" - rescue Errno::ENOENT - error "command not found: #{args.first}" + engine.env.each { |k, v| ENV[k] = v } + if args.size == 1 && process = engine.process(args.first) + process.exec(env: engine.env) + else + exec args.shelljoin end + rescue Errno::EACCES + error "not executable: #{args.first}" + rescue Errno::ENOENT + error "command not found: #{args.first}" end trap("INT") do Process.kill(:INT, pid) @@ -128,7 +125,7 @@ def engine end end -private ###################################################################### + private ###################################################################### def error(message) puts "ERROR: #{message}" @@ -151,17 +148,19 @@ def load_environment! end def procfile - case - when options[:procfile] then options[:procfile] - when options[:root] then File.expand_path(File.join(options[:root], "Procfile")) - else "Procfile" + if options[:procfile] + options[:procfile] + elsif options[:root] + File.expand_path(File.join(options[:root], "Procfile")) + else + "Procfile" end end def options original_options = super return original_options unless File.file?(".foreman") - defaults = ::YAML::load_file(".foreman") || {} + defaults = ::YAML.load_file(".foreman") || {} Foreman::Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options)) end end diff --git a/lib/foreman/engine.rb b/lib/foreman/engine.rb index a1316593..1e31845a 100644 --- a/lib/foreman/engine.rb +++ b/lib/foreman/engine.rb @@ -7,10 +7,9 @@ require "thread" class Foreman::Engine - # The signals that the engine cares about. # - HANDLED_SIGNALS = [ :TERM, :INT, :HUP, :USR1, :USR2 ] + HANDLED_SIGNALS = [:TERM, :INT, :HUP, :USR1, :USR2] attr_reader :env attr_reader :options @@ -24,25 +23,25 @@ class Foreman::Engine # @option options [Fixnum] :port (5000) The base port to assign to processes # @option options [String] :root (Dir.pwd) The root directory from which to run processes # - def initialize(options={}) + def initialize(options = {}) @options = options.dup @options[:formation] ||= "all=1" @options[:timeout] ||= 5 - @env = {} - @mutex = Mutex.new - @names = {} + @env = {} + @mutex = Mutex.new + @names = {} @processes = [] - @running = {} - @readers = {} - @shutdown = false + @running = {} + @readers = {} + @shutdown = false # Self-pipe for deferred signal-handling (ala djb: http://cr.yp.to/docs/selfpipe.html) - reader, writer = create_pipe + reader, writer = create_pipe reader.close_on_exec = true if reader.respond_to?(:close_on_exec) writer.close_on_exec = true if writer.respond_to?(:close_on_exec) - @selfpipe = { :reader => reader, :writer => writer } + @selfpipe = {reader: reader, writer: writer} # Set up a global signal queue # http://blog.rubybestpractices.com/posts/ewong/016-Implementing-Signal-Handlers.html @@ -67,7 +66,10 @@ def start def register_signal_handlers HANDLED_SIGNALS.each do |sig| if ::Signal.list.include? sig.to_s - trap(sig) { Thread.main[:signal_queue] << sig ; notice_signal } + trap(sig) { + Thread.main[:signal_queue] << sig + notice_signal + } end end end @@ -83,7 +85,7 @@ def restore_default_signal_handlers # Wake the main thread up via the selfpipe when there's a signal # def notice_signal - @selfpipe[:writer].write_nonblock( '.' ) + @selfpipe[:writer].write_nonblock(".") rescue Errno::EAGAIN # Ignore writes that would block rescue Errno::EINTR @@ -145,7 +147,7 @@ def handle_signal_forward(signal) # # @option options [Hash] :env A custom environment for this process # - def register(name, command, options={}) + def register(name, command, options = {}) options[:env] ||= env options[:cwd] ||= File.dirname(command.split(" ").first) process = Foreman::Process.new(command, options) @@ -156,7 +158,7 @@ def register(name, command, options={}) # Clear the processes registered to this +Engine+ # def clear - @names = {} + @names = {} @processes = [] end @@ -167,7 +169,7 @@ def clear def load_procfile(filename) options[:root] ||= File.dirname(filename) Foreman::Procfile.new(filename).entries do |name, command| - register name, command, :cwd => options[:root] + register name, command, cwd: options[:root] end self end @@ -186,7 +188,7 @@ def load_env(filename) # # @param [String] signal The signal to send to each process # - def kill_children(signal="SIGTERM") + def kill_children(signal = "SIGTERM") if Foreman.windows? @running.each do |pid, (process, index)| system "sending #{signal} to #{name_for(pid)} at pid #{pid}" @@ -208,7 +210,7 @@ def kill_children(signal="SIGTERM") # # @param [String] signal The signal to send # - def killall(signal="SIGTERM") + def killall(signal = "SIGTERM") if Foreman.windows? kill_children(signal) else @@ -268,7 +270,7 @@ def root # # @returns [Fixnum] port The port to use for this instance of this process # - def port_for(process, instance, base=nil) + def port_for(process, instance, base = nil) if base base + (@processes.index(process.process) * 100) + (instance - 1) else @@ -289,9 +291,9 @@ def environment env end -private + private -### Engine API ###################################################### + ### Engine API ###################################################### def startup raise TypeError, "must use a subclass of Foreman::Engine" @@ -305,7 +307,7 @@ def shutdown raise TypeError, "must use a subclass of Foreman::Engine" end -## Helpers ########################################################## + ## Helpers ########################################################## def create_pipe IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY") @@ -317,16 +319,15 @@ def name_for(pid) end def name_for_index(process, index) - [ @names[process], index.to_s ].compact.join(".") + [@names[process], index.to_s].compact.join(".") end def parse_formation(formation) pairs = formation.to_s.gsub(/\s/, "").split(",") - pairs.inject(Hash.new(0)) do |ax, pair| + pairs.each_with_object(Hash.new(0)) do |pair, ax| process, amount = pair.split("=") - process == "all" ? ax.default = amount.to_i : ax[process] = amount.to_i - ax + (process == "all") ? ax.default = amount.to_i : ax[process] = amount.to_i end end @@ -357,14 +358,14 @@ def flush_reader(reader) end end -## Engine ########################################################### + ## Engine ########################################################### def spawn_processes @processes.each do |process| 1.upto(formation[@names[process]]) do |n| reader, writer = create_pipe begin - pid = process.run(:output => writer, :env => { + pid = process.run(output: writer, env: { "PORT" => port_for(process, n).to_s, "PS" => name_for_index(process, n) }) @@ -386,7 +387,7 @@ def read_self_pipe def handle_signals while sig = Thread.main[:signal_queue].shift - self.handle_signal(sig) + handle_signal(sig) end end @@ -405,17 +406,15 @@ def handle_io(readers) def watch_for_output Thread.new do - begin - loop do - io = IO.select([@selfpipe[:reader]] + @readers.values, nil, nil, 30) - read_self_pipe - handle_signals - handle_io(io ? io.first : []) - end - rescue Exception => ex - puts ex.message - puts ex.backtrace + loop do + io = IO.select([@selfpipe[:reader]] + @readers.values, nil, nil, 30) + read_self_pipe + handle_signals + handle_io(io ? io.first : []) end + rescue Exception => ex + puts ex.message + puts ex.backtrace end end @@ -458,7 +457,7 @@ def check_for_termination # Delete it from the list of running processes and return its pid @running.delete(pid) - return pid + pid end def terminate_gracefully @@ -466,10 +465,10 @@ def terminate_gracefully # Tell all children to stop gracefully if Foreman.windows? - system "sending SIGKILL to all processes" + system "sending SIGKILL to all processes" kill_children "SIGKILL" else - system "sending SIGTERM to all processes" + system "sending SIGTERM to all processes" kill_children "SIGTERM" end @@ -488,7 +487,7 @@ def terminate_gracefully end # Ok, we have no other option than to kill all of our children - system "sending SIGKILL to all processes" + system "sending SIGKILL to all processes" kill_children "SIGKILL" end end diff --git a/lib/foreman/engine/cli.rb b/lib/foreman/engine/cli.rb index 1cbc66f4..6c01ecf4 100644 --- a/lib/foreman/engine/cli.rb +++ b/lib/foreman/engine/cli.rb @@ -1,30 +1,28 @@ require "foreman/engine" class Foreman::Engine::CLI < Foreman::Engine - module Color - ANSI = { - :reset => 0, - :black => 30, - :red => 31, - :green => 32, - :yellow => 33, - :blue => 34, - :magenta => 35, - :cyan => 36, - :white => 37, - :bright_black => 30, - :bright_red => 31, - :bright_green => 32, - :bright_yellow => 33, - :bright_blue => 34, - :bright_magenta => 35, - :bright_cyan => 36, - :bright_white => 37, + reset: 0, + black: 30, + red: 31, + green: 32, + yellow: 33, + blue: 34, + magenta: 35, + cyan: 36, + white: 37, + bright_black: 30, + bright_red: 31, + bright_green: 32, + bright_yellow: 33, + bright_blue: 34, + bright_magenta: 35, + bright_cyan: 36, + bright_white: 37 } - def self.enable(io, force=false) + def self.enable(io, force = false) io.extend(self) @@color_force = force end @@ -32,8 +30,8 @@ def self.enable(io, force=false) def color? return true if @@color_force return false if Foreman.windows? - return false unless self.respond_to?(:isatty) - self.isatty && ENV["TERM"] + return false unless respond_to?(:isatty) + isatty && ENV["TERM"] end def color(name) @@ -41,11 +39,10 @@ def color(name) return "" unless ansi = ANSI[name.to_sym] "\e[#{ansi}m" end - end - FOREMAN_COLORS = %w( cyan yellow green magenta red blue bright_cyan bright_yellow - bright_green bright_magenta bright_red bright_blue ) + FOREMAN_COLORS = %w[ cyan yellow green magenta red blue bright_cyan bright_yellow + bright_green bright_magenta bright_red bright_blue ] def startup @colors = map_colors @@ -55,7 +52,7 @@ def startup def output(name, data) data.to_s.lines.map(&:chomp).each do |message| - output = "" + output = "" output += $stdout.color(@colors[name.split(".").first].to_sym) output += "#{Time.now.strftime("%H:%M:%S")} " if options[:timestamp] output += "#{pad_process_name(name)} | " @@ -71,13 +68,13 @@ def output(name, data) def shutdown end -private + private def name_padding @name_padding ||= begin index_padding = @names.values.map { |n| formation[n] }.max.to_s.length + 1 - name_padding = @names.values.map { |n| n.length + index_padding }.sort.last - [ 6, name_padding.to_i ].max + name_padding = @names.values.map { |n| n.length + index_padding }.sort.last + [6, name_padding.to_i].max end end @@ -101,5 +98,4 @@ def proctitle(title) def termtitle(title) printf("\033]0;#{title}\007") unless Foreman.windows? end - end diff --git a/lib/foreman/env.rb b/lib/foreman/env.rb index 378d2f7b..992937db 100644 --- a/lib/foreman/env.rb +++ b/lib/foreman/env.rb @@ -1,22 +1,20 @@ require "foreman" class Foreman::Env - attr_reader :entries def initialize(filename) - @entries = File.read(filename).gsub("\r\n","\n").split("\n").inject({}) do |ax, line| + @entries = File.read(filename).gsub("\r\n", "\n").split("\n").each_with_object({}) do |line, ax| if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/ key = $1 - case val = $2 + ax[key] = case val = $2 # Remove single quotes - when /\A'(.*)'\z/ then ax[key] = $1 + when /\A'(.*)'\z/ then $1 # Remove double quotes and unescape string preserving newline characters - when /\A"(.*)"\z/ then ax[key] = $1.gsub('\n', "\n").gsub(/\\(.)/, '\1') - else ax[key] = val + when /\A"(.*)"\z/ then $1.gsub('\n', "\n").gsub(/\\(.)/, '\1') + else val end end - ax end end @@ -25,5 +23,4 @@ def entries yield key, value end end - end diff --git a/lib/foreman/export.rb b/lib/foreman/export.rb index 04bf71c3..2599f240 100644 --- a/lib/foreman/export.rb +++ b/lib/foreman/export.rb @@ -8,21 +8,18 @@ module Foreman::Export class Exception < ::Exception; end def self.formatter(format) - begin - require "foreman/export/#{ format.tr('-', '_') }" - classy_format = classify(format) - formatter = constantize("Foreman::Export::#{ classy_format }") - rescue NameError => ex - error "Unknown export format: #{format} (no class Foreman::Export::#{ classy_format })." - rescue LoadError => ex - error "Unknown export format: #{format} (unable to load file 'foreman/export/#{ format.tr('-', '_') }')." - end + require "foreman/export/#{format.tr("-", "_")}" + classy_format = classify(format) + formatter = constantize("Foreman::Export::#{classy_format}") + rescue NameError => ex + error "Unknown export format: #{format} (no class Foreman::Export::#{classy_format})." + rescue LoadError => ex + error "Unknown export format: #{format} (unable to load file 'foreman/export/#{format.tr("-", "_")}')." end def self.error(message) raise Foreman::Export::Exception.new(message) end - end require "foreman/export/base" diff --git a/lib/foreman/export/base.rb b/lib/foreman/export/base.rb index 010529e6..e1533f73 100644 --- a/lib/foreman/export/base.rb +++ b/lib/foreman/export/base.rb @@ -4,7 +4,6 @@ require "shellwords" class Foreman::Export::Base - attr_reader :location attr_reader :engine attr_reader :options @@ -13,10 +12,10 @@ class Foreman::Export::Base # deprecated attr_reader :port - def initialize(location, engine, options={}) - @location = location - @engine = engine - @options = options.dup + def initialize(location, engine, options = {}) + @location = location + @engine = engine + @options = options.dup @formation = engine.formation # deprecated @@ -36,8 +35,8 @@ def @engine.procfile Foreman::Export::Base.warn_deprecation! @processes.map do |process| OpenStruct.new( - :name => @names[process], - :process => process + name: @names[process], + process: process ) end end @@ -45,7 +44,11 @@ def @engine.procfile def export error("Must specify a location") unless location - FileUtils.mkdir_p(location) rescue error("Could not create: #{location}") + begin + FileUtils.mkdir_p(location) + rescue + error("Could not create: #{location}") + end chown user, log chown user, run end @@ -66,7 +69,7 @@ def user options[:user] || app end -private ###################################################################### + private ###################################################################### def self.warn_deprecation! @@deprecation_warned ||= false @@ -83,7 +86,7 @@ def self.warn_deprecation! def chown user, dir FileUtils.chown user, nil, dir rescue - error("Could not chown #{dir} to #{user}") unless File.writable?(dir) || ! File.exist?(dir) + error("Could not chown #{dir} to #{user}") unless File.writable?(dir) || !File.exist?(dir) end def error(message) @@ -93,7 +96,7 @@ def error(message) def say(message) puts "[foreman export] %s" % message end - + def clean(filename) return unless File.exist?(filename) say "cleaning up: #{filename}" @@ -121,7 +124,7 @@ def old_export_template(exporter, file, template_root) end end - def export_template(name, file=nil, template_root=nil) + def export_template(name, file = nil, template_root = nil) if file && template_root old_export_template name, file, template_root else @@ -136,10 +139,10 @@ def export_template(name, file=nil, template_root=nil) def write_template(name, target, binding) compiled = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+ - ERB.new(export_template(name), trim_mode: '-').result(binding) - else - ERB.new(export_template(name), nil, '-').result(binding) - end + ERB.new(export_template(name), trim_mode: "-").result(binding) + else + ERB.new(export_template(name), trim_mode: "-").result(binding) + end write_file target, compiled end @@ -167,5 +170,4 @@ def write_file(filename, contents) file.puts contents end end - end diff --git a/lib/foreman/export/bluepill.rb b/lib/foreman/export/bluepill.rb index 1372b5a5..1dd9e7ab 100644 --- a/lib/foreman/export/bluepill.rb +++ b/lib/foreman/export/bluepill.rb @@ -2,11 +2,9 @@ require "foreman/export" class Foreman::Export::Bluepill < Foreman::Export::Base - def export super clean "#{location}/#{app}.pill" write_template "bluepill/master.pill.erb", "#{app}.pill", binding end - end diff --git a/lib/foreman/export/daemon.rb b/lib/foreman/export/daemon.rb index 40f623c6..9d43a659 100644 --- a/lib/foreman/export/daemon.rb +++ b/lib/foreman/export/daemon.rb @@ -2,7 +2,6 @@ require "foreman/export" class Foreman::Export::Daemon < Foreman::Export::Base - def export super @@ -20,7 +19,7 @@ def export port = engine.port_for(process, num) arguments = process.command.split(" ") executable = arguments.slice!(0) - arguments = arguments.size > 0 ? " -- #{arguments.join(' ')}" : "" + arguments = (arguments.size > 0) ? " -- #{arguments.join(" ")}" : "" write_template "daemon/process.conf.erb", "#{app}-#{name}-#{num}.conf", binding end end diff --git a/lib/foreman/export/inittab.rb b/lib/foreman/export/inittab.rb index d8b1f4db..284ea8ff 100644 --- a/lib/foreman/export/inittab.rb +++ b/lib/foreman/export/inittab.rb @@ -1,7 +1,6 @@ require "foreman/export" class Foreman::Export::Inittab < Foreman::Export::Base - def export error("Must specify a location") unless location @@ -38,5 +37,4 @@ def export File.open(location, "w") { |file| file.puts inittab } end end - end diff --git a/lib/foreman/export/launchd.rb b/lib/foreman/export/launchd.rb index b21a6756..14a2baf6 100644 --- a/lib/foreman/export/launchd.rb +++ b/lib/foreman/export/launchd.rb @@ -2,13 +2,12 @@ require "foreman/export" class Foreman::Export::Launchd < Foreman::Export::Base - def export super engine.each_process do |name, process| 1.upto(engine.formation[name]) do |num| port = engine.port_for(process, num) - command_args = process.command.split(/\s+/).map{|arg| + command_args = process.command.split(/\s+/).map { |arg| case arg when "$PORT" then port else arg @@ -18,5 +17,4 @@ def export end end end - end diff --git a/lib/foreman/export/runit.rb b/lib/foreman/export/runit.rb index ce22d0ed..a2adb432 100644 --- a/lib/foreman/export/runit.rb +++ b/lib/foreman/export/runit.rb @@ -2,7 +2,6 @@ require "foreman/export" class Foreman::Export::Runit < Foreman::Export::Base - ENV_VARIABLE_REGEX = /([a-zA-Z_]+[a-zA-Z0-9_]*)=(\S+)/ def export @@ -17,7 +16,7 @@ def export create_directory "#{process_directory}/log" write_template "runit/run.erb", "#{process_directory}/run", binding - chmod 0755, "#{process_directory}/run" + chmod 0o755, "#{process_directory}/run" port = engine.port_for(process, num) engine.env.merge("PORT" => port.to_s).each do |key, value| @@ -25,10 +24,8 @@ def export end write_template "runit/log/run.erb", "#{process_directory}/log/run", binding - chmod 0755, "#{process_directory}/log/run" + chmod 0o755, "#{process_directory}/log/run" end end - end - end diff --git a/lib/foreman/export/supervisord.rb b/lib/foreman/export/supervisord.rb index c6b1a872..4a07a521 100644 --- a/lib/foreman/export/supervisord.rb +++ b/lib/foreman/export/supervisord.rb @@ -2,7 +2,6 @@ require "foreman/export" class Foreman::Export::Supervisord < Foreman::Export::Base - def export super @@ -12,5 +11,4 @@ def export write_template "supervisord/app.conf.erb", "#{app}.conf", binding end - end diff --git a/lib/foreman/export/systemd.rb b/lib/foreman/export/systemd.rb index 9e39f5e4..74883730 100644 --- a/lib/foreman/export/systemd.rb +++ b/lib/foreman/export/systemd.rb @@ -2,7 +2,6 @@ require "foreman/export" class Foreman::Export::Systemd < Foreman::Export::Base - def export super diff --git a/lib/foreman/export/upstart.rb b/lib/foreman/export/upstart.rb index 20daf392..39ad586b 100644 --- a/lib/foreman/export/upstart.rb +++ b/lib/foreman/export/upstart.rb @@ -2,7 +2,6 @@ require "foreman/export" class Foreman::Export::Upstart < Foreman::Export::Base - def export super diff --git a/lib/foreman/helpers.rb b/lib/foreman/helpers.rb index 95b6e171..0fbd961b 100644 --- a/lib/foreman/helpers.rb +++ b/lib/foreman/helpers.rb @@ -5,7 +5,7 @@ module Foreman::Helpers # # classify('job-name') # => 'JobName' def classify(dashed_word) - dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join + dashed_word.split("-").each { |part| part[0] = part[0].chr.upcase }.join end # Tries to find a constant with the name specified in the argument string: # @@ -27,17 +27,17 @@ def classify(dashed_word) def constantize(camel_cased_word) camel_cased_word = camel_cased_word.to_s - names = camel_cased_word.split('::') + names = camel_cased_word.split("::") names.shift if names.empty? || names.first.empty? constant = Object names.each do |name| - args = Module.method(:const_get).arity != 1 ? [false] : [] + args = (Module.method(:const_get).arity != 1) ? [false] : [] - if constant.const_defined?(name, *args) - constant = constant.const_get(name) + constant = if constant.const_defined?(name, *args) + constant.const_get(name) else - constant = constant.const_missing(name) + constant.const_missing(name) end end constant diff --git a/lib/foreman/process.rb b/lib/foreman/process.rb index ee3de948..60f3912e 100644 --- a/lib/foreman/process.rb +++ b/lib/foreman/process.rb @@ -2,7 +2,6 @@ require "shellwords" class Foreman::Process - attr_reader :command attr_reader :env @@ -14,7 +13,7 @@ class Foreman::Process # @option options [String] :cwd (./) Change to this working directory before executing the process # @option options [Hash] :env ({}) Environment variables to set for this process # - def initialize(command, options={}) + def initialize(command, options = {}) @command = command @options = options.dup @@ -27,7 +26,7 @@ def initialize(command, options={}) # # @return [String] The expanded command # - def expanded_command(custom_env={}) + def expanded_command(custom_env = {}) env = @options[:env].merge(custom_env) expanded_command = command.dup env.each do |key, val| @@ -45,13 +44,13 @@ def expanded_command(custom_env={}) # # @returns [Fixnum] pid The +pid+ of the process # - def run(options={}) - env = @options[:env].merge(options[:env] || {}) + def run(options = {}) + env = @options[:env].merge(options[:env] || {}) output = options[:output] || $stdout runner = "#{Foreman.runner}".shellescape - + Dir.chdir(cwd) do - Process.spawn env, expanded_command(env), :out => output, :err => output + Process.spawn env, expanded_command(env), out: output, err: output end end @@ -62,7 +61,7 @@ def run(options={}) # @option options :env ({}) Environment variables to set for this execution # # @return Does not return - def exec(options={}) + def exec(options = {}) env = @options[:env].merge(options[:env] || {}) env.each { |k, v| ENV[k] = v } Dir.chdir(cwd) @@ -76,5 +75,4 @@ def exec(options={}) def cwd File.expand_path(@options[:cwd] || ".") end - end diff --git a/lib/foreman/procfile.rb b/lib/foreman/procfile.rb index 74887212..832219c8 100644 --- a/lib/foreman/procfile.rb +++ b/lib/foreman/procfile.rb @@ -9,14 +9,13 @@ # All other lines are ignored. # class Foreman::Procfile - EmptyFileError = Class.new(StandardError) # Initialize a Procfile # # @param [String] filename (nil) An optional filename to read from # - def initialize(filename=nil) + def initialize(filename = nil) @entries = [] load(filename) if filename end @@ -34,7 +33,7 @@ def entries # @param [String] name The name of the Procfile entry to retrieve # def [](name) - if entry = @entries.detect { |n,c| name == n } + if entry = @entries.detect { |n, c| name == n } entry.last end end @@ -54,7 +53,7 @@ def []=(name, command) # @param [String] name The name of the +Procfile+ entry to remove # def delete(name) - @entries.reject! { |n,c| name == n } + @entries.reject! { |n, c| name == n } end # Load a Procfile from a file @@ -74,8 +73,8 @@ def load(filename) # @param [String] filename Save the +Procfile+ to this file # def save(filename) - File.open(filename, 'w') do |file| - file.puts self.to_s + File.open(filename, "w") do |file| + file.puts to_s end end @@ -83,18 +82,17 @@ def save(filename) # def to_s @entries.map do |name, command| - [ name, command ].join(": ") + [name, command].join(": ") end.join("\n") end -private + private def parse(filename) - File.read(filename).gsub("\r\n","\n").split("\n").map do |line| + File.read(filename).gsub("\r\n", "\n").split("\n").map do |line| if line =~ /^([A-Za-z0-9_-]+):\s*(.+)$/ [$1, $2] end end.compact end - end diff --git a/lib/foreman/vendor/thor/lib/thor.rb b/lib/foreman/vendor/thor/lib/thor.rb deleted file mode 100644 index 4a2497e9..00000000 --- a/lib/foreman/vendor/thor/lib/thor.rb +++ /dev/null @@ -1,492 +0,0 @@ -require "set" -require "foreman/vendor/thor/lib/thor/base" - -class Foreman::Thor - class << self - # Allows for custom "Command" package naming. - # - # === Parameters - # name - # options - # - def package_name(name, _ = {}) - @package_name = name.nil? || name == "" ? nil : name - end - - # Sets the default command when thor is executed without an explicit command to be called. - # - # ==== Parameters - # meth:: name of the default command - # - def default_command(meth = nil) - if meth - @default_command = meth == :none ? "help" : meth.to_s - else - @default_command ||= from_superclass(:default_command, "help") - end - end - alias_method :default_task, :default_command - - # Registers another Foreman::Thor subclass as a command. - # - # ==== Parameters - # klass:: Foreman::Thor subclass to register - # command:: Subcommand name to use - # usage:: Short usage for the subcommand - # description:: Description for the subcommand - def register(klass, subcommand_name, usage, description, options = {}) - if klass <= Foreman::Thor::Group - desc usage, description, options - define_method(subcommand_name) { |*args| invoke(klass, args) } - else - desc usage, description, options - subcommand subcommand_name, klass - end - end - - # Defines the usage and the description of the next command. - # - # ==== Parameters - # usage - # description - # options - # - def desc(usage, description, options = {}) - if options[:for] - command = find_and_refresh_command(options[:for]) - command.usage = usage if usage - command.description = description if description - else - @usage = usage - @desc = description - @hide = options[:hide] || false - end - end - - # Defines the long description of the next command. - # - # ==== Parameters - # long description - # - def long_desc(long_description, options = {}) - if options[:for] - command = find_and_refresh_command(options[:for]) - command.long_description = long_description if long_description - else - @long_desc = long_description - end - end - - # Maps an input to a command. If you define: - # - # map "-T" => "list" - # - # Running: - # - # thor -T - # - # Will invoke the list command. - # - # ==== Parameters - # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command. - # - def map(mappings = nil) - @map ||= from_superclass(:map, {}) - - if mappings - mappings.each do |key, value| - if key.respond_to?(:each) - key.each { |subkey| @map[subkey] = value } - else - @map[key] = value - end - end - end - - @map - end - - # Declares the options for the next command to be declared. - # - # ==== Parameters - # Hash[Symbol => Object]:: The hash key is the name of the option and the value - # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric - # or :required (string). If you give a value, the type of the value is used. - # - def method_options(options = nil) - @method_options ||= {} - build_options(options, @method_options) if options - @method_options - end - - alias_method :options, :method_options - - # Adds an option to the set of method options. If :for is given as option, - # it allows you to change the options from a previous defined command. - # - # def previous_command - # # magic - # end - # - # method_option :foo => :bar, :for => :previous_command - # - # def next_command - # # magic - # end - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :default - Default value for this argument. It cannot be required and have default values. - # :aliases - Aliases for this option. - # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean. - # :banner - String to show on usage notes. - # :hide - If you want to hide this option from the help. - # - def method_option(name, options = {}) - scope = if options[:for] - find_and_refresh_command(options[:for]).options - else - method_options - end - - build_option(name, options, scope) - end - alias_method :option, :method_option - - def disable_class_options - @disable_class_options = true - end - - # Prints help information for the given command. - # - # ==== Parameters - # shell - # command_name - # - def command_help(shell, command_name) - meth = normalize_command_name(command_name) - command = all_commands[meth] - handle_no_command_error(meth) unless command - - shell.say "Usage:" - shell.say " #{banner(command)}" - shell.say - class_options_help(shell, nil => command.options.values) - if command.long_description - shell.say "Description:" - shell.print_wrapped(command.long_description, :indent => 2) - else - shell.say command.description - end - end - alias_method :task_help, :command_help - - # Prints help information for this class. - # - # ==== Parameters - # shell - # - def help(shell, subcommand = false) - list = printable_commands(true, subcommand) - Foreman::Thor::Util.thor_classes_in(self).each do |klass| - list += klass.printable_commands(false) - end - list.sort! { |a, b| a[0] <=> b[0] } - - if defined?(@package_name) && @package_name - shell.say "#{@package_name} commands:" - else - shell.say "Commands:" - end - - shell.print_table(list, :indent => 2, :truncate => true) - shell.say - class_options_help(shell) - end - - # Returns commands ready to be printed. - def printable_commands(all = true, subcommand = false) - (all ? all_commands : commands).map do |_, command| - next if command.hidden? - item = [] - item << banner(command, false, subcommand) - item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : "") - item - end.compact - end - alias_method :printable_tasks, :printable_commands - - def subcommands - @subcommands ||= from_superclass(:subcommands, []) - end - alias_method :subtasks, :subcommands - - def subcommand_classes - @subcommand_classes ||= {} - end - - def subcommand(subcommand, subcommand_class) - subcommands << subcommand.to_s - subcommand_class.subcommand_help subcommand - subcommand_classes[subcommand.to_s] = subcommand_class - - define_method(subcommand) do |*args| - args, opts = Foreman::Thor::Arguments.split(args) - invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}] - invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h") - invoke subcommand_class, *invoke_args - end - end - alias_method :subtask, :subcommand - - # Extend check unknown options to accept a hash of conditions. - # - # === Parameters - # options: A hash containing :only and/or :except keys - def check_unknown_options!(options = {}) - @check_unknown_options ||= {} - options.each do |key, value| - if value - @check_unknown_options[key] = Array(value) - else - @check_unknown_options.delete(key) - end - end - @check_unknown_options - end - - # Overwrite check_unknown_options? to take subcommands and options into account. - def check_unknown_options?(config) #:nodoc: - options = check_unknown_options - return false unless options - - command = config[:current_command] - return true unless command - - name = command.name - - if subcommands.include?(name) - false - elsif options[:except] - !options[:except].include?(name.to_sym) - elsif options[:only] - options[:only].include?(name.to_sym) - else - true - end - end - - # Stop parsing of options as soon as an unknown option or a regular - # argument is encountered. All remaining arguments are passed to the command. - # This is useful if you have a command that can receive arbitrary additional - # options, and where those additional options should not be handled by - # Foreman::Thor. - # - # ==== Example - # - # To better understand how this is useful, let's consider a command that calls - # an external command. A user may want to pass arbitrary options and - # arguments to that command. The command itself also accepts some options, - # which should be handled by Foreman::Thor. - # - # class_option "verbose", :type => :boolean - # stop_on_unknown_option! :exec - # check_unknown_options! :except => :exec - # - # desc "exec", "Run a shell command" - # def exec(*args) - # puts "diagnostic output" if options[:verbose] - # Kernel.exec(*args) - # end - # - # Here +exec+ can be called with +--verbose+ to get diagnostic output, - # e.g.: - # - # $ thor exec --verbose echo foo - # diagnostic output - # foo - # - # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead: - # - # $ thor exec echo --verbose foo - # --verbose foo - # - # ==== Parameters - # Symbol ...:: A list of commands that should be affected. - def stop_on_unknown_option!(*command_names) - stop_on_unknown_option.merge(command_names) - end - - def stop_on_unknown_option?(command) #:nodoc: - command && stop_on_unknown_option.include?(command.name.to_sym) - end - - protected - - def stop_on_unknown_option #:nodoc: - @stop_on_unknown_option ||= Set.new - end - - # The method responsible for dispatching given the args. - def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength - meth ||= retrieve_command_name(given_args) - command = all_commands[normalize_command_name(meth)] - - if !command && config[:invoked_via_subcommand] - # We're a subcommand and our first argument didn't match any of our - # commands. So we put it back and call our default command. - given_args.unshift(meth) - command = all_commands[normalize_command_name(default_command)] - end - - if command - args, opts = Foreman::Thor::Options.split(given_args) - if stop_on_unknown_option?(command) && !args.empty? - # given_args starts with a non-option, so we treat everything as - # ordinary arguments - args.concat opts - opts.clear - end - else - args = given_args - opts = nil - command = dynamic_command_class.new(meth) - end - - opts = given_opts || opts || [] - config[:current_command] = command - config[:command_options] = command.options - - instance = new(args, opts, config) - yield instance if block_given? - args = instance.args - trailing = args[Range.new(arguments.size, -1)] - instance.invoke_command(command, trailing || []) - end - - # The banner for this class. You can customize it if you are invoking the - # thor class by another ways which is not the Foreman::Thor::Runner. It receives - # the command that is going to be invoked and a boolean which indicates if - # the namespace should be displayed as arguments. - # - def banner(command, namespace = nil, subcommand = false) - "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}" - end - - def baseclass #:nodoc: - Foreman::Thor - end - - def dynamic_command_class #:nodoc: - Foreman::Thor::DynamicCommand - end - - def create_command(meth) #:nodoc: - @usage ||= nil - @desc ||= nil - @long_desc ||= nil - @disable_class_options ||= nil - - if @usage && @desc - base_class = @hide ? Foreman::Thor::HiddenCommand : Foreman::Thor::Command - commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options, @disable_class_options) - @usage, @desc, @long_desc, @method_options, @hide, @disable_class_options = nil - true - elsif all_commands[meth] || meth == "method_missing" - true - else - puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " \ - "Call desc if you want this method to be available as command or declare it inside a " \ - "no_commands{} block. Invoked from #{caller[1].inspect}." - false - end - end - alias_method :create_task, :create_command - - def initialize_added #:nodoc: - class_options.merge!(method_options) - @method_options = nil - end - - # Retrieve the command name from given args. - def retrieve_command_name(args) #:nodoc: - meth = args.first.to_s unless args.empty? - args.shift if meth && (map[meth] || meth !~ /^\-/) - end - alias_method :retrieve_task_name, :retrieve_command_name - - # receives a (possibly nil) command name and returns a name that is in - # the commands hash. In addition to normalizing aliases, this logic - # will determine if a shortened command is an unambiguous substring of - # a command or alias. - # - # +normalize_command_name+ also converts names like +animal-prison+ - # into +animal_prison+. - def normalize_command_name(meth) #:nodoc: - return default_command.to_s.tr("-", "_") unless meth - - possibilities = find_command_possibilities(meth) - raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]" if possibilities.size > 1 - - if possibilities.empty? - meth ||= default_command - elsif map[meth] - meth = map[meth] - else - meth = possibilities.first - end - - meth.to_s.tr("-", "_") # treat foo-bar as foo_bar - end - alias_method :normalize_task_name, :normalize_command_name - - # this is the logic that takes the command name passed in by the user - # and determines whether it is an unambiguous substrings of a command or - # alias name. - def find_command_possibilities(meth) - len = meth.to_s.length - possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort - unique_possibilities = possibilities.map { |k| map[k] || k }.uniq - - if possibilities.include?(meth) - [meth] - elsif unique_possibilities.size == 1 - unique_possibilities - else - possibilities - end - end - alias_method :find_task_possibilities, :find_command_possibilities - - def subcommand_help(cmd) - desc "help [COMMAND]", "Describe subcommands or one specific subcommand" - class_eval " - def help(command = nil, subcommand = true); super; end -" - end - alias_method :subtask_help, :subcommand_help - end - - include Foreman::Thor::Base - - map HELP_MAPPINGS => :help - - desc "help [COMMAND]", "Describe available commands or one specific command" - disable_class_options - def help(command = nil, subcommand = false) - if command - if self.class.subcommands.include? command - self.class.subcommand_classes[command].help(shell, true) - else - self.class.command_help(shell, command) - end - else - self.class.help(shell, subcommand) - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/actions.rb b/lib/foreman/vendor/thor/lib/thor/actions.rb deleted file mode 100644 index 09ddd50a..00000000 --- a/lib/foreman/vendor/thor/lib/thor/actions.rb +++ /dev/null @@ -1,318 +0,0 @@ -require "fileutils" -require "uri" -require "foreman/vendor/thor/lib/thor/core_ext/io_binary_read" -require "foreman/vendor/thor/lib/thor/actions/create_file" -require "foreman/vendor/thor/lib/thor/actions/create_link" -require "foreman/vendor/thor/lib/thor/actions/directory" -require "foreman/vendor/thor/lib/thor/actions/empty_directory" -require "foreman/vendor/thor/lib/thor/actions/file_manipulation" -require "foreman/vendor/thor/lib/thor/actions/inject_into_file" - -class Foreman::Thor - module Actions - attr_accessor :behavior - - def self.included(base) #:nodoc: - base.extend ClassMethods - end - - module ClassMethods - # Hold source paths for one Foreman::Thor instance. source_paths_for_search is the - # method responsible to gather source_paths from this current class, - # inherited paths and the source root. - # - def source_paths - @_source_paths ||= [] - end - - # Stores and return the source root for this class - def source_root(path = nil) - @_source_root = path if path - @_source_root ||= nil - end - - # Returns the source paths in the following order: - # - # 1) This class source paths - # 2) Source root - # 3) Parents source paths - # - def source_paths_for_search - paths = [] - paths += source_paths - paths << source_root if source_root - paths += from_superclass(:source_paths, []) - paths - end - - # Add runtime options that help actions execution. - # - def add_runtime_options! - class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime, - :desc => "Overwrite files that already exist" - - class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime, - :desc => "Run but do not make any changes" - - class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime, - :desc => "Suppress status output" - - class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime, - :desc => "Skip files that already exist" - end - end - - # Extends initializer to add more configuration options. - # - # ==== Configuration - # behavior:: The actions default behavior. Can be :invoke or :revoke. - # It also accepts :force, :skip and :pretend to set the behavior - # and the respective option. - # - # destination_root:: The root directory needed for some actions. - # - def initialize(args = [], options = {}, config = {}) - self.behavior = case config[:behavior].to_s - when "force", "skip" - _cleanup_options_and_set(options, config[:behavior]) - :invoke - when "revoke" - :revoke - else - :invoke - end - - super - self.destination_root = config[:destination_root] - end - - # Wraps an action object and call it accordingly to the thor class behavior. - # - def action(instance) #:nodoc: - if behavior == :revoke - instance.revoke! - else - instance.invoke! - end - end - - # Returns the root for this thor class (also aliased as destination root). - # - def destination_root - @destination_stack.last - end - - # Sets the root for this thor class. Relatives path are added to the - # directory where the script was invoked and expanded. - # - def destination_root=(root) - @destination_stack ||= [] - @destination_stack[0] = File.expand_path(root || "") - end - - # Returns the given path relative to the absolute root (ie, root where - # the script started). - # - def relative_to_original_destination_root(path, remove_dot = true) - path = path.dup - if path.gsub!(@destination_stack[0], ".") - remove_dot ? (path[2..-1] || "") : path - else - path - end - end - - # Holds source paths in instance so they can be manipulated. - # - def source_paths - @source_paths ||= self.class.source_paths_for_search - end - - # Receives a file or directory and search for it in the source paths. - # - def find_in_source_paths(file) - possible_files = [file, file + TEMPLATE_EXTNAME] - relative_root = relative_to_original_destination_root(destination_root, false) - - source_paths.each do |source| - possible_files.each do |f| - source_file = File.expand_path(f, File.join(source, relative_root)) - return source_file if File.exist?(source_file) - end - end - - message = "Could not find #{file.inspect} in any of your source paths. " - - unless self.class.source_root - message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. " - end - - message << if source_paths.empty? - "Currently you have no source paths." - else - "Your current source paths are: \n#{source_paths.join("\n")}" - end - - raise Error, message - end - - # Do something in the root or on a provided subfolder. If a relative path - # is given it's referenced from the current root. The full path is yielded - # to the block you provide. The path is set back to the previous path when - # the method exits. - # - # ==== Parameters - # dir:: the directory to move to. - # config:: give :verbose => true to log and use padding. - # - def inside(dir = "", config = {}, &block) - verbose = config.fetch(:verbose, false) - pretend = options[:pretend] - - say_status :inside, dir, verbose - shell.padding += 1 if verbose - @destination_stack.push File.expand_path(dir, destination_root) - - # If the directory doesnt exist and we're not pretending - if !File.exist?(destination_root) && !pretend - FileUtils.mkdir_p(destination_root) - end - - if pretend - # In pretend mode, just yield down to the block - block.arity == 1 ? yield(destination_root) : yield - else - FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield } - end - - @destination_stack.pop - shell.padding -= 1 if verbose - end - - # Goes to the root and execute the given block. - # - def in_root - inside(@destination_stack.first) { yield } - end - - # Loads an external file and execute it in the instance binding. - # - # ==== Parameters - # path:: The path to the file to execute. Can be a web address or - # a relative path from the source root. - # - # ==== Examples - # - # apply "http://gist.github.com/103208" - # - # apply "recipes/jquery.rb" - # - def apply(path, config = {}) - verbose = config.fetch(:verbose, true) - is_uri = path =~ %r{^https?\://} - path = find_in_source_paths(path) unless is_uri - - say_status :apply, path, verbose - shell.padding += 1 if verbose - - contents = if is_uri - open(path, "Accept" => "application/x-thor-template", &:read) - else - open(path, &:read) - end - - instance_eval(contents, path) - shell.padding -= 1 if verbose - end - - # Executes a command returning the contents of the command. - # - # ==== Parameters - # command:: the command to be executed. - # config:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with - # to append an executable to command execution. - # - # ==== Example - # - # inside('vendor') do - # run('ln -s ~/edge rails') - # end - # - def run(command, config = {}) - return unless behavior == :invoke - - destination = relative_to_original_destination_root(destination_root, false) - desc = "#{command} from #{destination.inspect}" - - if config[:with] - desc = "#{File.basename(config[:with].to_s)} #{desc}" - command = "#{config[:with]} #{command}" - end - - say_status :run, desc, config.fetch(:verbose, true) - - !options[:pretend] && config[:capture] ? `#{command}` : system(command.to_s) - end - - # Executes a ruby script (taking into account WIN32 platform quirks). - # - # ==== Parameters - # command:: the command to be executed. - # config:: give :verbose => false to not log the status. - # - def run_ruby_script(command, config = {}) - return unless behavior == :invoke - run command, config.merge(:with => Foreman::Thor::Util.ruby_command) - end - - # Run a thor command. A hash of options can be given and it's converted to - # switches. - # - # ==== Parameters - # command:: the command to be invoked - # args:: arguments to the command - # config:: give :verbose => false to not log the status, :capture => true to hide to output. - # Other options are given as parameter to Foreman::Thor. - # - # - # ==== Examples - # - # thor :install, "http://gist.github.com/103208" - # #=> thor install http://gist.github.com/103208 - # - # thor :list, :all => true, :substring => 'rails' - # #=> thor list --all --substring=rails - # - def thor(command, *args) - config = args.last.is_a?(Hash) ? args.pop : {} - verbose = config.key?(:verbose) ? config.delete(:verbose) : true - pretend = config.key?(:pretend) ? config.delete(:pretend) : false - capture = config.key?(:capture) ? config.delete(:capture) : false - - args.unshift(command) - args.push Foreman::Thor::Options.to_switches(config) - command = args.join(" ").strip - - run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture - end - - protected - - # Allow current root to be shared between invocations. - # - def _shared_configuration #:nodoc: - super.merge!(:destination_root => destination_root) - end - - def _cleanup_options_and_set(options, key) #:nodoc: - case options - when Array - %w(--force -f --skip -s).each { |i| options.delete(i) } - options << "--#{key}" - when Hash - [:force, :skip, "force", "skip"].each { |i| options.delete(i) } - options.merge!(key => true) - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/actions/create_file.rb b/lib/foreman/vendor/thor/lib/thor/actions/create_file.rb deleted file mode 100644 index 592437ef..00000000 --- a/lib/foreman/vendor/thor/lib/thor/actions/create_file.rb +++ /dev/null @@ -1,103 +0,0 @@ -require "foreman/vendor/thor/lib/thor/actions/empty_directory" - -class Foreman::Thor - module Actions - # Create a new file relative to the destination root with the given data, - # which is the return value of a block or a data string. - # - # ==== Parameters - # destination:: the relative path to the destination root. - # data:: the data to append to the file. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # create_file "lib/fun_party.rb" do - # hostname = ask("What is the virtual hostname I should use?") - # "vhost.name = #{hostname}" - # end - # - # create_file "config/apache.conf", "your apache config" - # - def create_file(destination, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - data = args.first - action CreateFile.new(self, destination, block || data.to_s, config) - end - alias_method :add_file, :create_file - - # CreateFile is a subset of Template, which instead of rendering a file with - # ERB, it gets the content from the user. - # - class CreateFile < EmptyDirectory #:nodoc: - attr_reader :data - - def initialize(base, destination, data, config = {}) - @data = data - super(base, destination, config) - end - - # Checks if the content of the file at the destination is identical to the rendered result. - # - # ==== Returns - # Boolean:: true if it is identical, false otherwise. - # - def identical? - exists? && File.binread(destination) == render - end - - # Holds the content to be added to the file. - # - def render - @render ||= if data.is_a?(Proc) - data.call - else - data - end - end - - def invoke! - invoke_with_conflict_check do - FileUtils.mkdir_p(File.dirname(destination)) - File.open(destination, "wb") { |f| f.write render } - end - given_destination - end - - protected - - # Now on conflict we check if the file is identical or not. - # - def on_conflict_behavior(&block) - if identical? - say_status :identical, :blue - else - options = base.options.merge(config) - force_or_skip_or_conflict(options[:force], options[:skip], &block) - end - end - - # If force is true, run the action, otherwise check if it's not being - # skipped. If both are false, show the file_collision menu, if the menu - # returns true, force it, otherwise skip. - # - def force_or_skip_or_conflict(force, skip, &block) - if force - say_status :force, :yellow - yield unless pretend? - elsif skip - say_status :skip, :yellow - else - say_status :conflict, :red - force_or_skip_or_conflict(force_on_collision?, true, &block) - end - end - - # Shows the file collision menu to the user and gets the result. - # - def force_on_collision? - base.shell.file_collision(destination) { render } - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/actions/create_link.rb b/lib/foreman/vendor/thor/lib/thor/actions/create_link.rb deleted file mode 100644 index cdeb8027..00000000 --- a/lib/foreman/vendor/thor/lib/thor/actions/create_link.rb +++ /dev/null @@ -1,59 +0,0 @@ -require "foreman/vendor/thor/lib/thor/actions/create_file" - -class Foreman::Thor - module Actions - # Create a new file relative to the destination root from the given source. - # - # ==== Parameters - # destination:: the relative path to the destination root. - # source:: the relative path to the source root. - # config:: give :verbose => false to not log the status. - # :: give :symbolic => false for hard link. - # - # ==== Examples - # - # create_link "config/apache.conf", "/etc/apache.conf" - # - def create_link(destination, *args) - config = args.last.is_a?(Hash) ? args.pop : {} - source = args.first - action CreateLink.new(self, destination, source, config) - end - alias_method :add_link, :create_link - - # CreateLink is a subset of CreateFile, which instead of taking a block of - # data, just takes a source string from the user. - # - class CreateLink < CreateFile #:nodoc: - attr_reader :data - - # Checks if the content of the file at the destination is identical to the rendered result. - # - # ==== Returns - # Boolean:: true if it is identical, false otherwise. - # - def identical? - exists? && File.identical?(render, destination) - end - - def invoke! - invoke_with_conflict_check do - FileUtils.mkdir_p(File.dirname(destination)) - # Create a symlink by default - config[:symbolic] = true if config[:symbolic].nil? - File.unlink(destination) if exists? - if config[:symbolic] - File.symlink(render, destination) - else - File.link(render, destination) - end - end - given_destination - end - - def exists? - super || File.symlink?(destination) - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/actions/directory.rb b/lib/foreman/vendor/thor/lib/thor/actions/directory.rb deleted file mode 100644 index 9b5297e4..00000000 --- a/lib/foreman/vendor/thor/lib/thor/actions/directory.rb +++ /dev/null @@ -1,118 +0,0 @@ -require "foreman/vendor/thor/lib/thor/actions/empty_directory" - -class Foreman::Thor - module Actions - # Copies recursively the files from source directory to root directory. - # If any of the files finishes with .tt, it's considered to be a template - # and is placed in the destination without the extension .tt. If any - # empty directory is found, it's copied and all .empty_directory files are - # ignored. If any file name is wrapped within % signs, the text within - # the % signs will be executed as a method and replaced with the returned - # value. Let's suppose a doc directory with the following files: - # - # doc/ - # components/.empty_directory - # README - # rdoc.rb.tt - # %app_name%.rb - # - # When invoked as: - # - # directory "doc" - # - # It will create a doc directory in the destination with the following - # files (assuming that the `app_name` method returns the value "blog"): - # - # doc/ - # components/ - # README - # rdoc.rb - # blog.rb - # - # Encoded path note: Since Foreman::Thor internals use Object#respond_to? to check if it can - # expand %something%, this `something` should be a public method in the class calling - # #directory. If a method is private, Foreman::Thor stack raises PrivateMethodEncodedError. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # If :recursive => false, does not look for paths recursively. - # If :mode => :preserve, preserve the file mode from the source. - # If :exclude_pattern => /regexp/, prevents copying files that match that regexp. - # - # ==== Examples - # - # directory "doc" - # directory "doc", "docs", :recursive => false - # - def directory(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source - action Directory.new(self, source, destination || source, config, &block) - end - - class Directory < EmptyDirectory #:nodoc: - attr_reader :source - - def initialize(base, source, destination = nil, config = {}, &block) - @source = File.expand_path(base.find_in_source_paths(source.to_s)) - @block = block - super(base, destination, {:recursive => true}.merge(config)) - end - - def invoke! - base.empty_directory given_destination, config - execute! - end - - def revoke! - execute! - end - - protected - - def execute! - lookup = Util.escape_globs(source) - lookup = config[:recursive] ? File.join(lookup, "**") : lookup - lookup = file_level_lookup(lookup) - - files(lookup).sort.each do |file_source| - next if File.directory?(file_source) - next if config[:exclude_pattern] && file_source.match(config[:exclude_pattern]) - file_destination = File.join(given_destination, file_source.gsub(source, ".")) - file_destination.gsub!("/./", "/") - - case file_source - when /\.empty_directory$/ - dirname = File.dirname(file_destination).gsub(%r{/\.$}, "") - next if dirname == given_destination - base.empty_directory(dirname, config) - when /#{TEMPLATE_EXTNAME}$/ - base.template(file_source, file_destination[0..-4], config, &@block) - else - base.copy_file(file_source, file_destination, config, &@block) - end - end - end - - if RUBY_VERSION < "2.0" - def file_level_lookup(previous_lookup) - File.join(previous_lookup, "{*,.[a-z]*}") - end - - def files(lookup) - Dir[lookup] - end - else - def file_level_lookup(previous_lookup) - File.join(previous_lookup, "*") - end - - def files(lookup) - Dir.glob(lookup, File::FNM_DOTMATCH) - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/actions/empty_directory.rb b/lib/foreman/vendor/thor/lib/thor/actions/empty_directory.rb deleted file mode 100644 index c231b177..00000000 --- a/lib/foreman/vendor/thor/lib/thor/actions/empty_directory.rb +++ /dev/null @@ -1,135 +0,0 @@ -class Foreman::Thor - module Actions - # Creates an empty directory. - # - # ==== Parameters - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # empty_directory "doc" - # - def empty_directory(destination, config = {}) - action EmptyDirectory.new(self, destination, config) - end - - # Class which holds create directory logic. This is the base class for - # other actions like create_file and directory. - # - # This implementation is based in Templater actions, created by Jonas Nicklas - # and Michael S. Klishin under MIT LICENSE. - # - class EmptyDirectory #:nodoc: - attr_reader :base, :destination, :given_destination, :relative_destination, :config - - # Initializes given the source and destination. - # - # ==== Parameters - # base:: A Foreman::Thor::Base instance - # source:: Relative path to the source of this file - # destination:: Relative path to the destination of this file - # config:: give :verbose => false to not log the status. - # - def initialize(base, destination, config = {}) - @base = base - @config = {:verbose => true}.merge(config) - self.destination = destination - end - - # Checks if the destination file already exists. - # - # ==== Returns - # Boolean:: true if the file exists, false otherwise. - # - def exists? - ::File.exist?(destination) - end - - def invoke! - invoke_with_conflict_check do - ::FileUtils.mkdir_p(destination) - end - end - - def revoke! - say_status :remove, :red - ::FileUtils.rm_rf(destination) if !pretend? && exists? - given_destination - end - - protected - - # Shortcut for pretend. - # - def pretend? - base.options[:pretend] - end - - # Sets the absolute destination value from a relative destination value. - # It also stores the given and relative destination. Let's suppose our - # script is being executed on "dest", it sets the destination root to - # "dest". The destination, given_destination and relative_destination - # are related in the following way: - # - # inside "bar" do - # empty_directory "baz" - # end - # - # destination #=> dest/bar/baz - # relative_destination #=> bar/baz - # given_destination #=> baz - # - def destination=(destination) - return unless destination - @given_destination = convert_encoded_instructions(destination.to_s) - @destination = ::File.expand_path(@given_destination, base.destination_root) - @relative_destination = base.relative_to_original_destination_root(@destination) - end - - # Filenames in the encoded form are converted. If you have a file: - # - # %file_name%.rb - # - # It calls #file_name from the base and replaces %-string with the - # return value (should be String) of #file_name: - # - # user.rb - # - # The method referenced can be either public or private. - # - def convert_encoded_instructions(filename) - filename.gsub(/%(.*?)%/) do |initial_string| - method = $1.strip - base.respond_to?(method, true) ? base.send(method) : initial_string - end - end - - # Receives a hash of options and just execute the block if some - # conditions are met. - # - def invoke_with_conflict_check(&block) - if exists? - on_conflict_behavior(&block) - else - say_status :create, :green - yield unless pretend? - end - - destination - end - - # What to do when the destination file already exists. - # - def on_conflict_behavior - say_status :exist, :blue - end - - # Shortcut to say_status shell method. - # - def say_status(status, color) - base.shell.say_status status, relative_destination, color if config[:verbose] - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/foreman/vendor/thor/lib/thor/actions/file_manipulation.rb deleted file mode 100644 index 2716e5b2..00000000 --- a/lib/foreman/vendor/thor/lib/thor/actions/file_manipulation.rb +++ /dev/null @@ -1,327 +0,0 @@ -require "erb" -require "open-uri" - -class Foreman::Thor - module Actions - # Copies the file from the relative source to the relative destination. If - # the destination is not given it's assumed to be equal to the source. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status, and - # :mode => :preserve, to preserve the file mode from the source. - - # - # ==== Examples - # - # copy_file "README", "doc/README" - # - # copy_file "doc/README" - # - def copy_file(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source - source = File.expand_path(find_in_source_paths(source.to_s)) - - create_file destination, nil, config do - content = File.binread(source) - content = yield(content) if block - content - end - if config[:mode] == :preserve - mode = File.stat(source).mode - chmod(destination, mode, config) - end - end - - # Links the file from the relative source to the relative destination. If - # the destination is not given it's assumed to be equal to the source. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # link_file "README", "doc/README" - # - # link_file "doc/README" - # - def link_file(source, *args) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source - source = File.expand_path(find_in_source_paths(source.to_s)) - - create_link destination, source, config - end - - # Gets the content at the given address and places it at the given relative - # destination. If a block is given instead of destination, the content of - # the url is yielded and used as location. - # - # ==== Parameters - # source:: the address of the given content. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # get "http://gist.github.com/103208", "doc/README" - # - # get "http://gist.github.com/103208" do |content| - # content.split("\n").first - # end - # - def get(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first - - source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ %r{^https?\://} - render = open(source) { |input| input.binmode.read } - - destination ||= if block_given? - block.arity == 1 ? yield(render) : yield - else - File.basename(source) - end - - create_file destination, render, config - end - - # Gets an ERB template at the relative source, executes it and makes a copy - # at the relative destination. If the destination is not given it's assumed - # to be equal to the source removing .tt from the filename. - # - # ==== Parameters - # source:: the relative path to the source root. - # destination:: the relative path to the destination root. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # template "README", "doc/README" - # - # template "doc/README" - # - def template(source, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "") - - source = File.expand_path(find_in_source_paths(source.to_s)) - context = config.delete(:context) || instance_eval("binding") - - create_file destination, nil, config do - content = CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context) - content = yield(content) if block - content - end - end - - # Changes the mode of the given file or directory. - # - # ==== Parameters - # mode:: the file mode - # path:: the name of the file to change mode - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # chmod "script/server", 0755 - # - def chmod(path, mode, config = {}) - return unless behavior == :invoke - path = File.expand_path(path, destination_root) - say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true) - FileUtils.chmod_R(mode, path) unless options[:pretend] - end - - # Prepend text to a file. Since it depends on insert_into_file, it's reversible. - # - # ==== Parameters - # path:: path of the file to be changed - # data:: the data to prepend to the file, can be also given as a block. - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"' - # - # prepend_to_file 'config/environments/test.rb' do - # 'config.gem "rspec"' - # end - # - def prepend_to_file(path, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - config[:after] = /\A/ - insert_into_file(path, *(args << config), &block) - end - alias_method :prepend_file, :prepend_to_file - - # Append text to a file. Since it depends on insert_into_file, it's reversible. - # - # ==== Parameters - # path:: path of the file to be changed - # data:: the data to append to the file, can be also given as a block. - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # append_to_file 'config/environments/test.rb', 'config.gem "rspec"' - # - # append_to_file 'config/environments/test.rb' do - # 'config.gem "rspec"' - # end - # - def append_to_file(path, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - config[:before] = /\z/ - insert_into_file(path, *(args << config), &block) - end - alias_method :append_file, :append_to_file - - # Injects text right after the class definition. Since it depends on - # insert_into_file, it's reversible. - # - # ==== Parameters - # path:: path of the file to be changed - # klass:: the class to be manipulated - # data:: the data to append to the class, can be also given as a block. - # config:: give :verbose => false to not log the status. - # - # ==== Examples - # - # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n" - # - # inject_into_class "app/controllers/application_controller.rb", ApplicationController do - # " filter_parameter :password\n" - # end - # - def inject_into_class(path, klass, *args, &block) - config = args.last.is_a?(Hash) ? args.pop : {} - config[:after] = /class #{klass}\n|class #{klass} .*\n/ - insert_into_file(path, *(args << config), &block) - end - - # Run a regular expression replacement on a file. - # - # ==== Parameters - # path:: path of the file to be changed - # flag:: the regexp or string to be replaced - # replacement:: the replacement, can be also given as a block - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1' - # - # gsub_file 'README', /rake/, :green do |match| - # match << " no more. Use thor!" - # end - # - def gsub_file(path, flag, *args, &block) - return unless behavior == :invoke - config = args.last.is_a?(Hash) ? args.pop : {} - - path = File.expand_path(path, destination_root) - say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true) - - unless options[:pretend] - content = File.binread(path) - content.gsub!(flag, *args, &block) - File.open(path, "wb") { |file| file.write(content) } - end - end - - # Uncomment all lines matching a given regex. It will leave the space - # which existed before the comment hash in tact but will remove any spacing - # between the comment hash and the beginning of the line. - # - # ==== Parameters - # path:: path of the file to be changed - # flag:: the regexp or string used to decide which lines to uncomment - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # uncomment_lines 'config/initializers/session_store.rb', /active_record/ - # - def uncomment_lines(path, flag, *args) - flag = flag.respond_to?(:source) ? flag.source : flag - - gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args) - end - - # Comment all lines matching a given regex. It will leave the space - # which existed before the beginning of the line in tact and will insert - # a single space after the comment hash. - # - # ==== Parameters - # path:: path of the file to be changed - # flag:: the regexp or string used to decide which lines to comment - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # comment_lines 'config/initializers/session_store.rb', /cookie_store/ - # - def comment_lines(path, flag, *args) - flag = flag.respond_to?(:source) ? flag.source : flag - - gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args) - end - - # Removes a file at the given location. - # - # ==== Parameters - # path:: path of the file to be changed - # config:: give :verbose => false to not log the status. - # - # ==== Example - # - # remove_file 'README' - # remove_file 'app/controllers/application_controller.rb' - # - def remove_file(path, config = {}) - return unless behavior == :invoke - path = File.expand_path(path, destination_root) - - say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true) - ::FileUtils.rm_rf(path) if !options[:pretend] && File.exist?(path) - end - alias_method :remove_dir, :remove_file - - attr_accessor :output_buffer - private :output_buffer, :output_buffer= - - private - - def concat(string) - @output_buffer.concat(string) - end - - def capture(*args) - with_output_buffer { yield(*args) } - end - - def with_output_buffer(buf = "") #:nodoc: - self.output_buffer, old_buffer = buf, output_buffer - yield - output_buffer - ensure - self.output_buffer = old_buffer - end - - # Foreman::Thor::Actions#capture depends on what kind of buffer is used in ERB. - # Thus CapturableERB fixes ERB to use String buffer. - class CapturableERB < ERB - def set_eoutvar(compiler, eoutvar = "_erbout") - compiler.put_cmd = "#{eoutvar}.concat" - compiler.insert_cmd = "#{eoutvar}.concat" - compiler.pre_cmd = ["#{eoutvar} = ''"] - compiler.post_cmd = [eoutvar] - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/actions/inject_into_file.rb b/lib/foreman/vendor/thor/lib/thor/actions/inject_into_file.rb deleted file mode 100644 index 749f8410..00000000 --- a/lib/foreman/vendor/thor/lib/thor/actions/inject_into_file.rb +++ /dev/null @@ -1,103 +0,0 @@ -require "foreman/vendor/thor/lib/thor/actions/empty_directory" - -class Foreman::Thor - module Actions - # Injects the given content into a file. Different from gsub_file, this - # method is reversible. - # - # ==== Parameters - # destination:: Relative path to the destination root - # data:: Data to add to the file. Can be given as a block. - # config:: give :verbose => false to not log the status and the flag - # for injection (:after or :before) or :force => true for - # insert two or more times the same content. - # - # ==== Examples - # - # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n" - # - # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do - # gems = ask "Which gems would you like to add?" - # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n") - # end - # - def insert_into_file(destination, *args, &block) - data = block_given? ? block : args.shift - config = args.shift - action InjectIntoFile.new(self, destination, data, config) - end - alias_method :inject_into_file, :insert_into_file - - class InjectIntoFile < EmptyDirectory #:nodoc: - attr_reader :replacement, :flag, :behavior - - def initialize(base, destination, data, config) - super(base, destination, {:verbose => true}.merge(config)) - - @behavior, @flag = if @config.key?(:after) - [:after, @config.delete(:after)] - else - [:before, @config.delete(:before)] - end - - @replacement = data.is_a?(Proc) ? data.call : data - @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp) - end - - def invoke! - say_status :invoke - - content = if @behavior == :after - '\0' + replacement - else - replacement + '\0' - end - - replace!(/#{flag}/, content, config[:force]) - end - - def revoke! - say_status :revoke - - regexp = if @behavior == :after - content = '\1\2' - /(#{flag})(.*)(#{Regexp.escape(replacement)})/m - else - content = '\2\3' - /(#{Regexp.escape(replacement)})(.*)(#{flag})/m - end - - replace!(regexp, content, true) - end - - protected - - def say_status(behavior) - status = if behavior == :invoke - if flag == /\A/ - :prepend - elsif flag == /\z/ - :append - else - :insert - end - else - :subtract - end - - super(status, config[:verbose]) - end - - # Adds the content to the file. - # - def replace!(regexp, string, force) - return if base.options[:pretend] - content = File.binread(destination) - if force || !content.include?(replacement) - content.gsub!(regexp, string) - File.open(destination, "wb") { |file| file.write(content) } - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/base.rb b/lib/foreman/vendor/thor/lib/thor/base.rb deleted file mode 100644 index 56b72bd5..00000000 --- a/lib/foreman/vendor/thor/lib/thor/base.rb +++ /dev/null @@ -1,656 +0,0 @@ -require "foreman/vendor/thor/lib/thor/command" -require "foreman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access" -require "foreman/vendor/thor/lib/thor/core_ext/ordered_hash" -require "foreman/vendor/thor/lib/thor/error" -require "foreman/vendor/thor/lib/thor/invocation" -require "foreman/vendor/thor/lib/thor/parser" -require "foreman/vendor/thor/lib/thor/shell" -require "foreman/vendor/thor/lib/thor/line_editor" -require "foreman/vendor/thor/lib/thor/util" - -class Foreman::Thor - autoload :Actions, "foreman/vendor/thor/lib/thor/actions" - autoload :RakeCompat, "foreman/vendor/thor/lib/thor/rake_compat" - autoload :Group, "foreman/vendor/thor/lib/thor/group" - - # Shortcuts for help. - HELP_MAPPINGS = %w(-h -? --help -D) - - # Foreman::Thor methods that should not be overwritten by the user. - THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root - action add_file create_file in_root inside run run_ruby_script) - - TEMPLATE_EXTNAME = ".tt" - - module Base - attr_accessor :options, :parent_options, :args - - # It receives arguments in an Array and two hashes, one for options and - # other for configuration. - # - # Notice that it does not check if all required arguments were supplied. - # It should be done by the parser. - # - # ==== Parameters - # args:: An array of objects. The objects are applied to their - # respective accessors declared with argument. - # - # options:: An options hash that will be available as self.options. - # The hash given is converted to a hash with indifferent - # access, magic predicates (options.skip?) and then frozen. - # - # config:: Configuration for this Foreman::Thor class. - # - def initialize(args = [], local_options = {}, config = {}) - parse_options = config[:current_command] && config[:current_command].disable_class_options ? {} : self.class.class_options - - # The start method splits inbound arguments at the first argument - # that looks like an option (starts with - or --). It then calls - # new, passing in the two halves of the arguments Array as the - # first two parameters. - - command_options = config.delete(:command_options) # hook for start - parse_options = parse_options.merge(command_options) if command_options - if local_options.is_a?(Array) - array_options = local_options - hash_options = {} - else - # Handle the case where the class was explicitly instantiated - # with pre-parsed options. - array_options = [] - hash_options = local_options - end - - # Let Foreman::Thor::Options parse the options first, so it can remove - # declared options from the array. This will leave us with - # a list of arguments that weren't declared. - stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command] - opts = Foreman::Thor::Options.new(parse_options, hash_options, stop_on_unknown) - self.options = opts.parse(array_options) - self.options = config[:class_options].merge(options) if config[:class_options] - - # If unknown options are disallowed, make sure that none of the - # remaining arguments looks like an option. - opts.check_unknown! if self.class.check_unknown_options?(config) - - # Add the remaining arguments from the options parser to the - # arguments passed in to initialize. Then remove any positional - # arguments declared using #argument (this is primarily used - # by Foreman::Thor::Group). Tis will leave us with the remaining - # positional arguments. - to_parse = args - to_parse += opts.remaining unless self.class.strict_args_position?(config) - - thor_args = Foreman::Thor::Arguments.new(self.class.arguments) - thor_args.parse(to_parse).each { |k, v| __send__("#{k}=", v) } - @args = thor_args.remaining - end - - class << self - def included(base) #:nodoc: - base.extend ClassMethods - base.send :include, Invocation - base.send :include, Shell - end - - # Returns the classes that inherits from Foreman::Thor or Foreman::Thor::Group. - # - # ==== Returns - # Array[Class] - # - def subclasses - @subclasses ||= [] - end - - # Returns the files where the subclasses are kept. - # - # ==== Returns - # Hash[path => Class] - # - def subclass_files - @subclass_files ||= Hash.new { |h, k| h[k] = [] } - end - - # Whenever a class inherits from Foreman::Thor or Foreman::Thor::Group, we should track the - # class and the file on Foreman::Thor::Base. This is the method responsable for it. - # - def register_klass_file(klass) #:nodoc: - file = caller[1].match(/(.*):\d+/)[1] - Foreman::Thor::Base.subclasses << klass unless Foreman::Thor::Base.subclasses.include?(klass) - - file_subclasses = Foreman::Thor::Base.subclass_files[File.expand_path(file)] - file_subclasses << klass unless file_subclasses.include?(klass) - end - end - - module ClassMethods - def attr_reader(*) #:nodoc: - no_commands { super } - end - - def attr_writer(*) #:nodoc: - no_commands { super } - end - - def attr_accessor(*) #:nodoc: - no_commands { super } - end - - # If you want to raise an error for unknown options, call check_unknown_options! - # This is disabled by default to allow dynamic invocations. - def check_unknown_options! - @check_unknown_options = true - end - - def check_unknown_options #:nodoc: - @check_unknown_options ||= from_superclass(:check_unknown_options, false) - end - - def check_unknown_options?(config) #:nodoc: - !!check_unknown_options - end - - # If true, option parsing is suspended as soon as an unknown option or a - # regular argument is encountered. All remaining arguments are passed to - # the command as regular arguments. - def stop_on_unknown_option?(command_name) #:nodoc: - false - end - - # If you want only strict string args (useful when cascading thor classes), - # call strict_args_position! This is disabled by default to allow dynamic - # invocations. - def strict_args_position! - @strict_args_position = true - end - - def strict_args_position #:nodoc: - @strict_args_position ||= from_superclass(:strict_args_position, false) - end - - def strict_args_position?(config) #:nodoc: - !!strict_args_position - end - - # Adds an argument to the class and creates an attr_accessor for it. - # - # Arguments are different from options in several aspects. The first one - # is how they are parsed from the command line, arguments are retrieved - # from position: - # - # thor command NAME - # - # Instead of: - # - # thor command --name=NAME - # - # Besides, arguments are used inside your code as an accessor (self.argument), - # while options are all kept in a hash (self.options). - # - # Finally, arguments cannot have type :default or :boolean but can be - # optional (supplying :optional => :true or :required => false), although - # you cannot have a required argument after a non-required argument. If you - # try it, an error is raised. - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc - Description for the argument. - # :required - If the argument is required or not. - # :optional - If the argument is optional or not. - # :type - The type of the argument, can be :string, :hash, :array, :numeric. - # :default - Default value for this argument. It cannot be required and have default values. - # :banner - String to show on usage notes. - # - # ==== Errors - # ArgumentError:: Raised if you supply a required argument after a non required one. - # - def argument(name, options = {}) - is_thor_reserved_word?(name, :argument) - no_commands { attr_accessor name } - - required = if options.key?(:optional) - !options[:optional] - elsif options.key?(:required) - options[:required] - else - options[:default].nil? - end - - remove_argument name - - if required - arguments.each do |argument| - next if argument.required? - raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " \ - "the non-required argument #{argument.human_name.inspect}." - end - end - - options[:required] = required - - arguments << Foreman::Thor::Argument.new(name, options) - end - - # Returns this class arguments, looking up in the ancestors chain. - # - # ==== Returns - # Array[Foreman::Thor::Argument] - # - def arguments - @arguments ||= from_superclass(:arguments, []) - end - - # Adds a bunch of options to the set of class options. - # - # class_options :foo => false, :bar => :required, :baz => :string - # - # If you prefer more detailed declaration, check class_option. - # - # ==== Parameters - # Hash[Symbol => Object] - # - def class_options(options = nil) - @class_options ||= from_superclass(:class_options, {}) - build_options(options, @class_options) if options - @class_options - end - - # Adds an option to the set of class options - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described below. - # - # ==== Options - # :desc:: -- Description for the argument. - # :required:: -- If the argument is required or not. - # :default:: -- Default value for this argument. - # :group:: -- The group for this options. Use by class options to output options in different levels. - # :aliases:: -- Aliases for this option. Note: Foreman::Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead. - # :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean. - # :banner:: -- String to show on usage notes. - # :hide:: -- If you want to hide this option from the help. - # - def class_option(name, options = {}) - build_option(name, options, class_options) - end - - # Removes a previous defined argument. If :undefine is given, undefine - # accessors as well. - # - # ==== Parameters - # names:: Arguments to be removed - # - # ==== Examples - # - # remove_argument :foo - # remove_argument :foo, :bar, :baz, :undefine => true - # - def remove_argument(*names) - options = names.last.is_a?(Hash) ? names.pop : {} - - names.each do |name| - arguments.delete_if { |a| a.name == name.to_s } - undef_method name, "#{name}=" if options[:undefine] - end - end - - # Removes a previous defined class option. - # - # ==== Parameters - # names:: Class options to be removed - # - # ==== Examples - # - # remove_class_option :foo - # remove_class_option :foo, :bar, :baz - # - def remove_class_option(*names) - names.each do |name| - class_options.delete(name) - end - end - - # Defines the group. This is used when thor list is invoked so you can specify - # that only commands from a pre-defined group will be shown. Defaults to standard. - # - # ==== Parameters - # name - # - def group(name = nil) - if name - @group = name.to_s - else - @group ||= from_superclass(:group, "standard") - end - end - - # Returns the commands for this Foreman::Thor class. - # - # ==== Returns - # OrderedHash:: An ordered hash with commands names as keys and Foreman::Thor::Command - # objects as values. - # - def commands - @commands ||= Foreman::Thor::CoreExt::OrderedHash.new - end - alias_method :tasks, :commands - - # Returns the commands for this Foreman::Thor class and all subclasses. - # - # ==== Returns - # OrderedHash:: An ordered hash with commands names as keys and Foreman::Thor::Command - # objects as values. - # - def all_commands - @all_commands ||= from_superclass(:all_commands, Foreman::Thor::CoreExt::OrderedHash.new) - @all_commands.merge!(commands) - end - alias_method :all_tasks, :all_commands - - # Removes a given command from this Foreman::Thor class. This is usually done if you - # are inheriting from another class and don't want it to be available - # anymore. - # - # By default it only remove the mapping to the command. But you can supply - # :undefine => true to undefine the method from the class as well. - # - # ==== Parameters - # name:: The name of the command to be removed - # options:: You can give :undefine => true if you want commands the method - # to be undefined from the class as well. - # - def remove_command(*names) - options = names.last.is_a?(Hash) ? names.pop : {} - - names.each do |name| - commands.delete(name.to_s) - all_commands.delete(name.to_s) - undef_method name if options[:undefine] - end - end - alias_method :remove_task, :remove_command - - # All methods defined inside the given block are not added as commands. - # - # So you can do: - # - # class MyScript < Foreman::Thor - # no_commands do - # def this_is_not_a_command - # end - # end - # end - # - # You can also add the method and remove it from the command list: - # - # class MyScript < Foreman::Thor - # def this_is_not_a_command - # end - # remove_command :this_is_not_a_command - # end - # - def no_commands - @no_commands = true - yield - ensure - @no_commands = false - end - alias_method :no_tasks, :no_commands - - # Sets the namespace for the Foreman::Thor or Foreman::Thor::Group class. By default the - # namespace is retrieved from the class name. If your Foreman::Thor class is named - # Scripts::MyScript, the help method, for example, will be called as: - # - # thor scripts:my_script -h - # - # If you change the namespace: - # - # namespace :my_scripts - # - # You change how your commands are invoked: - # - # thor my_scripts -h - # - # Finally, if you change your namespace to default: - # - # namespace :default - # - # Your commands can be invoked with a shortcut. Instead of: - # - # thor :my_command - # - def namespace(name = nil) - if name - @namespace = name.to_s - else - @namespace ||= Foreman::Thor::Util.namespace_from_thor_class(self) - end - end - - # Parses the command and options from the given args, instantiate the class - # and invoke the command. This method is used when the arguments must be parsed - # from an array. If you are inside Ruby and want to use a Foreman::Thor class, you - # can simply initialize it: - # - # script = MyScript.new(args, options, config) - # script.invoke(:command, first_arg, second_arg, third_arg) - # - def start(given_args = ARGV, config = {}) - config[:shell] ||= Foreman::Thor::Base.shell.new - dispatch(nil, given_args.dup, nil, config) - rescue Foreman::Thor::Error => e - config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message) - exit(1) if exit_on_failure? - rescue Errno::EPIPE - # This happens if a thor command is piped to something like `head`, - # which closes the pipe when it's done reading. This will also - # mean that if the pipe is closed, further unnecessary - # computation will not occur. - exit(0) - end - - # Allows to use private methods from parent in child classes as commands. - # - # ==== Parameters - # names:: Method names to be used as commands - # - # ==== Examples - # - # public_command :foo - # public_command :foo, :bar, :baz - # - def public_command(*names) - names.each do |name| - class_eval "def #{name}(*); super end" - end - end - alias_method :public_task, :public_command - - def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc: - raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace." if has_namespace - raise UndefinedCommandError, "Could not find command #{command.inspect}." - end - alias_method :handle_no_task_error, :handle_no_command_error - - def handle_argument_error(command, error, args, arity) #:nodoc: - msg = "ERROR: \"#{basename} #{command.name}\" was called with " - msg << "no arguments" if args.empty? - msg << "arguments " << args.inspect unless args.empty? - msg << "\nUsage: #{banner(command).inspect}" - raise InvocationError, msg - end - - protected - - # Prints the class options per group. If an option does not belong to - # any group, it's printed as Class option. - # - def class_options_help(shell, groups = {}) #:nodoc: - # Group options by group - class_options.each do |_, value| - groups[value.group] ||= [] - groups[value.group] << value - end - - # Deal with default group - global_options = groups.delete(nil) || [] - print_options(shell, global_options) - - # Print all others - groups.each do |group_name, options| - print_options(shell, options, group_name) - end - end - - # Receives a set of options and print them. - def print_options(shell, options, group_name = nil) - return if options.empty? - - list = [] - padding = options.map { |o| o.aliases.size }.max.to_i * 4 - - options.each do |option| - next if option.hide - item = [option.usage(padding)] - item.push(option.description ? "# #{option.description}" : "") - - list << item - list << ["", "# Default: #{option.default}"] if option.show_default? - list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum - end - - shell.say(group_name ? "#{group_name} options:" : "Options:") - shell.print_table(list, :indent => 2) - shell.say "" - end - - # Raises an error if the word given is a Foreman::Thor reserved word. - def is_thor_reserved_word?(word, type) #:nodoc: - return false unless THOR_RESERVED_WORDS.include?(word.to_s) - raise "#{word.inspect} is a Foreman::Thor reserved word and cannot be defined as #{type}" - end - - # Build an option and adds it to the given scope. - # - # ==== Parameters - # name:: The name of the argument. - # options:: Described in both class_option and method_option. - # scope:: Options hash that is being built up - def build_option(name, options, scope) #:nodoc: - scope[name] = Foreman::Thor::Option.new(name, options) - end - - # Receives a hash of options, parse them and add to the scope. This is a - # fast way to set a bunch of options: - # - # build_options :foo => true, :bar => :required, :baz => :string - # - # ==== Parameters - # Hash[Symbol => Object] - def build_options(options, scope) #:nodoc: - options.each do |key, value| - scope[key] = Foreman::Thor::Option.parse(key, value) - end - end - - # Finds a command with the given name. If the command belongs to the current - # class, just return it, otherwise dup it and add the fresh copy to the - # current command hash. - def find_and_refresh_command(name) #:nodoc: - if commands[name.to_s] - commands[name.to_s] - elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition - commands[name.to_s] = command.clone - else - raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found." - end - end - alias_method :find_and_refresh_task, :find_and_refresh_command - - # Everytime someone inherits from a Foreman::Thor class, register the klass - # and file into baseclass. - def inherited(klass) - Foreman::Thor::Base.register_klass_file(klass) - klass.instance_variable_set(:@no_commands, false) - end - - # Fire this callback whenever a method is added. Added methods are - # tracked as commands by invoking the create_command method. - def method_added(meth) - meth = meth.to_s - - if meth == "initialize" - initialize_added - return - end - - # Return if it's not a public instance method - return unless public_method_defined?(meth.to_sym) - - @no_commands ||= false - return if @no_commands || !create_command(meth) - - is_thor_reserved_word?(meth, :command) - Foreman::Thor::Base.register_klass_file(self) - end - - # Retrieves a value from superclass. If it reaches the baseclass, - # returns default. - def from_superclass(method, default = nil) - if self == baseclass || !superclass.respond_to?(method, true) - default - else - value = superclass.send(method) - - # Ruby implements `dup` on Object, but raises a `TypeError` - # if the method is called on immediates. As a result, we - # don't have a good way to check whether dup will succeed - # without calling it and rescuing the TypeError. - begin - value.dup - rescue TypeError - value - end - - end - end - - # A flag that makes the process exit with status 1 if any error happens. - def exit_on_failure? - false - end - - # - # The basename of the program invoking the thor class. - # - def basename - File.basename($PROGRAM_NAME).split(" ").first - end - - # SIGNATURE: Sets the baseclass. This is where the superclass lookup - # finishes. - def baseclass #:nodoc: - end - - # SIGNATURE: Creates a new command if valid_command? is true. This method is - # called when a new method is added to the class. - def create_command(meth) #:nodoc: - end - alias_method :create_task, :create_command - - # SIGNATURE: Defines behavior when the initialize method is added to the - # class. - def initialize_added #:nodoc: - end - - # SIGNATURE: The hook invoked by start. - def dispatch(command, given_args, given_opts, config) #:nodoc: - raise NotImplementedError - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/command.rb b/lib/foreman/vendor/thor/lib/thor/command.rb deleted file mode 100644 index 8db02c99..00000000 --- a/lib/foreman/vendor/thor/lib/thor/command.rb +++ /dev/null @@ -1,133 +0,0 @@ -class Foreman::Thor - class Command < Struct.new(:name, :description, :long_description, :usage, :options, :disable_class_options) - FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/ - - def initialize(name, description, long_description, usage, options = nil, disable_class_options = false) - super(name.to_s, description, long_description, usage, options || {}, disable_class_options) - end - - def initialize_copy(other) #:nodoc: - super(other) - self.options = other.options.dup if other.options - end - - def hidden? - false - end - - # By default, a command invokes a method in the thor class. You can change this - # implementation to create custom commands. - def run(instance, args = []) - arity = nil - - if private_method?(instance) - instance.class.handle_no_command_error(name) - elsif public_method?(instance) - arity = instance.method(name).arity - instance.__send__(name, *args) - elsif local_method?(instance, :method_missing) - instance.__send__(:method_missing, name.to_sym, *args) - else - instance.class.handle_no_command_error(name) - end - rescue ArgumentError => e - handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e, args, arity) : (raise e) - rescue NoMethodError => e - handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_command_error(name) : (raise e) - end - - # Returns the formatted usage by injecting given required arguments - # and required options into the given usage. - def formatted_usage(klass, namespace = true, subcommand = false) - if namespace - namespace = klass.namespace - formatted = "#{namespace.gsub(/^(default)/, '')}:" - end - formatted = "#{klass.namespace.split(':').last} " if subcommand - - formatted ||= "" - - # Add usage with required arguments - formatted << if klass && !klass.arguments.empty? - usage.to_s.gsub(/^#{name}/) do |match| - match << " " << klass.arguments.map(&:usage).compact.join(" ") - end - else - usage.to_s - end - - # Add required options - formatted << " #{required_options}" - - # Strip and go! - formatted.strip - end - - protected - - def not_debugging?(instance) - !(instance.class.respond_to?(:debugging) && instance.class.debugging) - end - - def required_options - @required_options ||= options.map { |_, o| o.usage if o.required? }.compact.sort.join(" ") - end - - # Given a target, checks if this class name is a public method. - def public_method?(instance) #:nodoc: - !(instance.public_methods & [name.to_s, name.to_sym]).empty? - end - - def private_method?(instance) - !(instance.private_methods & [name.to_s, name.to_sym]).empty? - end - - def local_method?(instance, name) - methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false) - !(methods & [name.to_s, name.to_sym]).empty? - end - - def sans_backtrace(backtrace, caller) #:nodoc: - saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) || (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/) } - saned - caller - end - - def handle_argument_error?(instance, error, caller) - not_debugging?(instance) && (error.message =~ /wrong number of arguments/ || error.message =~ /given \d*, expected \d*/) && begin - saned = sans_backtrace(error.backtrace, caller) - # Ruby 1.9 always include the called method in the backtrace - saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9") - end - end - - def handle_no_method_error?(instance, error, caller) - not_debugging?(instance) && - error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/ - end - end - Task = Command - - # A command that is hidden in help messages but still invocable. - class HiddenCommand < Command - def hidden? - true - end - end - HiddenTask = HiddenCommand - - # A dynamic command that handles method missing scenarios. - class DynamicCommand < Command - def initialize(name, options = nil) - super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options) - end - - def run(instance, args = []) - if (instance.methods & [name.to_s, name.to_sym]).empty? - super - else - instance.class.handle_no_command_error(name) - end - end - end - DynamicTask = DynamicCommand -end diff --git a/lib/foreman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb b/lib/foreman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb deleted file mode 100644 index 0cf2e9d6..00000000 --- a/lib/foreman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +++ /dev/null @@ -1,85 +0,0 @@ -class Foreman::Thor - module CoreExt #:nodoc: - # A hash with indifferent access and magic predicates. - # - # hash = Foreman::Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true - # - # hash[:foo] #=> 'bar' - # hash['foo'] #=> 'bar' - # hash.foo? #=> true - # - class HashWithIndifferentAccess < ::Hash #:nodoc: - def initialize(hash = {}) - super() - hash.each do |key, value| - self[convert_key(key)] = value - end - end - - def [](key) - super(convert_key(key)) - end - - def []=(key, value) - super(convert_key(key), value) - end - - def delete(key) - super(convert_key(key)) - end - - def fetch(key, *args) - super(convert_key(key), *args) - end - - def key?(key) - super(convert_key(key)) - end - - def values_at(*indices) - indices.map { |key| self[convert_key(key)] } - end - - def merge(other) - dup.merge!(other) - end - - def merge!(other) - other.each do |key, value| - self[convert_key(key)] = value - end - self - end - - # Convert to a Hash with String keys. - def to_hash - Hash.new(default).merge!(self) - end - - protected - - def convert_key(key) - key.is_a?(Symbol) ? key.to_s : key - end - - # Magic predicates. For instance: - # - # options.force? # => !!options['force'] - # options.shebang # => "/usr/lib/local/ruby" - # options.test_framework?(:rspec) # => options[:test_framework] == :rspec - # - def method_missing(method, *args) - method = method.to_s - if method =~ /^(\w+)\?$/ - if args.empty? - !!self[$1] - else - self[$1] == args.first - end - else - self[method] - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/core_ext/io_binary_read.rb b/lib/foreman/vendor/thor/lib/thor/core_ext/io_binary_read.rb deleted file mode 100644 index 0f6e2e0a..00000000 --- a/lib/foreman/vendor/thor/lib/thor/core_ext/io_binary_read.rb +++ /dev/null @@ -1,12 +0,0 @@ -class IO #:nodoc: - class << self - unless method_defined? :binread - def binread(file, *args) - raise ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3 - File.open(file, "rb") do |f| - f.read(*args) - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/core_ext/ordered_hash.rb b/lib/foreman/vendor/thor/lib/thor/core_ext/ordered_hash.rb deleted file mode 100644 index 0c0562ad..00000000 --- a/lib/foreman/vendor/thor/lib/thor/core_ext/ordered_hash.rb +++ /dev/null @@ -1,129 +0,0 @@ -class Foreman::Thor - module CoreExt - class OrderedHash < ::Hash - if RUBY_VERSION < "1.9" - def initialize(*args, &block) - super - @keys = [] - end - - def initialize_copy(other) - super - # make a deep copy of keys - @keys = other.keys - end - - def []=(key, value) - @keys << key unless key?(key) - super - end - - def delete(key) - if key? key - index = @keys.index(key) - @keys.delete_at index - end - super - end - - def delete_if - super - sync_keys! - self - end - - alias_method :reject!, :delete_if - - def reject(&block) - dup.reject!(&block) - end - - def keys - @keys.dup - end - - def values - @keys.map { |key| self[key] } - end - - def to_hash - self - end - - def to_a - @keys.map { |key| [key, self[key]] } - end - - def each_key - return to_enum(:each_key) unless block_given? - @keys.each { |key| yield(key) } - self - end - - def each_value - return to_enum(:each_value) unless block_given? - @keys.each { |key| yield(self[key]) } - self - end - - def each - return to_enum(:each) unless block_given? - @keys.each { |key| yield([key, self[key]]) } - self - end - - def each_pair - return to_enum(:each_pair) unless block_given? - @keys.each { |key| yield(key, self[key]) } - self - end - - alias_method :select, :find_all - - def clear - super - @keys.clear - self - end - - def shift - k = @keys.first - v = delete(k) - [k, v] - end - - def merge!(other_hash) - if block_given? - other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v } - else - other_hash.each { |k, v| self[k] = v } - end - self - end - - alias_method :update, :merge! - - def merge(other_hash, &block) - dup.merge!(other_hash, &block) - end - - # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not. - def replace(other) - super - @keys = other.keys - self - end - - def inspect - "#<#{self.class} #{super}>" - end - - private - - def sync_keys! - @keys.delete_if { |k| !key?(k) } - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/error.rb b/lib/foreman/vendor/thor/lib/thor/error.rb deleted file mode 100644 index da942b6f..00000000 --- a/lib/foreman/vendor/thor/lib/thor/error.rb +++ /dev/null @@ -1,32 +0,0 @@ -class Foreman::Thor - # Foreman::Thor::Error is raised when it's caused by wrong usage of thor classes. Those - # errors have their backtrace suppressed and are nicely shown to the user. - # - # Errors that are caused by the developer, like declaring a method which - # overwrites a thor keyword, SHOULD NOT raise a Foreman::Thor::Error. This way, we - # ensure that developer errors are shown with full backtrace. - class Error < StandardError - end - - # Raised when a command was not found. - class UndefinedCommandError < Error - end - UndefinedTaskError = UndefinedCommandError - - class AmbiguousCommandError < Error - end - AmbiguousTaskError = AmbiguousCommandError - - # Raised when a command was found, but not invoked properly. - class InvocationError < Error - end - - class UnknownArgumentError < Error - end - - class RequiredArgumentMissingError < InvocationError - end - - class MalformattedArgumentError < InvocationError - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/group.rb b/lib/foreman/vendor/thor/lib/thor/group.rb deleted file mode 100644 index ea3ab1db..00000000 --- a/lib/foreman/vendor/thor/lib/thor/group.rb +++ /dev/null @@ -1,281 +0,0 @@ -require "foreman/vendor/thor/lib/thor/base" - -# Foreman::Thor has a special class called Foreman::Thor::Group. The main difference to Foreman::Thor class -# is that it invokes all commands at once. It also include some methods that allows -# invocations to be done at the class method, which are not available to Foreman::Thor -# commands. -class Foreman::Thor::Group - class << self - # The description for this Foreman::Thor::Group. If none is provided, but a source root - # exists, tries to find the USAGE one folder above it, otherwise searches - # in the superclass. - # - # ==== Parameters - # description:: The description for this Foreman::Thor::Group. - # - def desc(description = nil) - if description - @desc = description - else - @desc ||= from_superclass(:desc, nil) - end - end - - # Prints help information. - # - # ==== Options - # short:: When true, shows only usage. - # - def help(shell) - shell.say "Usage:" - shell.say " #{banner}\n" - shell.say - class_options_help(shell) - shell.say desc if desc - end - - # Stores invocations for this class merging with superclass values. - # - def invocations #:nodoc: - @invocations ||= from_superclass(:invocations, {}) - end - - # Stores invocation blocks used on invoke_from_option. - # - def invocation_blocks #:nodoc: - @invocation_blocks ||= from_superclass(:invocation_blocks, {}) - end - - # Invoke the given namespace or class given. It adds an instance - # method that will invoke the klass and command. You can give a block to - # configure how it will be invoked. - # - # The namespace/class given will have its options showed on the help - # usage. Check invoke_from_option for more information. - # - def invoke(*names, &block) - options = names.last.is_a?(Hash) ? names.pop : {} - verbose = options.fetch(:verbose, true) - - names.each do |name| - invocations[name] = false - invocation_blocks[name] = block if block_given? - - class_eval <<-METHOD, __FILE__, __LINE__ - def _invoke_#{name.to_s.gsub(/\W/, '_')} - klass, command = self.class.prepare_for_invocation(nil, #{name.inspect}) - - if klass - say_status :invoke, #{name.inspect}, #{verbose.inspect} - block = self.class.invocation_blocks[#{name.inspect}] - _invoke_for_class_method klass, command, &block - else - say_status :error, %(#{name.inspect} [not found]), :red - end - end - METHOD - end - end - - # Invoke a thor class based on the value supplied by the user to the - # given option named "name". A class option must be created before this - # method is invoked for each name given. - # - # ==== Examples - # - # class GemGenerator < Foreman::Thor::Group - # class_option :test_framework, :type => :string - # invoke_from_option :test_framework - # end - # - # ==== Boolean options - # - # In some cases, you want to invoke a thor class if some option is true or - # false. This is automatically handled by invoke_from_option. Then the - # option name is used to invoke the generator. - # - # ==== Preparing for invocation - # - # In some cases you want to customize how a specified hook is going to be - # invoked. You can do that by overwriting the class method - # prepare_for_invocation. The class method must necessarily return a klass - # and an optional command. - # - # ==== Custom invocations - # - # You can also supply a block to customize how the option is going to be - # invoked. The block receives two parameters, an instance of the current - # class and the klass to be invoked. - # - def invoke_from_option(*names, &block) - options = names.last.is_a?(Hash) ? names.pop : {} - verbose = options.fetch(:verbose, :white) - - names.each do |name| - unless class_options.key?(name) - raise ArgumentError, "You have to define the option #{name.inspect} " \ - "before setting invoke_from_option." - end - - invocations[name] = true - invocation_blocks[name] = block if block_given? - - class_eval <<-METHOD, __FILE__, __LINE__ - def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')} - return unless options[#{name.inspect}] - - value = options[#{name.inspect}] - value = #{name.inspect} if TrueClass === value - klass, command = self.class.prepare_for_invocation(#{name.inspect}, value) - - if klass - say_status :invoke, value, #{verbose.inspect} - block = self.class.invocation_blocks[#{name.inspect}] - _invoke_for_class_method klass, command, &block - else - say_status :error, %(\#{value} [not found]), :red - end - end - METHOD - end - end - - # Remove a previously added invocation. - # - # ==== Examples - # - # remove_invocation :test_framework - # - def remove_invocation(*names) - names.each do |name| - remove_command(name) - remove_class_option(name) - invocations.delete(name) - invocation_blocks.delete(name) - end - end - - # Overwrite class options help to allow invoked generators options to be - # shown recursively when invoking a generator. - # - def class_options_help(shell, groups = {}) #:nodoc: - get_options_from_invocations(groups, class_options) do |klass| - klass.send(:get_options_from_invocations, groups, class_options) - end - super(shell, groups) - end - - # Get invocations array and merge options from invocations. Those - # options are added to group_options hash. Options that already exists - # in base_options are not added twice. - # - def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength - invocations.each do |name, from_option| - value = if from_option - option = class_options[name] - option.type == :boolean ? name : option.default - else - name - end - next unless value - - klass, _ = prepare_for_invocation(name, value) - next unless klass && klass.respond_to?(:class_options) - - value = value.to_s - human_name = value.respond_to?(:classify) ? value.classify : value - - group_options[human_name] ||= [] - group_options[human_name] += klass.class_options.values.select do |class_option| - base_options[class_option.name.to_sym].nil? && class_option.group.nil? && - !group_options.values.flatten.any? { |i| i.name == class_option.name } - end - - yield klass if block_given? - end - end - - # Returns commands ready to be printed. - def printable_commands(*) - item = [] - item << banner - item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "") - [item] - end - alias_method :printable_tasks, :printable_commands - - def handle_argument_error(command, error, _args, arity) #:nodoc: - msg = "#{basename} #{command.name} takes #{arity} argument" - msg << "s" if arity > 1 - msg << ", but it should not." - raise error, msg - end - - protected - - # The method responsible for dispatching given the args. - def dispatch(command, given_args, given_opts, config) #:nodoc: - if Foreman::Thor::HELP_MAPPINGS.include?(given_args.first) - help(config[:shell]) - return - end - - args, opts = Foreman::Thor::Options.split(given_args) - opts = given_opts || opts - - instance = new(args, opts, config) - yield instance if block_given? - - if command - instance.invoke_command(all_commands[command]) - else - instance.invoke_all - end - end - - # The banner for this class. You can customize it if you are invoking the - # thor class by another ways which is not the Foreman::Thor::Runner. - def banner - "#{basename} #{self_command.formatted_usage(self, false)}" - end - - # Represents the whole class as a command. - def self_command #:nodoc: - Foreman::Thor::DynamicCommand.new(namespace, class_options) - end - alias_method :self_task, :self_command - - def baseclass #:nodoc: - Foreman::Thor::Group - end - - def create_command(meth) #:nodoc: - commands[meth.to_s] = Foreman::Thor::Command.new(meth, nil, nil, nil, nil) - true - end - alias_method :create_task, :create_command - end - - include Foreman::Thor::Base - -protected - - # Shortcut to invoke with padding and block handling. Use internally by - # invoke and invoke_from_option class methods. - def _invoke_for_class_method(klass, command = nil, *args, &block) #:nodoc: - with_padding do - if block - case block.arity - when 3 - yield(self, klass, command) - when 2 - yield(self, klass) - when 1 - instance_exec(klass, &block) - end - else - invoke klass, command, *args - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/invocation.rb b/lib/foreman/vendor/thor/lib/thor/invocation.rb deleted file mode 100644 index dce48605..00000000 --- a/lib/foreman/vendor/thor/lib/thor/invocation.rb +++ /dev/null @@ -1,177 +0,0 @@ -class Foreman::Thor - module Invocation - def self.included(base) #:nodoc: - base.extend ClassMethods - end - - module ClassMethods - # This method is responsible for receiving a name and find the proper - # class and command for it. The key is an optional parameter which is - # available only in class methods invocations (i.e. in Foreman::Thor::Group). - def prepare_for_invocation(key, name) #:nodoc: - case name - when Symbol, String - Foreman::Thor::Util.find_class_and_command_by_namespace(name.to_s, !key) - else - name - end - end - end - - # Make initializer aware of invocations and the initialization args. - def initialize(args = [], options = {}, config = {}, &block) #:nodoc: - @_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] } - @_initializer = [args, options, config] - super - end - - # Make the current command chain accessible with in a Foreman::Thor-(sub)command - def current_command_chain - @_invocations.values.flatten.map(&:to_sym) - end - - # Receives a name and invokes it. The name can be a string (either "command" or - # "namespace:command"), a Foreman::Thor::Command, a Class or a Foreman::Thor instance. If the - # command cannot be guessed by name, it can also be supplied as second argument. - # - # You can also supply the arguments, options and configuration values for - # the command to be invoked, if none is given, the same values used to - # initialize the invoker are used to initialize the invoked. - # - # When no name is given, it will invoke the default command of the current class. - # - # ==== Examples - # - # class A < Foreman::Thor - # def foo - # invoke :bar - # invoke "b:hello", ["Erik"] - # end - # - # def bar - # invoke "b:hello", ["Erik"] - # end - # end - # - # class B < Foreman::Thor - # def hello(name) - # puts "hello #{name}" - # end - # end - # - # You can notice that the method "foo" above invokes two commands: "bar", - # which belongs to the same class and "hello" which belongs to the class B. - # - # By using an invocation system you ensure that a command is invoked only once. - # In the example above, invoking "foo" will invoke "b:hello" just once, even - # if it's invoked later by "bar" method. - # - # When class A invokes class B, all arguments used on A initialization are - # supplied to B. This allows lazy parse of options. Let's suppose you have - # some rspec commands: - # - # class Rspec < Foreman::Thor::Group - # class_option :mock_framework, :type => :string, :default => :rr - # - # def invoke_mock_framework - # invoke "rspec:#{options[:mock_framework]}" - # end - # end - # - # As you noticed, it invokes the given mock framework, which might have its - # own options: - # - # class Rspec::RR < Foreman::Thor::Group - # class_option :style, :type => :string, :default => :mock - # end - # - # Since it's not rspec concern to parse mock framework options, when RR - # is invoked all options are parsed again, so RR can extract only the options - # that it's going to use. - # - # If you want Rspec::RR to be initialized with its own set of options, you - # have to do that explicitly: - # - # invoke "rspec:rr", [], :style => :foo - # - # Besides giving an instance, you can also give a class to invoke: - # - # invoke Rspec::RR, [], :style => :foo - # - def invoke(name = nil, *args) - if name.nil? - warn "[Foreman::Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}" - return invoke_all - end - - args.unshift(nil) if args.first.is_a?(Array) || args.first.nil? - command, args, opts, config = args - - klass, command = _retrieve_class_and_command(name, command) - raise "Missing Foreman::Thor class for invoke #{name}" unless klass - raise "Expected Foreman::Thor class, got #{klass}" unless klass <= Foreman::Thor::Base - - args, opts, config = _parse_initialization_options(args, opts, config) - klass.send(:dispatch, command, args, opts, config) do |instance| - instance.parent_options = options - end - end - - # Invoke the given command if the given args. - def invoke_command(command, *args) #:nodoc: - current = @_invocations[self.class] - - unless current.include?(command.name) - current << command.name - command.run(self, *args) - end - end - alias_method :invoke_task, :invoke_command - - # Invoke all commands for the current instance. - def invoke_all #:nodoc: - self.class.all_commands.map { |_, command| invoke_command(command) } - end - - # Invokes using shell padding. - def invoke_with_padding(*args) - with_padding { invoke(*args) } - end - - protected - - # Configuration values that are shared between invocations. - def _shared_configuration #:nodoc: - {:invocations => @_invocations} - end - - # This method simply retrieves the class and command to be invoked. - # If the name is nil or the given name is a command in the current class, - # use the given name and return self as class. Otherwise, call - # prepare_for_invocation in the current class. - def _retrieve_class_and_command(name, sent_command = nil) #:nodoc: - if name.nil? - [self.class, nil] - elsif self.class.all_commands[name.to_s] - [self.class, name.to_s] - else - klass, command = self.class.prepare_for_invocation(nil, name) - [klass, command || sent_command] - end - end - alias_method :_retrieve_class_and_task, :_retrieve_class_and_command - - # Initialize klass using values stored in the @_initializer. - def _parse_initialization_options(args, opts, config) #:nodoc: - stored_args, stored_opts, stored_config = @_initializer - - args ||= stored_args.dup - opts ||= stored_opts.dup - - config ||= {} - config = stored_config.merge(_shared_configuration).merge!(config) - - [args, opts, config] - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/line_editor.rb b/lib/foreman/vendor/thor/lib/thor/line_editor.rb deleted file mode 100644 index e6bf7f5c..00000000 --- a/lib/foreman/vendor/thor/lib/thor/line_editor.rb +++ /dev/null @@ -1,17 +0,0 @@ -require "foreman/vendor/thor/lib/thor/line_editor/basic" -require "foreman/vendor/thor/lib/thor/line_editor/readline" - -class Foreman::Thor - module LineEditor - def self.readline(prompt, options = {}) - best_available.new(prompt, options).readline - end - - def self.best_available - [ - Foreman::Thor::LineEditor::Readline, - Foreman::Thor::LineEditor::Basic - ].detect(&:available?) - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/line_editor/basic.rb b/lib/foreman/vendor/thor/lib/thor/line_editor/basic.rb deleted file mode 100644 index 91719963..00000000 --- a/lib/foreman/vendor/thor/lib/thor/line_editor/basic.rb +++ /dev/null @@ -1,35 +0,0 @@ -class Foreman::Thor - module LineEditor - class Basic - attr_reader :prompt, :options - - def self.available? - true - end - - def initialize(prompt, options) - @prompt = prompt - @options = options - end - - def readline - $stdout.print(prompt) - get_input - end - - private - - def get_input - if echo? - $stdin.gets - else - $stdin.noecho(&:gets) - end - end - - def echo? - options.fetch(:echo, true) - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/line_editor/readline.rb b/lib/foreman/vendor/thor/lib/thor/line_editor/readline.rb deleted file mode 100644 index b84481da..00000000 --- a/lib/foreman/vendor/thor/lib/thor/line_editor/readline.rb +++ /dev/null @@ -1,88 +0,0 @@ -begin - require "readline" -rescue LoadError -end - -class Foreman::Thor - module LineEditor - class Readline < Basic - def self.available? - Object.const_defined?(:Readline) - end - - def readline - if echo? - ::Readline.completion_append_character = nil - # Ruby 1.8.7 does not allow Readline.completion_proc= to receive nil. - if complete = completion_proc - ::Readline.completion_proc = complete - end - ::Readline.readline(prompt, add_to_history?) - else - super - end - end - - private - - def add_to_history? - options.fetch(:add_to_history, true) - end - - def completion_proc - if use_path_completion? - proc { |text| PathCompletion.new(text).matches } - elsif completion_options.any? - proc do |text| - completion_options.select { |option| option.start_with?(text) } - end - end - end - - def completion_options - options.fetch(:limited_to, []) - end - - def use_path_completion? - options.fetch(:path, false) - end - - class PathCompletion - attr_reader :text - private :text - - def initialize(text) - @text = text - end - - def matches - relative_matches - end - - private - - def relative_matches - absolute_matches.map { |path| path.sub(base_path, "") } - end - - def absolute_matches - Dir[glob_pattern].map do |path| - if File.directory?(path) - "#{path}/" - else - path - end - end - end - - def glob_pattern - "#{base_path}#{text}*" - end - - def base_path - "#{Dir.pwd}/" - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/parser.rb b/lib/foreman/vendor/thor/lib/thor/parser.rb deleted file mode 100644 index 48fc9c66..00000000 --- a/lib/foreman/vendor/thor/lib/thor/parser.rb +++ /dev/null @@ -1,4 +0,0 @@ -require "foreman/vendor/thor/lib/thor/parser/argument" -require "foreman/vendor/thor/lib/thor/parser/arguments" -require "foreman/vendor/thor/lib/thor/parser/option" -require "foreman/vendor/thor/lib/thor/parser/options" diff --git a/lib/foreman/vendor/thor/lib/thor/parser/argument.rb b/lib/foreman/vendor/thor/lib/thor/parser/argument.rb deleted file mode 100644 index d49e2bc6..00000000 --- a/lib/foreman/vendor/thor/lib/thor/parser/argument.rb +++ /dev/null @@ -1,70 +0,0 @@ -class Foreman::Thor - class Argument #:nodoc: - VALID_TYPES = [:numeric, :hash, :array, :string] - - attr_reader :name, :description, :enum, :required, :type, :default, :banner - alias_method :human_name, :name - - def initialize(name, options = {}) - class_name = self.class.name.split("::").last - - type = options[:type] - - raise ArgumentError, "#{class_name} name can't be nil." if name.nil? - raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type) - - @name = name.to_s - @description = options[:desc] - @required = options.key?(:required) ? options[:required] : true - @type = (type || :string).to_sym - @default = options[:default] - @banner = options[:banner] || default_banner - @enum = options[:enum] - - validate! # Trigger specific validations - end - - def usage - required? ? banner : "[#{banner}]" - end - - def required? - required - end - - def show_default? - case default - when Array, String, Hash - !default.empty? - else - default - end - end - - protected - - def validate! - raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil? - raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array) - end - - def valid_type?(type) - self.class::VALID_TYPES.include?(type.to_sym) - end - - def default_banner - case type - when :boolean - nil - when :string, :default - human_name.upcase - when :numeric - "N" - when :hash - "key:value" - when :array - "one two three" - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/parser/arguments.rb b/lib/foreman/vendor/thor/lib/thor/parser/arguments.rb deleted file mode 100644 index 3298ec9d..00000000 --- a/lib/foreman/vendor/thor/lib/thor/parser/arguments.rb +++ /dev/null @@ -1,175 +0,0 @@ -class Foreman::Thor - class Arguments #:nodoc: # rubocop:disable ClassLength - NUMERIC = /[-+]?(\d*\.\d+|\d+)/ - - # Receives an array of args and returns two arrays, one with arguments - # and one with switches. - # - def self.split(args) - arguments = [] - - args.each do |item| - break if item =~ /^-/ - arguments << item - end - - [arguments, args[Range.new(arguments.size, -1)]] - end - - def self.parse(*args) - to_parse = args.pop - new(*args).parse(to_parse) - end - - # Takes an array of Foreman::Thor::Argument objects. - # - def initialize(arguments = []) - @assigns = {} - @non_assigned_required = [] - @switches = arguments - - arguments.each do |argument| - if !argument.default.nil? - @assigns[argument.human_name] = argument.default - elsif argument.required? - @non_assigned_required << argument - end - end - end - - def parse(args) - @pile = args.dup - - @switches.each do |argument| - break unless peek - @non_assigned_required.delete(argument) - @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name) - end - - check_requirement! - @assigns - end - - def remaining - @pile - end - - private - - def no_or_skip?(arg) - arg =~ /^--(no|skip)-([-\w]+)$/ - $2 - end - - def last? - @pile.empty? - end - - def peek - @pile.first - end - - def shift - @pile.shift - end - - def unshift(arg) - if arg.is_a?(Array) - @pile = arg + @pile - else - @pile.unshift(arg) - end - end - - def current_is_value? - peek && peek.to_s !~ /^-/ - end - - # Runs through the argument array getting strings that contains ":" and - # mark it as a hash: - # - # [ "name:string", "age:integer" ] - # - # Becomes: - # - # { "name" => "string", "age" => "integer" } - # - def parse_hash(name) - return shift if peek.is_a?(Hash) - hash = {} - - while current_is_value? && peek.include?(":") - key, value = shift.split(":", 2) - raise MalformattedArgumentError, "You can't specify '#{key}' more than once in option '#{name}'; got #{key}:#{hash[key]} and #{key}:#{value}" if hash.include? key - hash[key] = value - end - hash - end - - # Runs through the argument array getting all strings until no string is - # found or a switch is found. - # - # ["a", "b", "c"] - # - # And returns it as an array: - # - # ["a", "b", "c"] - # - def parse_array(name) - return shift if peek.is_a?(Array) - array = [] - array << shift while current_is_value? - array - end - - # Check if the peek is numeric format and return a Float or Integer. - # Check if the peek is included in enum if enum is provided. - # Otherwise raises an error. - # - def parse_numeric(name) - return shift if peek.is_a?(Numeric) - - unless peek =~ NUMERIC && $& == peek - raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}" - end - - value = $&.index(".") ? shift.to_f : shift.to_i - if @switches.is_a?(Hash) && switch = @switches[name] - if switch.enum && !switch.enum.include?(value) - raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" - end - end - value - end - - # Parse string: - # for --string-arg, just return the current value in the pile - # for --no-string-arg, nil - # Check if the peek is included in enum if enum is provided. Otherwise raises an error. - # - def parse_string(name) - if no_or_skip?(name) - nil - else - value = shift - if @switches.is_a?(Hash) && switch = @switches[name] - if switch.enum && !switch.enum.include?(value) - raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}" - end - end - value - end - end - - # Raises an error if @non_assigned_required array is not empty. - # - def check_requirement! - return if @non_assigned_required.empty? - names = @non_assigned_required.map do |o| - o.respond_to?(:switch_name) ? o.switch_name : o.human_name - end.join("', '") - class_name = self.class.name.split("::").last.downcase - raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'" - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/parser/option.rb b/lib/foreman/vendor/thor/lib/thor/parser/option.rb deleted file mode 100644 index a0375523..00000000 --- a/lib/foreman/vendor/thor/lib/thor/parser/option.rb +++ /dev/null @@ -1,146 +0,0 @@ -class Foreman::Thor - class Option < Argument #:nodoc: - attr_reader :aliases, :group, :lazy_default, :hide - - VALID_TYPES = [:boolean, :numeric, :hash, :array, :string] - - def initialize(name, options = {}) - options[:required] = false unless options.key?(:required) - super - @lazy_default = options[:lazy_default] - @group = options[:group].to_s.capitalize if options[:group] - @aliases = Array(options[:aliases]) - @hide = options[:hide] - end - - # This parse quick options given as method_options. It makes several - # assumptions, but you can be more specific using the option method. - # - # parse :foo => "bar" - # #=> Option foo with default value bar - # - # parse [:foo, :baz] => "bar" - # #=> Option foo with default value bar and alias :baz - # - # parse :foo => :required - # #=> Required option foo without default value - # - # parse :foo => 2 - # #=> Option foo with default value 2 and type numeric - # - # parse :foo => :numeric - # #=> Option foo without default value and type numeric - # - # parse :foo => true - # #=> Option foo with default value true and type boolean - # - # The valid types are :boolean, :numeric, :hash, :array and :string. If none - # is given a default type is assumed. This default type accepts arguments as - # string (--foo=value) or booleans (just --foo). - # - # By default all options are optional, unless :required is given. - # - def self.parse(key, value) - if key.is_a?(Array) - name, *aliases = key - else - name = key - aliases = [] - end - - name = name.to_s - default = value - - type = case value - when Symbol - default = nil - if VALID_TYPES.include?(value) - value - elsif required = (value == :required) # rubocop:disable AssignmentInCondition - :string - end - when TrueClass, FalseClass - :boolean - when Numeric - :numeric - when Hash, Array, String - value.class.name.downcase.to_sym - end - - new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases) - end - - def switch_name - @switch_name ||= dasherized? ? name : dasherize(name) - end - - def human_name - @human_name ||= dasherized? ? undasherize(name) : name - end - - def usage(padding = 0) - sample = if banner && !banner.to_s.empty? - "#{switch_name}=#{banner}" - else - switch_name - end - - sample = "[#{sample}]" unless required? - - if boolean? - sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-") - end - - if aliases.empty? - (" " * padding) << sample - else - "#{aliases.join(', ')}, #{sample}" - end - end - - VALID_TYPES.each do |type| - class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{type}? - self.type == #{type.inspect} - end - RUBY - end - - protected - - def validate! - raise ArgumentError, "An option cannot be boolean and required." if boolean? && required? - validate_default_type! - end - - def validate_default_type! - default_type = case @default - when nil - return - when TrueClass, FalseClass - required? ? :string : :boolean - when Numeric - :numeric - when Symbol - :string - when Hash, Array, String - @default.class.name.downcase.to_sym - end - - # TODO: This should raise an ArgumentError in a future version of Foreman::Thor - warn "Expected #{@type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})" unless default_type == @type - end - - def dasherized? - name.index("-") == 0 - end - - def undasherize(str) - str.sub(/^-{1,2}/, "") - end - - def dasherize(str) - (str.length > 1 ? "--" : "-") + str.tr("_", "-") - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/parser/options.rb b/lib/foreman/vendor/thor/lib/thor/parser/options.rb deleted file mode 100644 index 2f15b8b1..00000000 --- a/lib/foreman/vendor/thor/lib/thor/parser/options.rb +++ /dev/null @@ -1,220 +0,0 @@ -class Foreman::Thor - class Options < Arguments #:nodoc: # rubocop:disable ClassLength - LONG_RE = /^(--\w+(?:-\w+)*)$/ - SHORT_RE = /^(-[a-z])$/i - EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i - SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args - SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i - OPTS_END = "--".freeze - - # Receives a hash and makes it switches. - def self.to_switches(options) - options.map do |key, value| - case value - when true - "--#{key}" - when Array - "--#{key} #{value.map(&:inspect).join(' ')}" - when Hash - "--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}" - when nil, false - "" - else - "--#{key} #{value.inspect}" - end - end.join(" ") - end - - # Takes a hash of Foreman::Thor::Option and a hash with defaults. - # - # If +stop_on_unknown+ is true, #parse will stop as soon as it encounters - # an unknown option or a regular argument. - def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false) - @stop_on_unknown = stop_on_unknown - options = hash_options.values - super(options) - - # Add defaults - defaults.each do |key, value| - @assigns[key.to_s] = value - @non_assigned_required.delete(hash_options[key]) - end - - @shorts = {} - @switches = {} - @extra = [] - - options.each do |option| - @switches[option.switch_name] = option - - option.aliases.each do |short| - name = short.to_s.sub(/^(?!\-)/, "-") - @shorts[name] ||= option.switch_name - end - end - end - - def remaining - @extra - end - - def peek - return super unless @parsing_options - - result = super - if result == OPTS_END - shift - @parsing_options = false - super - else - result - end - end - - def parse(args) # rubocop:disable MethodLength - @pile = args.dup - @parsing_options = true - - while peek - if parsing_options? - match, is_switch = current_is_switch? - shifted = shift - - if is_switch - case shifted - when SHORT_SQ_RE - unshift($1.split("").map { |f| "-#{f}" }) - next - when EQ_RE, SHORT_NUM - unshift($2) - switch = $1 - when LONG_RE, SHORT_RE - switch = $1 - end - - switch = normalize_switch(switch) - option = switch_option(switch) - @assigns[option.human_name] = parse_peek(switch, option) - elsif @stop_on_unknown - @parsing_options = false - @extra << shifted - @extra << shift while peek - break - elsif match - @extra << shifted - @extra << shift while peek && peek !~ /^-/ - else - @extra << shifted - end - else - @extra << shift - end - end - - check_requirement! - - assigns = Foreman::Thor::CoreExt::HashWithIndifferentAccess.new(@assigns) - assigns.freeze - assigns - end - - def check_unknown! - # an unknown option starts with - or -- and has no more --'s afterward. - unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ } - raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty? - end - - protected - - # Check if the current value in peek is a registered switch. - # - # Two booleans are returned. The first is true if the current value - # starts with a hyphen; the second is true if it is a registered switch. - def current_is_switch? - case peek - when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM - [true, switch?($1)] - when SHORT_SQ_RE - [true, $1.split("").any? { |f| switch?("-#{f}") }] - else - [false, false] - end - end - - def current_is_switch_formatted? - case peek - when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE - true - else - false - end - end - - def current_is_value? - peek && (!parsing_options? || super) - end - - def switch?(arg) - switch_option(normalize_switch(arg)) - end - - def switch_option(arg) - if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition - @switches[arg] || @switches["--#{match}"] - else - @switches[arg] - end - end - - # Check if the given argument is actually a shortcut. - # - def normalize_switch(arg) - (@shorts[arg] || arg).tr("_", "-") - end - - def parsing_options? - peek - @parsing_options - end - - # Parse boolean values which can be given as --foo=true, --foo or --no-foo. - # - def parse_boolean(switch) - if current_is_value? - if ["true", "TRUE", "t", "T", true].include?(peek) - shift - true - elsif ["false", "FALSE", "f", "F", false].include?(peek) - shift - false - else - true - end - else - @switches.key?(switch) || !no_or_skip?(switch) - end - end - - # Parse the value at the peek analyzing if it requires an input or not. - # - def parse_peek(switch, option) - if parsing_options? && (current_is_switch_formatted? || last?) - if option.boolean? - # No problem for boolean types - elsif no_or_skip?(switch) - return nil # User set value to nil - elsif option.string? && !option.required? - # Return the default if there is one, else the human name - return option.lazy_default || option.default || option.human_name - elsif option.lazy_default - return option.lazy_default - else - raise MalformattedArgumentError, "No value provided for option '#{switch}'" - end - end - - @non_assigned_required.delete(option) - send(:"parse_#{option.type}", switch) - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/rake_compat.rb b/lib/foreman/vendor/thor/lib/thor/rake_compat.rb deleted file mode 100644 index 7cb51f85..00000000 --- a/lib/foreman/vendor/thor/lib/thor/rake_compat.rb +++ /dev/null @@ -1,71 +0,0 @@ -require "rake" -require "rake/dsl_definition" - -class Foreman::Thor - # Adds a compatibility layer to your Foreman::Thor classes which allows you to use - # rake package tasks. For example, to use rspec rake tasks, one can do: - # - # require 'foreman/vendor/thor/lib/thor/rake_compat' - # require 'rspec/core/rake_task' - # - # class Default < Foreman::Thor - # include Foreman::Thor::RakeCompat - # - # RSpec::Core::RakeTask.new(:spec) do |t| - # t.spec_opts = ['--options', './.rspec'] - # t.spec_files = FileList['spec/**/*_spec.rb'] - # end - # end - # - module RakeCompat - include Rake::DSL if defined?(Rake::DSL) - - def self.rake_classes - @rake_classes ||= [] - end - - def self.included(base) - # Hack. Make rakefile point to invoker, so rdoc task is generated properly. - rakefile = File.basename(caller[0].match(/(.*):\d+/)[1]) - Rake.application.instance_variable_set(:@rakefile, rakefile) - rake_classes << base - end - end -end - -# override task on (main), for compatibility with Rake 0.9 -instance_eval do - alias rake_namespace namespace - - def task(*) - task = super - - if klass = Foreman::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition - non_namespaced_name = task.name.split(":").last - - description = non_namespaced_name - description << task.arg_names.map { |n| n.to_s.upcase }.join(" ") - description.strip! - - klass.desc description, Rake.application.last_description || non_namespaced_name - Rake.application.last_description = nil - klass.send :define_method, non_namespaced_name do |*args| - Rake::Task[task.name.to_sym].invoke(*args) - end - end - - task - end - - def namespace(name) - if klass = Foreman::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition - const_name = Foreman::Thor::Util.camel_case(name.to_s).to_sym - klass.const_set(const_name, Class.new(Foreman::Thor)) - new_klass = klass.const_get(const_name) - Foreman::Thor::RakeCompat.rake_classes << new_klass - end - - super - Foreman::Thor::RakeCompat.rake_classes.pop - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/runner.rb b/lib/foreman/vendor/thor/lib/thor/runner.rb deleted file mode 100644 index 07c43df9..00000000 --- a/lib/foreman/vendor/thor/lib/thor/runner.rb +++ /dev/null @@ -1,322 +0,0 @@ -require "foreman/vendor/thor/lib/thor" -require "foreman/vendor/thor/lib/thor/group" -require "foreman/vendor/thor/lib/thor/core_ext/io_binary_read" - -require "fileutils" -require "open-uri" -require "yaml" -require "digest/md5" -require "pathname" - -class Foreman::Thor::Runner < Foreman::Thor #:nodoc: # rubocop:disable ClassLength - map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version - - def self.banner(command, all = false, subcommand = false) - "thor " + command.formatted_usage(self, all, subcommand) - end - - def self.exit_on_failure? - true - end - - # Override Foreman::Thor#help so it can give information about any class and any method. - # - def help(meth = nil) - if meth && !respond_to?(meth) - initialize_thorfiles(meth) - klass, command = Foreman::Thor::Util.find_class_and_command_by_namespace(meth) - self.class.handle_no_command_error(command, false) if klass.nil? - klass.start(["-h", command].compact, :shell => shell) - else - super - end - end - - # If a command is not found on Foreman::Thor::Runner, method missing is invoked and - # Foreman::Thor::Runner is then responsible for finding the command in all classes. - # - def method_missing(meth, *args) - meth = meth.to_s - initialize_thorfiles(meth) - klass, command = Foreman::Thor::Util.find_class_and_command_by_namespace(meth) - self.class.handle_no_command_error(command, false) if klass.nil? - args.unshift(command) if command - klass.start(args, :shell => shell) - end - - desc "install NAME", "Install an optionally named Foreman::Thor file into your system commands" - method_options :as => :string, :relative => :boolean, :force => :boolean - def install(name) # rubocop:disable MethodLength - initialize_thorfiles - - # If a directory name is provided as the argument, look for a 'main.thor' - # command in said directory. - begin - if File.directory?(File.expand_path(name)) - base = File.join(name, "main.thor") - package = :directory - contents = open(base, &:read) - else - base = name - package = :file - contents = open(name, &:read) - end - rescue OpenURI::HTTPError - raise Error, "Error opening URI '#{name}'" - rescue Errno::ENOENT - raise Error, "Error opening file '#{name}'" - end - - say "Your Foreman::Thorfile contains:" - say contents - - unless options["force"] - return false if no?("Do you wish to continue [y/N]?") - end - - as = options["as"] || begin - first_line = contents.split("\n")[0] - (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil - end - - unless as - basename = File.basename(name) - as = ask("Please specify a name for #{name} in the system repository [#{basename}]:") - as = basename if as.empty? - end - - location = if options[:relative] || name =~ %r{^https?://} - name - else - File.expand_path(name) - end - - thor_yaml[as] = { - :filename => Digest::MD5.hexdigest(name + as), - :location => location, - :namespaces => Foreman::Thor::Util.namespaces_in_content(contents, base) - } - - save_yaml(thor_yaml) - say "Storing thor file in your system repository" - destination = File.join(thor_root, thor_yaml[as][:filename]) - - if package == :file - File.open(destination, "w") { |f| f.puts contents } - else - FileUtils.cp_r(name, destination) - end - - thor_yaml[as][:filename] # Indicate success - end - - desc "version", "Show Foreman::Thor version" - def version - require "foreman/vendor/thor/lib/thor/version" - say "Foreman::Thor #{Foreman::Thor::VERSION}" - end - - desc "uninstall NAME", "Uninstall a named Foreman::Thor module" - def uninstall(name) - raise Error, "Can't find module '#{name}'" unless thor_yaml[name] - say "Uninstalling #{name}." - FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s)) - - thor_yaml.delete(name) - save_yaml(thor_yaml) - - puts "Done." - end - - desc "update NAME", "Update a Foreman::Thor file from its original location" - def update(name) - raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location] - - say "Updating '#{name}' from #{thor_yaml[name][:location]}" - - old_filename = thor_yaml[name][:filename] - self.options = options.merge("as" => name) - - if File.directory? File.expand_path(name) - FileUtils.rm_rf(File.join(thor_root, old_filename)) - - thor_yaml.delete(old_filename) - save_yaml(thor_yaml) - - filename = install(name) - else - filename = install(thor_yaml[name][:location]) - end - - File.delete(File.join(thor_root, old_filename)) unless filename == old_filename - end - - desc "installed", "List the installed Foreman::Thor modules and commands" - method_options :internal => :boolean - def installed - initialize_thorfiles(nil, true) - display_klasses(true, options["internal"]) - end - - desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)" - method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean - def list(search = "") - initialize_thorfiles - - search = ".*#{search}" if options["substring"] - search = /^#{search}.*/i - group = options[:group] || "standard" - - klasses = Foreman::Thor::Base.subclasses.select do |k| - (options[:all] || k.group == group) && k.namespace =~ search - end - - display_klasses(false, false, klasses) - end - -private - - def thor_root - Foreman::Thor::Util.thor_root - end - - def thor_yaml - @thor_yaml ||= begin - yaml_file = File.join(thor_root, "thor.yml") - yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file) - yaml || {} - end - end - - # Save the yaml file. If none exists in thor root, creates one. - # - def save_yaml(yaml) - yaml_file = File.join(thor_root, "thor.yml") - - unless File.exist?(yaml_file) - FileUtils.mkdir_p(thor_root) - yaml_file = File.join(thor_root, "thor.yml") - FileUtils.touch(yaml_file) - end - - File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml } - end - - # Load the Foreman::Thorfiles. If relevant_to is supplied, looks for specific files - # in the thor_root instead of loading them all. - # - # By default, it also traverses the current path until find Foreman::Thor files, as - # described in thorfiles. This look up can be skipped by supplying - # skip_lookup true. - # - def initialize_thorfiles(relevant_to = nil, skip_lookup = false) - thorfiles(relevant_to, skip_lookup).each do |f| - Foreman::Thor::Util.load_thorfile(f, nil, options[:debug]) unless Foreman::Thor::Base.subclass_files.keys.include?(File.expand_path(f)) - end - end - - # Finds Foreman::Thorfiles by traversing from your current directory down to the root - # directory of your system. If at any time we find a Foreman::Thor file, we stop. - # - # We also ensure that system-wide Foreman::Thorfiles are loaded first, so local - # Foreman::Thorfiles can override them. - # - # ==== Example - # - # If we start at /Users/wycats/dev/thor ... - # - # 1. /Users/wycats/dev/thor - # 2. /Users/wycats/dev - # 3. /Users/wycats <-- we find a Foreman::Thorfile here, so we stop - # - # Suppose we start at c:\Documents and Settings\james\dev\thor ... - # - # 1. c:\Documents and Settings\james\dev\thor - # 2. c:\Documents and Settings\james\dev - # 3. c:\Documents and Settings\james - # 4. c:\Documents and Settings - # 5. c:\ <-- no Foreman::Thorfiles found! - # - def thorfiles(relevant_to = nil, skip_lookup = false) - thorfiles = [] - - unless skip_lookup - Pathname.pwd.ascend do |path| - thorfiles = Foreman::Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten - break unless thorfiles.empty? - end - end - - files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Foreman::Thor::Util.thor_root_glob) - files += thorfiles - files -= ["#{thor_root}/thor.yml"] - - files.map! do |file| - File.directory?(file) ? File.join(file, "main.thor") : file - end - end - - # Load Foreman::Thorfiles relevant to the given method. If you provide "foo:bar" it - # will load all thor files in the thor.yaml that has "foo" e "foo:bar" - # namespaces registered. - # - def thorfiles_relevant_to(meth) - lookup = [meth, meth.split(":")[0...-1].join(":")] - - files = thor_yaml.select do |_, v| - v[:namespaces] && !(v[:namespaces] & lookup).empty? - end - - files.map { |_, v| File.join(thor_root, (v[:filename]).to_s) } - end - - # Display information about the given klasses. If with_module is given, - # it shows a table with information extracted from the yaml file. - # - def display_klasses(with_modules = false, show_internal = false, klasses = Foreman::Thor::Base.subclasses) - klasses -= [Foreman::Thor, Foreman::Thor::Runner, Foreman::Thor::Group] unless show_internal - - raise Error, "No Foreman::Thor commands available" if klasses.empty? - show_modules if with_modules && !thor_yaml.empty? - - list = Hash.new { |h, k| h[k] = [] } - groups = klasses.select { |k| k.ancestors.include?(Foreman::Thor::Group) } - - # Get classes which inherit from Foreman::Thor - (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) } - - # Get classes which inherit from Foreman::Thor::Base - groups.map! { |k| k.printable_commands(false).first } - list["root"] = groups - - # Order namespaces with default coming first - list = list.sort { |a, b| a[0].sub(/^default/, "") <=> b[0].sub(/^default/, "") } - list.each { |n, commands| display_commands(n, commands) unless commands.empty? } - end - - def display_commands(namespace, list) #:nodoc: - list.sort! { |a, b| a[0] <=> b[0] } - - say shell.set_color(namespace, :blue, true) - say "-" * namespace.size - - print_table(list, :truncate => true) - say - end - alias_method :display_tasks, :display_commands - - def show_modules #:nodoc: - info = [] - labels = %w(Modules Namespaces) - - info << labels - info << ["-" * labels[0].size, "-" * labels[1].size] - - thor_yaml.each do |name, hash| - info << [name, hash[:namespaces].join(", ")] - end - - print_table info - say "" - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/shell.rb b/lib/foreman/vendor/thor/lib/thor/shell.rb deleted file mode 100644 index 38ad8e11..00000000 --- a/lib/foreman/vendor/thor/lib/thor/shell.rb +++ /dev/null @@ -1,81 +0,0 @@ -require "rbconfig" - -class Foreman::Thor - module Base - class << self - attr_writer :shell - - # Returns the shell used in all Foreman::Thor classes. If you are in a Unix platform - # it will use a colored log, otherwise it will use a basic one without color. - # - def shell - @shell ||= if ENV["THOR_SHELL"] && !ENV["THOR_SHELL"].empty? - Foreman::Thor::Shell.const_get(ENV["THOR_SHELL"]) - elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"] - Foreman::Thor::Shell::Basic - else - Foreman::Thor::Shell::Color - end - end - end - end - - module Shell - SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width] - attr_writer :shell - - autoload :Basic, "foreman/vendor/thor/lib/thor/shell/basic" - autoload :Color, "foreman/vendor/thor/lib/thor/shell/color" - autoload :HTML, "foreman/vendor/thor/lib/thor/shell/html" - - # Add shell to initialize config values. - # - # ==== Configuration - # shell:: An instance of the shell to be used. - # - # ==== Examples - # - # class MyScript < Foreman::Thor - # argument :first, :type => :numeric - # end - # - # MyScript.new [1.0], { :foo => :bar }, :shell => Foreman::Thor::Shell::Basic.new - # - def initialize(args = [], options = {}, config = {}) - super - self.shell = config[:shell] - shell.base ||= self if shell.respond_to?(:base) - end - - # Holds the shell for the given Foreman::Thor instance. If no shell is given, - # it gets a default shell from Foreman::Thor::Base.shell. - def shell - @shell ||= Foreman::Thor::Base.shell.new - end - - # Common methods that are delegated to the shell. - SHELL_DELEGATED_METHODS.each do |method| - module_eval <<-METHOD, __FILE__, __LINE__ - def #{method}(*args,&block) - shell.#{method}(*args,&block) - end - METHOD - end - - # Yields the given block with padding. - def with_padding - shell.padding += 1 - yield - ensure - shell.padding -= 1 - end - - protected - - # Allow shell to be shared between invocations. - # - def _shared_configuration #:nodoc: - super.merge!(:shell => shell) - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/shell/basic.rb b/lib/foreman/vendor/thor/lib/thor/shell/basic.rb deleted file mode 100644 index 72f18e91..00000000 --- a/lib/foreman/vendor/thor/lib/thor/shell/basic.rb +++ /dev/null @@ -1,436 +0,0 @@ -require "tempfile" -require "io/console" if RUBY_VERSION > "1.9.2" - -class Foreman::Thor - module Shell - class Basic - attr_accessor :base - attr_reader :padding - - # Initialize base, mute and padding to nil. - # - def initialize #:nodoc: - @base = nil - @mute = false - @padding = 0 - @always_force = false - end - - # Mute everything that's inside given block - # - def mute - @mute = true - yield - ensure - @mute = false - end - - # Check if base is muted - # - def mute? - @mute - end - - # Sets the output padding, not allowing less than zero values. - # - def padding=(value) - @padding = [0, value].max - end - - # Sets the output padding while executing a block and resets it. - # - def indent(count = 1) - orig_padding = padding - self.padding = padding + count - yield - self.padding = orig_padding - end - - # Asks something to the user and receives a response. - # - # If asked to limit the correct responses, you can pass in an - # array of acceptable answers. If one of those is not supplied, - # they will be shown a message stating that one of those answers - # must be given and re-asked the question. - # - # If asking for sensitive information, the :echo option can be set - # to false to mask user input from $stdin. - # - # If the required input is a path, then set the path option to - # true. This will enable tab completion for file paths relative - # to the current working directory on systems that support - # Readline. - # - # ==== Example - # ask("What is your name?") - # - # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"]) - # - # ask("What is your password?", :echo => false) - # - # ask("Where should the file be saved?", :path => true) - # - def ask(statement, *args) - options = args.last.is_a?(Hash) ? args.pop : {} - color = args.first - - if options[:limited_to] - ask_filtered(statement, color, options) - else - ask_simply(statement, color, options) - end - end - - # Say (print) something to the user. If the sentence ends with a whitespace - # or tab character, a new line is not appended (print + flush). Otherwise - # are passed straight to puts (behavior got from Highline). - # - # ==== Example - # say("I know you knew that.") - # - def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/)) - buffer = prepare_message(message, *color) - buffer << "\n" if force_new_line && !message.to_s.end_with?("\n") - - stdout.print(buffer) - stdout.flush - end - - # Say a status with the given color and appends the message. Since this - # method is used frequently by actions, it allows nil or false to be given - # in log_status, avoiding the message from being shown. If a Symbol is - # given in log_status, it's used as the color. - # - def say_status(status, message, log_status = true) - return if quiet? || log_status == false - spaces = " " * (padding + 1) - color = log_status.is_a?(Symbol) ? log_status : :green - - status = status.to_s.rjust(12) - status = set_color status, color, true if color - - buffer = "#{status}#{spaces}#{message}" - buffer << "\n" unless buffer.end_with?("\n") - - stdout.print(buffer) - stdout.flush - end - - # Make a question the to user and returns true if the user replies "y" or - # "yes". - # - def yes?(statement, color = nil) - !!(ask(statement, color, :add_to_history => false) =~ is?(:yes)) - end - - # Make a question the to user and returns true if the user replies "n" or - # "no". - # - def no?(statement, color = nil) - !!(ask(statement, color, :add_to_history => false) =~ is?(:no)) - end - - # Prints values in columns - # - # ==== Parameters - # Array[String, String, ...] - # - def print_in_columns(array) - return if array.empty? - colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2 - array.each_with_index do |value, index| - # Don't output trailing spaces when printing the last column - if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length - stdout.puts value - else - stdout.printf("%-#{colwidth}s", value) - end - end - end - - # Prints a table. - # - # ==== Parameters - # Array[Array[String, String, ...]] - # - # ==== Options - # indent:: Indent the first column by indent value. - # colwidth:: Force the first column to colwidth spaces wide. - # - def print_table(array, options = {}) # rubocop:disable MethodLength - return if array.empty? - - formats = [] - indent = options[:indent].to_i - colwidth = options[:colwidth] - options[:truncate] = terminal_width if options[:truncate] == true - - formats << "%-#{colwidth + 2}s" if colwidth - start = colwidth ? 1 : 0 - - colcount = array.max { |a, b| a.size <=> b.size }.size - - maximas = [] - - start.upto(colcount - 1) do |index| - maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max - maximas << maxima - formats << if index == colcount - 1 - # Don't output 2 trailing spaces when printing the last column - "%-s" - else - "%-#{maxima + 2}s" - end - end - - formats[0] = formats[0].insert(0, " " * indent) - formats << "%s" - - array.each do |row| - sentence = "" - - row.each_with_index do |column, index| - maxima = maximas[index] - - f = if column.is_a?(Numeric) - if index == row.size - 1 - # Don't output 2 trailing spaces when printing the last column - "%#{maxima}s" - else - "%#{maxima}s " - end - else - formats[index] - end - sentence << f % column.to_s - end - - sentence = truncate(sentence, options[:truncate]) if options[:truncate] - stdout.puts sentence - end - end - - # Prints a long string, word-wrapping the text to the current width of the - # terminal display. Ideal for printing heredocs. - # - # ==== Parameters - # String - # - # ==== Options - # indent:: Indent each line of the printed paragraph by indent value. - # - def print_wrapped(message, options = {}) - indent = options[:indent] || 0 - width = terminal_width - indent - paras = message.split("\n\n") - - paras.map! do |unwrapped| - unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") } - end - - paras.each do |para| - para.split("\n").each do |line| - stdout.puts line.insert(0, " " * indent) - end - stdout.puts unless para == paras.last - end - end - - # Deals with file collision and returns true if the file should be - # overwritten and false otherwise. If a block is given, it uses the block - # response as the content for the diff. - # - # ==== Parameters - # destination:: the destination file to solve conflicts - # block:: an optional block that returns the value to be used in diff - # - def file_collision(destination) - return true if @always_force - options = block_given? ? "[Ynaqdh]" : "[Ynaqh]" - - loop do - answer = ask( - %[Overwrite #{destination}? (enter "h" for help) #{options}], - :add_to_history => false - ) - - case answer - when is?(:yes), is?(:force), "" - return true - when is?(:no), is?(:skip) - return false - when is?(:always) - return @always_force = true - when is?(:quit) - say "Aborting..." - raise SystemExit - when is?(:diff) - show_diff(destination, yield) if block_given? - say "Retrying..." - else - say file_collision_help - end - end - end - - # This code was copied from Rake, available under MIT-LICENSE - # Copyright (c) 2003, 2004 Jim Weirich - def terminal_width - result = if ENV["THOR_COLUMNS"] - ENV["THOR_COLUMNS"].to_i - else - unix? ? dynamic_width : 80 - end - result < 10 ? 80 : result - rescue - 80 - end - - # Called if something goes wrong during the execution. This is used by Foreman::Thor - # internally and should not be used inside your scripts. If something went - # wrong, you can always raise an exception. If you raise a Foreman::Thor::Error, it - # will be rescued and wrapped in the method below. - # - def error(statement) - stderr.puts statement - end - - # Apply color to the given string with optional bold. Disabled in the - # Foreman::Thor::Shell::Basic class. - # - def set_color(string, *) #:nodoc: - string - end - - protected - - def prepare_message(message, *color) - spaces = " " * padding - spaces + set_color(message.to_s, *color) - end - - def can_display_colors? - false - end - - def lookup_color(color) - return color unless color.is_a?(Symbol) - self.class.const_get(color.to_s.upcase) - end - - def stdout - $stdout - end - - def stderr - $stderr - end - - def is?(value) #:nodoc: - value = value.to_s - - if value.size == 1 - /\A#{value}\z/i - else - /\A(#{value}|#{value[0, 1]})\z/i - end - end - - def file_collision_help #:nodoc: - <<-HELP - Y - yes, overwrite - n - no, do not overwrite - a - all, overwrite this and all others - q - quit, abort - d - diff, show the differences between the old and the new - h - help, show this help - HELP - end - - def show_diff(destination, content) #:nodoc: - diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u" - - Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp| - temp.write content - temp.rewind - system %(#{diff_cmd} "#{destination}" "#{temp.path}") - end - end - - def quiet? #:nodoc: - mute? || (base && base.options[:quiet]) - end - - # Calculate the dynamic width of the terminal - def dynamic_width - @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) - end - - def dynamic_width_stty - `stty size 2>/dev/null`.split[1].to_i - end - - def dynamic_width_tput - `tput cols 2>/dev/null`.to_i - end - - def unix? - RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i - end - - def truncate(string, width) - as_unicode do - chars = string.chars.to_a - if chars.length <= width - chars.join - else - chars[0, width - 3].join + "..." - end - end - end - - if "".respond_to?(:encode) - def as_unicode - yield - end - else - def as_unicode - old = $KCODE - $KCODE = "U" - yield - ensure - $KCODE = old - end - end - - def ask_simply(statement, color, options) - default = options[:default] - message = [statement, ("(#{default})" if default), nil].uniq.join(" ") - message = prepare_message(message, *color) - result = Foreman::Thor::LineEditor.readline(message, options) - - return unless result - - result.strip! - - if default && result == "" - default - else - result - end - end - - def ask_filtered(statement, color, options) - answer_set = options[:limited_to] - correct_answer = nil - until correct_answer - answers = answer_set.join(", ") - answer = ask_simply("#{statement} [#{answers}]", color, options) - correct_answer = answer_set.include?(answer) ? answer : nil - say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer - end - correct_answer - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/shell/color.rb b/lib/foreman/vendor/thor/lib/thor/shell/color.rb deleted file mode 100644 index b3597c0f..00000000 --- a/lib/foreman/vendor/thor/lib/thor/shell/color.rb +++ /dev/null @@ -1,149 +0,0 @@ -require "foreman/vendor/thor/lib/thor/shell/basic" - -class Foreman::Thor - module Shell - # Inherit from Foreman::Thor::Shell::Basic and add set_color behavior. Check - # Foreman::Thor::Shell::Basic to see all available methods. - # - class Color < Basic - # Embed in a String to clear all previous ANSI sequences. - CLEAR = "\e[0m" - # The start of an ANSI bold sequence. - BOLD = "\e[1m" - - # Set the terminal's foreground ANSI color to black. - BLACK = "\e[30m" - # Set the terminal's foreground ANSI color to red. - RED = "\e[31m" - # Set the terminal's foreground ANSI color to green. - GREEN = "\e[32m" - # Set the terminal's foreground ANSI color to yellow. - YELLOW = "\e[33m" - # Set the terminal's foreground ANSI color to blue. - BLUE = "\e[34m" - # Set the terminal's foreground ANSI color to magenta. - MAGENTA = "\e[35m" - # Set the terminal's foreground ANSI color to cyan. - CYAN = "\e[36m" - # Set the terminal's foreground ANSI color to white. - WHITE = "\e[37m" - - # Set the terminal's background ANSI color to black. - ON_BLACK = "\e[40m" - # Set the terminal's background ANSI color to red. - ON_RED = "\e[41m" - # Set the terminal's background ANSI color to green. - ON_GREEN = "\e[42m" - # Set the terminal's background ANSI color to yellow. - ON_YELLOW = "\e[43m" - # Set the terminal's background ANSI color to blue. - ON_BLUE = "\e[44m" - # Set the terminal's background ANSI color to magenta. - ON_MAGENTA = "\e[45m" - # Set the terminal's background ANSI color to cyan. - ON_CYAN = "\e[46m" - # Set the terminal's background ANSI color to white. - ON_WHITE = "\e[47m" - - # Set color by using a string or one of the defined constants. If a third - # option is set to true, it also adds bold to the string. This is based - # on Highline implementation and it automatically appends CLEAR to the end - # of the returned String. - # - # Pass foreground, background and bold options to this method as - # symbols. - # - # Example: - # - # set_color "Hi!", :red, :on_white, :bold - # - # The available colors are: - # - # :bold - # :black - # :red - # :green - # :yellow - # :blue - # :magenta - # :cyan - # :white - # :on_black - # :on_red - # :on_green - # :on_yellow - # :on_blue - # :on_magenta - # :on_cyan - # :on_white - def set_color(string, *colors) - if colors.compact.empty? || !can_display_colors? - string - elsif colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } - ansi_colors = colors.map { |color| lookup_color(color) } - "#{ansi_colors.join}#{string}#{CLEAR}" - else - # The old API was `set_color(color, bold=boolean)`. We - # continue to support the old API because you should never - # break old APIs unnecessarily :P - foreground, bold = colors - foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol) - - bold = bold ? BOLD : "" - "#{bold}#{foreground}#{string}#{CLEAR}" - end - end - - protected - - def can_display_colors? - stdout.tty? - end - - # Overwrite show_diff to show diff with colors if Diff::LCS is - # available. - # - def show_diff(destination, content) #:nodoc: - if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? - actual = File.binread(destination).to_s.split("\n") - content = content.to_s.split("\n") - - Diff::LCS.sdiff(actual, content).each do |diff| - output_diff_line(diff) - end - else - super - end - end - - def output_diff_line(diff) #:nodoc: - case diff.action - when "-" - say "- #{diff.old_element.chomp}", :red, true - when "+" - say "+ #{diff.new_element.chomp}", :green, true - when "!" - say "- #{diff.old_element.chomp}", :red, true - say "+ #{diff.new_element.chomp}", :green, true - else - say " #{diff.old_element.chomp}", nil, true - end - end - - # Check if Diff::LCS is loaded. If it is, use it to create pretty output - # for diff. - # - def diff_lcs_loaded? #:nodoc: - return true if defined?(Diff::LCS) - return @diff_lcs_loaded unless @diff_lcs_loaded.nil? - - @diff_lcs_loaded = begin - require "diff/lcs" - true - rescue LoadError - false - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/shell/html.rb b/lib/foreman/vendor/thor/lib/thor/shell/html.rb deleted file mode 100644 index 5c5a1ef2..00000000 --- a/lib/foreman/vendor/thor/lib/thor/shell/html.rb +++ /dev/null @@ -1,126 +0,0 @@ -require "foreman/vendor/thor/lib/thor/shell/basic" - -class Foreman::Thor - module Shell - # Inherit from Foreman::Thor::Shell::Basic and add set_color behavior. Check - # Foreman::Thor::Shell::Basic to see all available methods. - # - class HTML < Basic - # The start of an HTML bold sequence. - BOLD = "font-weight: bold" - - # Set the terminal's foreground HTML color to black. - BLACK = "color: black" - # Set the terminal's foreground HTML color to red. - RED = "color: red" - # Set the terminal's foreground HTML color to green. - GREEN = "color: green" - # Set the terminal's foreground HTML color to yellow. - YELLOW = "color: yellow" - # Set the terminal's foreground HTML color to blue. - BLUE = "color: blue" - # Set the terminal's foreground HTML color to magenta. - MAGENTA = "color: magenta" - # Set the terminal's foreground HTML color to cyan. - CYAN = "color: cyan" - # Set the terminal's foreground HTML color to white. - WHITE = "color: white" - - # Set the terminal's background HTML color to black. - ON_BLACK = "background-color: black" - # Set the terminal's background HTML color to red. - ON_RED = "background-color: red" - # Set the terminal's background HTML color to green. - ON_GREEN = "background-color: green" - # Set the terminal's background HTML color to yellow. - ON_YELLOW = "background-color: yellow" - # Set the terminal's background HTML color to blue. - ON_BLUE = "background-color: blue" - # Set the terminal's background HTML color to magenta. - ON_MAGENTA = "background-color: magenta" - # Set the terminal's background HTML color to cyan. - ON_CYAN = "background-color: cyan" - # Set the terminal's background HTML color to white. - ON_WHITE = "background-color: white" - - # Set color by using a string or one of the defined constants. If a third - # option is set to true, it also adds bold to the string. This is based - # on Highline implementation and it automatically appends CLEAR to the end - # of the returned String. - # - def set_color(string, *colors) - if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) } - html_colors = colors.map { |color| lookup_color(color) } - "#{string}" - else - color, bold = colors - html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) - styles = [html_color] - styles << BOLD if bold - "#{string}" - end - end - - # Ask something to the user and receives a response. - # - # ==== Example - # ask("What is your name?") - # - # TODO: Implement #ask for Foreman::Thor::Shell::HTML - def ask(statement, color = nil) - raise NotImplementedError, "Implement #ask for Foreman::Thor::Shell::HTML" - end - - protected - - def can_display_colors? - true - end - - # Overwrite show_diff to show diff with colors if Diff::LCS is - # available. - # - def show_diff(destination, content) #:nodoc: - if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil? - actual = File.binread(destination).to_s.split("\n") - content = content.to_s.split("\n") - - Diff::LCS.sdiff(actual, content).each do |diff| - output_diff_line(diff) - end - else - super - end - end - - def output_diff_line(diff) #:nodoc: - case diff.action - when "-" - say "- #{diff.old_element.chomp}", :red, true - when "+" - say "+ #{diff.new_element.chomp}", :green, true - when "!" - say "- #{diff.old_element.chomp}", :red, true - say "+ #{diff.new_element.chomp}", :green, true - else - say " #{diff.old_element.chomp}", nil, true - end - end - - # Check if Diff::LCS is loaded. If it is, use it to create pretty output - # for diff. - # - def diff_lcs_loaded? #:nodoc: - return true if defined?(Diff::LCS) - return @diff_lcs_loaded unless @diff_lcs_loaded.nil? - - @diff_lcs_loaded = begin - require "diff/lcs" - true - rescue LoadError - false - end - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/util.rb b/lib/foreman/vendor/thor/lib/thor/util.rb deleted file mode 100644 index b5e5593a..00000000 --- a/lib/foreman/vendor/thor/lib/thor/util.rb +++ /dev/null @@ -1,268 +0,0 @@ -require "rbconfig" - -class Foreman::Thor - module Sandbox #:nodoc: - end - - # This module holds several utilities: - # - # 1) Methods to convert thor namespaces to constants and vice-versa. - # - # Foreman::Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz" - # - # 2) Loading thor files and sandboxing: - # - # Foreman::Thor::Util.load_thorfile("~/.thor/foo") - # - module Util - class << self - # Receives a namespace and search for it in the Foreman::Thor::Base subclasses. - # - # ==== Parameters - # namespace:: The namespace to search for. - # - def find_by_namespace(namespace) - namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/ - Foreman::Thor::Base.subclasses.detect { |klass| klass.namespace == namespace } - end - - # Receives a constant and converts it to a Foreman::Thor namespace. Since Foreman::Thor - # commands can be added to a sandbox, this method is also responsable for - # removing the sandbox namespace. - # - # This method should not be used in general because it's used to deal with - # older versions of Foreman::Thor. On current versions, if you need to get the - # namespace from a class, just call namespace on it. - # - # ==== Parameters - # constant:: The constant to be converted to the thor path. - # - # ==== Returns - # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz" - # - def namespace_from_thor_class(constant) - constant = constant.to_s.gsub(/^Foreman::Thor::Sandbox::/, "") - constant = snake_case(constant).squeeze(":") - constant - end - - # Given the contents, evaluate it inside the sandbox and returns the - # namespaces defined in the sandbox. - # - # ==== Parameters - # contents - # - # ==== Returns - # Array[Object] - # - def namespaces_in_content(contents, file = __FILE__) - old_constants = Foreman::Thor::Base.subclasses.dup - Foreman::Thor::Base.subclasses.clear - - load_thorfile(file, contents) - - new_constants = Foreman::Thor::Base.subclasses.dup - Foreman::Thor::Base.subclasses.replace(old_constants) - - new_constants.map!(&:namespace) - new_constants.compact! - new_constants - end - - # Returns the thor classes declared inside the given class. - # - def thor_classes_in(klass) - stringfied_constants = klass.constants.map(&:to_s) - Foreman::Thor::Base.subclasses.select do |subclass| - next unless subclass.name - stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", "")) - end - end - - # Receives a string and convert it to snake case. SnakeCase returns snake_case. - # - # ==== Parameters - # String - # - # ==== Returns - # String - # - def snake_case(str) - return str.downcase if str =~ /^[A-Z_]+$/ - str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/ - $+.downcase - end - - # Receives a string and convert it to camel case. camel_case returns CamelCase. - # - # ==== Parameters - # String - # - # ==== Returns - # String - # - def camel_case(str) - return str if str !~ /_/ && str =~ /[A-Z]+.*/ - str.split("_").map(&:capitalize).join - end - - # Receives a namespace and tries to retrieve a Foreman::Thor or Foreman::Thor::Group class - # from it. It first searches for a class using the all the given namespace, - # if it's not found, removes the highest entry and searches for the class - # again. If found, returns the highest entry as the class name. - # - # ==== Examples - # - # class Foo::Bar < Foreman::Thor - # def baz - # end - # end - # - # class Baz::Foo < Foreman::Thor::Group - # end - # - # Foreman::Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command - # Foreman::Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil - # Foreman::Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz" - # - # ==== Parameters - # namespace - # - def find_class_and_command_by_namespace(namespace, fallback = true) - if namespace.include?(":") # look for a namespaced command - pieces = namespace.split(":") - command = pieces.pop - klass = Foreman::Thor::Util.find_by_namespace(pieces.join(":")) - end - unless klass # look for a Foreman::Thor::Group with the right name - klass = Foreman::Thor::Util.find_by_namespace(namespace) - command = nil - end - if !klass && fallback # try a command in the default namespace - command = namespace - klass = Foreman::Thor::Util.find_by_namespace("") - end - [klass, command] - end - alias_method :find_class_and_task_by_namespace, :find_class_and_command_by_namespace - - # Receives a path and load the thor file in the path. The file is evaluated - # inside the sandbox to avoid namespacing conflicts. - # - def load_thorfile(path, content = nil, debug = false) - content ||= File.binread(path) - - begin - Foreman::Thor::Sandbox.class_eval(content, path) - rescue StandardError => e - $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}") - if debug - $stderr.puts(*e.backtrace) - else - $stderr.puts(e.backtrace.first) - end - end - end - - def user_home - @@user_home ||= if ENV["HOME"] - ENV["HOME"] - elsif ENV["USERPROFILE"] - ENV["USERPROFILE"] - elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"] - File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"]) - elsif ENV["APPDATA"] - ENV["APPDATA"] - else - begin - File.expand_path("~") - rescue - if File::ALT_SEPARATOR - "C:/" - else - "/" - end - end - end - end - - # Returns the root where thor files are located, depending on the OS. - # - def thor_root - File.join(user_home, ".thor").tr('\\', "/") - end - - # Returns the files in the thor root. On Windows thor_root will be something - # like this: - # - # C:\Documents and Settings\james\.thor - # - # If we don't #gsub the \ character, Dir.glob will fail. - # - def thor_root_glob - files = Dir["#{escape_globs(thor_root)}/*"] - - files.map! do |file| - File.directory?(file) ? File.join(file, "main.thor") : file - end - end - - # Where to look for Foreman::Thor files. - # - def globs_for(path) - path = escape_globs(path) - ["#{path}/Foreman::Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"] - end - - # Return the path to the ruby interpreter taking into account multiple - # installations and windows extensions. - # - def ruby_command - @ruby_command ||= begin - ruby_name = RbConfig::CONFIG["ruby_install_name"] - ruby = File.join(RbConfig::CONFIG["bindir"], ruby_name) - ruby << RbConfig::CONFIG["EXEEXT"] - - # avoid using different name than ruby (on platforms supporting links) - if ruby_name != "ruby" && File.respond_to?(:readlink) - begin - alternate_ruby = File.join(RbConfig::CONFIG["bindir"], "ruby") - alternate_ruby << RbConfig::CONFIG["EXEEXT"] - - # ruby is a symlink - if File.symlink? alternate_ruby - linked_ruby = File.readlink alternate_ruby - - # symlink points to 'ruby_install_name' - ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby - end - rescue NotImplementedError # rubocop:disable HandleExceptions - # just ignore on windows - end - end - - # escape string in case path to ruby executable contain spaces. - ruby.sub!(/.*\s.*/m, '"\&"') - ruby - end - end - - # Returns a string that has had any glob characters escaped. - # The glob characters are `* ? { } [ ]`. - # - # ==== Examples - # - # Foreman::Thor::Util.escape_globs('[apps]') # => '\[apps\]' - # - # ==== Parameters - # String - # - # ==== Returns - # String - # - def escape_globs(path) - path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&') - end - end - end -end diff --git a/lib/foreman/vendor/thor/lib/thor/version.rb b/lib/foreman/vendor/thor/lib/thor/version.rb deleted file mode 100644 index 2538d944..00000000 --- a/lib/foreman/vendor/thor/lib/thor/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Foreman::Thor - VERSION = "0.19.4" -end diff --git a/lib/foreman/version.rb b/lib/foreman/version.rb index 326c530b..5abdfc97 100644 --- a/lib/foreman/version.rb +++ b/lib/foreman/version.rb @@ -1,5 +1,3 @@ module Foreman - VERSION = "0.88.1" - end diff --git a/spec/foreman/cli_spec.rb b/spec/foreman/cli_spec.rb index 4995a481..b7924b90 100644 --- a/spec/foreman/cli_spec.rb +++ b/spec/foreman/cli_spec.rb @@ -12,7 +12,7 @@ end it "is overridden by options at the cli" do - subject = Foreman::CLI.new([], :formation => "alpha=3") + subject = Foreman::CLI.new([], formation: "alpha=3") expect(subject.send(:options)["formation"]).to eq("alpha=3") end end @@ -21,7 +21,7 @@ describe "when a Procfile doesnt exist", :fakefs do it "displays an error" do mock_error(subject, "Procfile does not exist.") do - expect_any_instance_of(Foreman::Engine).to_not receive(:start) + expect_any_instance_of(Foreman::Engine).not_to receive(:start) subject.start end end @@ -31,7 +31,7 @@ it "can run a single command" do without_fakefs do output = foreman("start env -f #{resource_path("Procfile")}") - expect(output).to match(/env.1/) + expect(output).to match(/env.1/) expect(output).not_to match(/test.1/) end end @@ -54,7 +54,7 @@ it "fails if process fails" do output = `bundle exec foreman start -f #{resource_path "Procfile.bad"} && echo success` - expect(output).not_to include 'success' + expect(output).not_to include "success" end end end @@ -107,5 +107,4 @@ expect(foreman("-v").chomp).to eq(Foreman::VERSION) end end - end diff --git a/spec/foreman/engine_spec.rb b/spec/foreman/engine_spec.rb index 060b9638..588249c9 100644 --- a/spec/foreman/engine_spec.rb +++ b/spec/foreman/engine_spec.rb @@ -45,7 +45,7 @@ def shutdown it "handles concurrency" do subject.options[:formation] = "alpha=2" expect(subject.process("alpha")).to receive(:run).twice - expect(subject.process("bravo")).to_not receive(:run) + expect(subject.process("bravo")).not_to receive(:run) expect(subject).to receive(:watch_for_output) expect(subject).to receive(:wait_for_shutdown_or_child_termination) subject.start @@ -61,13 +61,13 @@ def shutdown end describe "environment" do - it "should read env files" do + it "reads env files" do write_file("/tmp/env") { |f| f.puts("FOO=baz") } subject.load_env("/tmp/env") expect(subject.env["FOO"]).to eq("baz") end - it "should read more than one if specified" do + it "reads more than one if specified" do write_file("/tmp/env1") { |f| f.puts("FOO=bar") } write_file("/tmp/env2") { |f| f.puts("BAZ=qux") } subject.load_env "/tmp/env1" @@ -76,23 +76,23 @@ def shutdown expect(subject.env["BAZ"]).to eq("qux") end - it "should handle quoted values" do + it "handles quoted values" do write_file("/tmp/env") do |f| - f.puts 'FOO=bar' + f.puts "FOO=bar" f.puts 'BAZ="qux"' f.puts "FRED='barney'" f.puts 'OTHER="escaped\"quote"' f.puts 'URL="http://example.com/api?foo=bar&baz=1"' end subject.load_env "/tmp/env" - expect(subject.env["FOO"]).to eq("bar") - expect(subject.env["BAZ"]).to eq("qux") - expect(subject.env["FRED"]).to eq("barney") + expect(subject.env["FOO"]).to eq("bar") + expect(subject.env["BAZ"]).to eq("qux") + expect(subject.env["FRED"]).to eq("barney") expect(subject.env["OTHER"]).to eq('escaped"quote') - expect(subject.env["URL"]).to eq("http://example.com/api?foo=bar&baz=1") + expect(subject.env["URL"]).to eq("http://example.com/api?foo=bar&baz=1") end - it "should handle multiline strings" do + it "handles multiline strings" do write_file("/tmp/env") do |f| f.puts 'FOO="bar\nbaz"' end @@ -100,15 +100,14 @@ def shutdown expect(subject.env["FOO"]).to eq("bar\nbaz") end - it "should fail if specified and doesnt exist" do + it "fails if specified and doesnt exist" do expect { subject.load_env "/tmp/env" }.to raise_error(Errno::ENOENT) end - it "should set port from .env if specified" do + it "sets port from .env if specified" do write_file("/tmp/env") { |f| f.puts("PORT=9000") } subject.load_env "/tmp/env" expect(subject.send(:base_port)).to eq(9000) end end - end diff --git a/spec/foreman/export/base_spec.rb b/spec/foreman/export/base_spec.rb index 3add2964..e40ac53c 100644 --- a/spec/foreman/export/base_spec.rb +++ b/spec/foreman/export/base_spec.rb @@ -3,10 +3,13 @@ require "foreman/export" describe "Foreman::Export::Base", :fakefs do - let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") } + let(:procfile) { + FileUtils.mkdir_p("/tmp/app") + write_procfile("/tmp/app/Procfile") + } let(:location) { "/tmp/init" } - let(:engine) { Foreman::Engine.new().load_procfile(procfile) } - let(:subject) { Foreman::Export::Base.new(location, engine) } + let(:engine) { Foreman::Engine.new.load_procfile(procfile) } + let(:subject) { Foreman::Export::Base.new(location, engine) } it "has a say method for displaying info" do expect(subject).to receive(:puts).with("[foreman export] foo") diff --git a/spec/foreman/export/bluepill_spec.rb b/spec/foreman/export/bluepill_spec.rb index 284226ad..f9493868 100644 --- a/spec/foreman/export/bluepill_spec.rb +++ b/spec/foreman/export/bluepill_spec.rb @@ -4,14 +4,19 @@ require "tmpdir" describe Foreman::Export::Bluepill, :fakefs do - let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") } + let(:procfile) { + FileUtils.mkdir_p("/tmp/app") + write_procfile("/tmp/app/Procfile") + } let(:formation) { nil } - let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) } - let(:options) { Hash.new } - let(:bluepill) { Foreman::Export::Bluepill.new("/tmp/init", engine, options) } + let(:engine) { Foreman::Engine.new(formation: formation).load_procfile(procfile) } + let(:options) { {} } + let(:bluepill) { Foreman::Export::Bluepill.new("/tmp/init", engine, options) } - before(:each) { load_export_templates_into_fakefs("bluepill") } - before(:each) { allow(bluepill).to receive(:say) } + before { + load_export_templates_into_fakefs("bluepill") + allow(bluepill).to receive(:say) + } it "exports to the filesystem" do bluepill.export @@ -33,5 +38,4 @@ expect(normalize_space(File.read("/tmp/init/app.pill"))).to eq(normalize_space(example_export_file("bluepill/app-concurrency.pill"))) end end - end diff --git a/spec/foreman/export/daemon_spec.rb b/spec/foreman/export/daemon_spec.rb index 112784a0..faed1ce1 100644 --- a/spec/foreman/export/daemon_spec.rb +++ b/spec/foreman/export/daemon_spec.rb @@ -4,22 +4,24 @@ require "tmpdir" describe Foreman::Export::Daemon, :fakefs do - let(:procfile) { write_procfile("/tmp/app/Procfile") } + let(:procfile) { write_procfile("/tmp/app/Procfile") } let(:formation) { nil } - let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) } - let(:options) { Hash.new } - let(:daemon) { Foreman::Export::Daemon.new("/tmp/init", engine, options) } + let(:engine) { Foreman::Engine.new(formation: formation).load_procfile(procfile) } + let(:options) { {} } + let(:daemon) { Foreman::Export::Daemon.new("/tmp/init", engine, options) } - before(:each) { load_export_templates_into_fakefs("daemon") } - before(:each) { allow(daemon).to receive(:say) } + before { + load_export_templates_into_fakefs("daemon") + allow(daemon).to receive(:say) + } it "exports to the filesystem" do daemon.export - expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("daemon/app.conf")) - expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("daemon/app-alpha.conf")) + expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("daemon/app.conf")) + expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("daemon/app-alpha.conf")) expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("daemon/app-alpha-1.conf")) - expect(File.read("/tmp/init/app-bravo.conf")).to eq(example_export_file("daemon/app-bravo.conf")) + expect(File.read("/tmp/init/app-bravo.conf")).to eq(example_export_file("daemon/app-bravo.conf")) expect(File.read("/tmp/init/app-bravo-1.conf")).to eq(example_export_file("daemon/app-bravo-1.conf")) end @@ -44,7 +46,7 @@ ["app2", "app2-alpha", "app2-alpha-1"].each do |name| path = "/tmp/init/#{name}.conf" FileUtils.touch(path) - expect(FileUtils).to_not receive(:rm).with(path) + expect(FileUtils).not_to receive(:rm).with(path) end daemon.export @@ -56,17 +58,17 @@ it "exports to the filesystem with concurrency" do daemon.export - expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("daemon/app.conf")) - expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("daemon/app-alpha.conf")) - expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("daemon/app-alpha-1.conf")) - expect(File.read("/tmp/init/app-alpha-2.conf")).to eq(example_export_file("daemon/app-alpha-2.conf")) + expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("daemon/app.conf")) + expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("daemon/app-alpha.conf")) + expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("daemon/app-alpha-1.conf")) + expect(File.read("/tmp/init/app-alpha-2.conf")).to eq(example_export_file("daemon/app-alpha-2.conf")) expect(File.exist?("/tmp/init/app-bravo-1.conf")).to eq(false) end end context "with alternate templates" do let(:template) { "/tmp/alternate" } - let(:options) { { :app => "app", :template => template } } + let(:options) { {app: "app", template: template} } before do FileUtils.mkdir_p template @@ -80,7 +82,6 @@ end context "with alternate templates from home dir" do - before do FileUtils.mkdir_p File.expand_path("~/.foreman/templates/daemon") File.open(File.expand_path("~/.foreman/templates/daemon/master.conf.erb"), "w") do |file| @@ -93,5 +94,4 @@ expect(File.read("/tmp/init/app.conf")).to eq("default_alternate_template\n") end end - end diff --git a/spec/foreman/export/inittab_spec.rb b/spec/foreman/export/inittab_spec.rb index c097550e..10918479 100644 --- a/spec/foreman/export/inittab_spec.rb +++ b/spec/foreman/export/inittab_spec.rb @@ -4,15 +4,20 @@ require "tmpdir" describe Foreman::Export::Inittab, :fakefs do - let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") } - let(:location) { "/tmp/inittab" } + let(:procfile) { + FileUtils.mkdir_p("/tmp/app") + write_procfile("/tmp/app/Procfile") + } + let(:location) { "/tmp/inittab" } let(:formation) { nil } - let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) } - let(:options) { Hash.new } - let(:inittab) { Foreman::Export::Inittab.new(location, engine, options) } + let(:engine) { Foreman::Engine.new(formation: formation).load_procfile(procfile) } + let(:options) { {} } + let(:inittab) { Foreman::Export::Inittab.new(location, engine, options) } - before(:each) { load_export_templates_into_fakefs("inittab") } - before(:each) { allow(inittab).to receive(:say) } + before { + load_export_templates_into_fakefs("inittab") + allow(inittab).to receive(:say) + } it "exports to the filesystem" do inittab.export @@ -36,5 +41,4 @@ expect(File.read("/tmp/inittab")).to eq(example_export_file("inittab/inittab.concurrency")) end end - end diff --git a/spec/foreman/export/launchd_spec.rb b/spec/foreman/export/launchd_spec.rb index ee6c6638..2bffaea1 100644 --- a/spec/foreman/export/launchd_spec.rb +++ b/spec/foreman/export/launchd_spec.rb @@ -4,13 +4,18 @@ require "tmpdir" describe Foreman::Export::Launchd, :fakefs do - let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") } - let(:options) { Hash.new } - let(:engine) { Foreman::Engine.new().load_procfile(procfile) } - let(:launchd) { Foreman::Export::Launchd.new("/tmp/init", engine, options) } + let(:procfile) { + FileUtils.mkdir_p("/tmp/app") + write_procfile("/tmp/app/Procfile") + } + let(:options) { {} } + let(:engine) { Foreman::Engine.new.load_procfile(procfile) } + let(:launchd) { Foreman::Export::Launchd.new("/tmp/init", engine, options) } - before(:each) { load_export_templates_into_fakefs("launchd") } - before(:each) { allow(launchd).to receive(:say) } + before { + load_export_templates_into_fakefs("launchd") + allow(launchd).to receive(:say) + } it "exports to the filesystem" do launchd.export @@ -19,13 +24,14 @@ end context "with multiple command arguments" do - let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", "charlie") } + let(:procfile) { + FileUtils.mkdir_p("/tmp/app") + write_procfile("/tmp/app/Procfile", "charlie") + } it "splits each command argument" do launchd.export expect(File.read("/tmp/init/app-alpha-1.plist")).to eq(example_export_file("launchd/launchd-c.default")) end - end - end diff --git a/spec/foreman/export/runit_spec.rb b/spec/foreman/export/runit_spec.rb index 5fa12fa6..e3d7f450 100644 --- a/spec/foreman/export/runit_spec.rb +++ b/spec/foreman/export/runit_spec.rb @@ -4,33 +4,38 @@ require "tmpdir" describe Foreman::Export::Runit, :fakefs do - let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", 'bar=baz') } - let(:engine) { Foreman::Engine.new(:formation => "alpha=2,bravo=1").load_procfile(procfile) } - let(:options) { Hash.new } - let(:runit) { Foreman::Export::Runit.new('/tmp/init', engine, options) } + let(:procfile) { + FileUtils.mkdir_p("/tmp/app") + write_procfile("/tmp/app/Procfile", "bar=baz") + } + let(:engine) { Foreman::Engine.new(formation: "alpha=2,bravo=1").load_procfile(procfile) } + let(:options) { {} } + let(:runit) { Foreman::Export::Runit.new("/tmp/init", engine, options) } - before(:each) { load_export_templates_into_fakefs("runit") } - before(:each) { allow(runit).to receive(:say) } - before(:each) { allow(FakeFS::FileUtils).to receive(:chmod) } + before { + load_export_templates_into_fakefs("runit") + allow(runit).to receive(:say) + allow(FakeFS::FileUtils).to receive(:chmod) + } it "exports to the filesystem" do engine.env["BAR"] = "baz" runit.export - expect(File.read("/tmp/init/app-alpha-1/run")).to eq(example_export_file('runit/app-alpha-1/run')) - expect(File.read("/tmp/init/app-alpha-1/log/run")).to eq(example_export_file('runit/app-alpha-1/log/run')) + expect(File.read("/tmp/init/app-alpha-1/run")).to eq(example_export_file("runit/app-alpha-1/run")) + expect(File.read("/tmp/init/app-alpha-1/log/run")).to eq(example_export_file("runit/app-alpha-1/log/run")) expect(File.read("/tmp/init/app-alpha-1/env/PORT")).to eq("5000\n") - expect(File.read("/tmp/init/app-alpha-1/env/BAR")).to eq("baz\n") - expect(File.read("/tmp/init/app-alpha-2/run")).to eq(example_export_file('runit/app-alpha-2/run')) - expect(File.read("/tmp/init/app-alpha-2/log/run")).to eq(example_export_file('runit/app-alpha-2/log/run')) + expect(File.read("/tmp/init/app-alpha-1/env/BAR")).to eq("baz\n") + expect(File.read("/tmp/init/app-alpha-2/run")).to eq(example_export_file("runit/app-alpha-2/run")) + expect(File.read("/tmp/init/app-alpha-2/log/run")).to eq(example_export_file("runit/app-alpha-2/log/run")) expect(File.read("/tmp/init/app-alpha-2/env/PORT")).to eq("5001\n") - expect(File.read("/tmp/init/app-alpha-2/env/BAR")).to eq("baz\n") - expect(File.read("/tmp/init/app-bravo-1/run")).to eq(example_export_file('runit/app-bravo-1/run')) - expect(File.read("/tmp/init/app-bravo-1/log/run")).to eq(example_export_file('runit/app-bravo-1/log/run')) + expect(File.read("/tmp/init/app-alpha-2/env/BAR")).to eq("baz\n") + expect(File.read("/tmp/init/app-bravo-1/run")).to eq(example_export_file("runit/app-bravo-1/run")) + expect(File.read("/tmp/init/app-bravo-1/log/run")).to eq(example_export_file("runit/app-bravo-1/log/run")) expect(File.read("/tmp/init/app-bravo-1/env/PORT")).to eq("5100\n") end it "creates a full path to the export directory" do - expect { runit.export }.to_not raise_error + expect { runit.export }.not_to raise_error end end diff --git a/spec/foreman/export/supervisord_spec.rb b/spec/foreman/export/supervisord_spec.rb index 33355080..457a21a2 100644 --- a/spec/foreman/export/supervisord_spec.rb +++ b/spec/foreman/export/supervisord_spec.rb @@ -4,18 +4,23 @@ require "tmpdir" describe Foreman::Export::Supervisord, :fakefs do - let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") } - let(:formation) { nil } - let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) } - let(:options) { Hash.new } + let(:procfile) { + FileUtils.mkdir_p("/tmp/app") + write_procfile("/tmp/app/Procfile") + } + let(:formation) { nil } + let(:engine) { Foreman::Engine.new(formation: formation).load_procfile(procfile) } + let(:options) { {} } let(:supervisord) { Foreman::Export::Supervisord.new("/tmp/init", engine, options) } - before(:each) { load_export_templates_into_fakefs("supervisord") } - before(:each) { allow(supervisord).to receive(:say) } + before { + load_export_templates_into_fakefs("supervisord") + allow(supervisord).to receive(:say) + } it "exports to the filesystem" do - write_env(".env", "FOO"=>"bar", "URL"=>"http://example.com/api?foo=bar&baz=1") - supervisord.engine.load_env('.env') + write_env(".env", "FOO" => "bar", "URL" => "http://example.com/api?foo=bar&baz=1") + supervisord.engine.load_env(".env") supervisord.export expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("supervisord/app-alpha-1.conf")) end @@ -34,5 +39,4 @@ expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("supervisord/app-alpha-2.conf")) end end - end diff --git a/spec/foreman/export/systemd_spec.rb b/spec/foreman/export/systemd_spec.rb index b8ee190e..299efb46 100644 --- a/spec/foreman/export/systemd_spec.rb +++ b/spec/foreman/export/systemd_spec.rb @@ -3,15 +3,17 @@ require "foreman/export/systemd" require "tmpdir" -describe Foreman::Export::Systemd, :fakefs, :aggregate_failures do - let(:procfile) { write_procfile("/tmp/app/Procfile") } +describe Foreman::Export::Systemd, :aggregate_failures, :fakefs do + let(:procfile) { write_procfile("/tmp/app/Procfile") } let(:formation) { nil } - let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) } - let(:options) { Hash.new } - let(:systemd) { Foreman::Export::Systemd.new("/tmp/init", engine, options) } + let(:engine) { Foreman::Engine.new(formation: formation).load_procfile(procfile) } + let(:options) { {} } + let(:systemd) { Foreman::Export::Systemd.new("/tmp/init", engine, options) } - before(:each) { load_export_templates_into_fakefs("systemd") } - before(:each) { allow(systemd).to receive(:say) } + before { + load_export_templates_into_fakefs("systemd") + allow(systemd).to receive(:say) + } it "exports to the filesystem" do systemd.export @@ -23,23 +25,23 @@ context "when systemd export was run using the previous version of systemd export" do before do - write_file("/tmp/init/app.target") + write_file("/tmp/init/app.target") - write_file("/tmp/init/app-alpha@.service") - write_file("/tmp/init/app-alpha.target") - write_file("/tmp/init/app-alpha.target.wants/app-alpha@5000.service") + write_file("/tmp/init/app-alpha@.service") + write_file("/tmp/init/app-alpha.target") + write_file("/tmp/init/app-alpha.target.wants/app-alpha@5000.service") - write_file("/tmp/init/app-bravo.target") - write_file("/tmp/init/app-bravo@.service") - write_file("/tmp/init/app-bravo.target.wants/app-bravo@5100.service") + write_file("/tmp/init/app-bravo.target") + write_file("/tmp/init/app-bravo@.service") + write_file("/tmp/init/app-bravo.target.wants/app-bravo@5100.service") - write_file("/tmp/init/app-foo_bar.target") - write_file("/tmp/init/app-foo_bar@.service") - write_file("/tmp/init/app-foo_bar.target.wants/app-foo_bar@5200.service") + write_file("/tmp/init/app-foo_bar.target") + write_file("/tmp/init/app-foo_bar@.service") + write_file("/tmp/init/app-foo_bar.target.wants/app-foo_bar@5200.service") - write_file("/tmp/init/app-foo-bar.target") - write_file("/tmp/init/app-foo-bar@.service") - write_file("/tmp/init/app-foo-bar.target.wants/app-foo-bar@5300.service") + write_file("/tmp/init/app-foo-bar.target") + write_file("/tmp/init/app-foo-bar@.service") + write_file("/tmp/init/app-foo-bar.target.wants/app-foo-bar@5300.service") end it "cleans up service files created by systemd export" do @@ -86,13 +88,13 @@ end it "includes environment variables" do - engine.env['KEY'] = 'some "value"' + engine.env["KEY"] = 'some "value"' systemd.export expect(File.read("/tmp/init/app-alpha.1.service")).to match(/KEY=some "value"/) end it "includes ExecStart line" do - engine.env['KEY'] = 'some "value"' + engine.env["KEY"] = 'some "value"' systemd.export expect(File.read("/tmp/init/app-alpha.1.service")).to match(/^ExecStart=/) end @@ -112,7 +114,7 @@ context "with alternate template directory specified" do let(:template) { "/tmp/alternate" } - let(:options) { { :app => "app", :template => template } } + let(:options) { {app: "app", template: template} } before do FileUtils.mkdir_p template diff --git a/spec/foreman/export/upstart_spec.rb b/spec/foreman/export/upstart_spec.rb index 5c734978..64bbb4dc 100644 --- a/spec/foreman/export/upstart_spec.rb +++ b/spec/foreman/export/upstart_spec.rb @@ -4,22 +4,24 @@ require "tmpdir" describe Foreman::Export::Upstart, :fakefs do - let(:procfile) { write_procfile("/tmp/app/Procfile") } + let(:procfile) { write_procfile("/tmp/app/Procfile") } let(:formation) { nil } - let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) } - let(:options) { Hash.new } - let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, options) } + let(:engine) { Foreman::Engine.new(formation: formation).load_procfile(procfile) } + let(:options) { {} } + let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, options) } - before(:each) { load_export_templates_into_fakefs("upstart") } - before(:each) { allow(upstart).to receive(:say) } + before { + load_export_templates_into_fakefs("upstart") + allow(upstart).to receive(:say) + } it "exports to the filesystem" do upstart.export - expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf")) - expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf")) + expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf")) + expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf")) expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("upstart/app-alpha-1.conf")) - expect(File.read("/tmp/init/app-bravo.conf")).to eq(example_export_file("upstart/app-bravo.conf")) + expect(File.read("/tmp/init/app-bravo.conf")).to eq(example_export_file("upstart/app-bravo.conf")) expect(File.read("/tmp/init/app-bravo-1.conf")).to eq(example_export_file("upstart/app-bravo-1.conf")) end @@ -44,28 +46,28 @@ ["app2", "app2-alpha", "app2-alpha-1"].each do |name| path = "/tmp/init/#{name}.conf" FileUtils.touch(path) - expect(FileUtils).to_not receive(:rm).with(path) + expect(FileUtils).not_to receive(:rm).with(path) end upstart.export end - it 'does not delete exported files for app which share name prefix' do + it "does not delete exported files for app which share name prefix" do FileUtils.mkdir_p "/tmp/init" ["app-worker", "app-worker-worker", "app-worker-worker-1"].each do |name| path = "/tmp/init/#{name}.conf" FileUtils.touch(path) - expect(FileUtils).to_not receive(:rm).with(path) + expect(FileUtils).not_to receive(:rm).with(path) end upstart.export - expect(File.exist?('/tmp/init/app.conf')).to be true - expect(File.exist?('/tmp/init/app-worker.conf')).to be true + expect(File.exist?("/tmp/init/app.conf")).to be true + expect(File.exist?("/tmp/init/app-worker.conf")).to be true end it "quotes and escapes environment variables" do - engine.env['KEY'] = 'd"\|d' + engine.env["KEY"] = 'd"\|d' upstart.export expect("foobarfoo").to include "bar" expect(File.read("/tmp/init/app-alpha-1.conf")).to match(/KEY='d"\\\|d'/) @@ -77,17 +79,17 @@ it "exports to the filesystem with concurrency" do upstart.export - expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf")) - expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf")) - expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("upstart/app-alpha-1.conf")) - expect(File.read("/tmp/init/app-alpha-2.conf")).to eq(example_export_file("upstart/app-alpha-2.conf")) + expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf")) + expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf")) + expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("upstart/app-alpha-1.conf")) + expect(File.read("/tmp/init/app-alpha-2.conf")).to eq(example_export_file("upstart/app-alpha-2.conf")) expect(File.exist?("/tmp/init/app-bravo-1.conf")).to eq(false) end end context "with alternate templates" do let(:template) { "/tmp/alternate" } - let(:options) { { :app => "app", :template => template } } + let(:options) { {app: "app", template: template} } before do FileUtils.mkdir_p template @@ -101,7 +103,6 @@ end context "with alternate templates from home dir" do - before do FileUtils.mkdir_p File.expand_path("~/.foreman/templates/upstart") File.open(File.expand_path("~/.foreman/templates/upstart/master.conf.erb"), "w") do |file| @@ -114,5 +115,4 @@ expect(File.read("/tmp/init/app.conf")).to eq("default_alternate_template\n") end end - end diff --git a/spec/foreman/export_spec.rb b/spec/foreman/export_spec.rb index f98d40e7..8835fd88 100644 --- a/spec/foreman/export_spec.rb +++ b/spec/foreman/export_spec.rb @@ -8,13 +8,12 @@ it "prints an error" do expect(subject).to receive(:require).with("foreman/export/invalidformatter") mock_export_error("Unknown export format: invalidformatter (no class Foreman::Export::Invalidformatter).") do - subject.formatter("invalidformatter") + subject.formatter("invalidformatter") end end end describe "with an invalid formatter" do - it "prints an error" do mock_export_error("Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do subject.formatter("invalidformatter") diff --git a/spec/foreman/helpers_spec.rb b/spec/foreman/helpers_spec.rb index 72d64f27..85096969 100644 --- a/spec/foreman/helpers_spec.rb +++ b/spec/foreman/helpers_spec.rb @@ -2,6 +2,12 @@ require "foreman/helpers" describe "Foreman::Helpers" do + subject { + o = Object.new + o.extend(Foreman::Helpers) + o + } + before do module Foo class Bar; end @@ -12,14 +18,12 @@ class Bar; end Object.send(:remove_const, :Foo) end - subject { o = Object.new; o.extend(Foreman::Helpers); o } - - it "should classify words" do + it "classifies words" do expect(subject.classify("foo")).to eq("Foo") expect(subject.classify("foo-bar")).to eq("FooBar") end - it "should constantize words" do + it "constantizes words" do expect(subject.constantize("Object")).to eq(Object) expect(subject.constantize("Foo::Bar")).to eq(Foo::Bar) end diff --git a/spec/foreman/process_spec.rb b/spec/foreman/process_spec.rb index d449c956..d3f267f9 100644 --- a/spec/foreman/process_spec.rb +++ b/spec/foreman/process_spec.rb @@ -1,56 +1,54 @@ -require 'spec_helper' -require 'foreman/process' -require 'ostruct' -require 'timeout' -require 'tmpdir' +require "spec_helper" +require "foreman/process" +require "ostruct" +require "timeout" +require "tmpdir" describe Foreman::Process do - - def run(process, options={}) + def run(process, options = {}) rd, wr = IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY") - process.run(options.merge(:output => wr)) + process.run(options.merge(output: wr)) rd.gets end describe "#run" do - it "runs the process" do process = Foreman::Process.new(resource_path("bin/test")) expect(run(process)).to eq("testing\n") end it "can set environment" do - process = Foreman::Process.new(resource_path("bin/env FOO"), :env => { "FOO" => "bar" }) + process = Foreman::Process.new(resource_path("bin/env FOO"), env: {"FOO" => "bar"}) expect(run(process)).to eq("bar\n") end it "can set per-run environment" do process = Foreman::Process.new(resource_path("bin/env FOO")) - expect(run(process, :env => { "FOO" => "bar "})).to eq("bar\n") + expect(run(process, env: {"FOO" => "bar "})).to eq("bar\n") end it "can handle env vars in the command" do - process = Foreman::Process.new(resource_path("bin/echo $FOO"), :env => { "FOO" => "bar" }) + process = Foreman::Process.new(resource_path("bin/echo $FOO"), env: {"FOO" => "bar"}) expect(run(process)).to eq("bar\n") end it "can handle per-run env vars in the command" do process = Foreman::Process.new(resource_path("bin/echo $FOO")) - expect(run(process, :env => { "FOO" => "bar" })).to eq("bar\n") + expect(run(process, env: {"FOO" => "bar"})).to eq("bar\n") end - it "should output utf8 properly" do + it "outputs utf8 properly" do process = Foreman::Process.new(resource_path("bin/utf8")) - expect(run(process)).to eq(Foreman.ruby_18? ? "\xFF\x03\n" : "\xFF\x03\n".force_encoding('binary')) + expect(run(process)).to eq(Foreman.ruby_18? ? "\xFF\x03\n" : "\xFF\x03\n".force_encoding("binary")) end it "can expand env in the command" do - process = Foreman::Process.new("command $FOO $BAR", :env => { "FOO" => "bar" }) + process = Foreman::Process.new("command $FOO $BAR", env: {"FOO" => "bar"}) expect(process.expanded_command).to eq("command bar $BAR") end it "can expand extra env in the command" do - process = Foreman::Process.new("command $FOO $BAR", :env => { "FOO" => "bar" }) + process = Foreman::Process.new("command $FOO $BAR", env: {"FOO" => "bar"}) expect(process.expanded_command("BAR" => "qux")).to eq("command bar qux") end @@ -63,9 +61,7 @@ def run(process, options={}) it "can execute with env" do expect(Kernel).to receive(:exec).with("bin/command bar") process = Foreman::Process.new("bin/command $FOO") - process.exec(:env => { "FOO" => "bar" }) + process.exec(env: {"FOO" => "bar"}) end - end - end diff --git a/spec/foreman/procfile_spec.rb b/spec/foreman/procfile_spec.rb index ae604245..7acba17f 100644 --- a/spec/foreman/procfile_spec.rb +++ b/spec/foreman/procfile_spec.rb @@ -1,7 +1,7 @@ -require 'spec_helper' -require 'foreman/procfile' -require 'pathname' -require 'tmpdir' +require "spec_helper" +require "foreman/procfile" +require "pathname" +require "tmpdir" describe Foreman::Procfile, :fakefs do subject { Foreman::Procfile.new } @@ -16,8 +16,8 @@ it "loads a passed-in Procfile" do write_procfile procfile = Foreman::Procfile.new("Procfile") - expect(procfile["alpha"]).to eq("./alpha") - expect(procfile["bravo"]).to eq("./bravo") + expect(procfile["alpha"]).to eq("./alpha") + expect(procfile["bravo"]).to eq("./bravo") expect(procfile["foo-bar"]).to eq("./foo-bar") expect(procfile["foo_bar"]).to eq("./foo_bar") end @@ -30,7 +30,7 @@ expect { Foreman::Procfile.new("Procfile") }.to raise_error described_class::EmptyFileError end - it 'only creates Procfile entries for lines matching regex' do + it "only creates Procfile entries for lines matching regex" do write_procfile procfile = Foreman::Procfile.new("Procfile") keys = procfile.instance_variable_get(:@entries).map(&:first) @@ -57,9 +57,8 @@ it "can write to a file" do subject["foo"] = "./foo" subject["bar"] = "./bar" - Dir.mkdir('/tmp') + Dir.mkdir("/tmp") subject.save "/tmp/proc" expect(File.read("/tmp/proc")).to eq("foo: ./foo\nbar: ./bar\n") end - end diff --git a/spec/foreman_spec.rb b/spec/foreman_spec.rb index bb349ceb..f2c4a1fe 100644 --- a/spec/foreman_spec.rb +++ b/spec/foreman_spec.rb @@ -2,14 +2,14 @@ require "foreman" describe Foreman do - describe "VERSION" do subject { Foreman::VERSION } + it { is_expected.to be_a String } end describe "runner" do - it "should exist" do + it "exists" do expect(File.exist?(Foreman.runner)).to eq(true) end end diff --git a/spec/helper_spec.rb b/spec/helper_spec.rb index f04ff90c..03ad8f07 100644 --- a/spec/helper_spec.rb +++ b/spec/helper_spec.rb @@ -4,15 +4,15 @@ describe "#preserving_env" do after { ENV.delete "FOO" } - it "should remove added environment vars" do + it "removes added environment vars" do old = ENV["FOO"] preserving_env { ENV["FOO"] = "baz" } expect(ENV["FOO"]).to eq(old) end - it "should reset modified environment vars" do + it "resets modified environment vars" do ENV["FOO"] = "bar" - preserving_env { ENV["FOO"] = "baz"} + preserving_env { ENV["FOO"] = "baz" } expect(ENV["FOO"]).to eq("bar") end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 87e68890..a60e3b04 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -28,16 +28,14 @@ def make_pipe def foreman(args) capture_stdout do - begin - Foreman::CLI.start(args.split(" ")) - rescue SystemExit - end + Foreman::CLI.start(args.split(" ")) + rescue SystemExit end end def forked_foreman(args) rd, wr = make_pipe - Process.spawn("bundle exec bin/foreman #{args}", :out => wr, :err => wr) + Process.spawn("bundle exec bin/foreman #{args}", out: wr, err: wr) wr.close rd.read end @@ -62,7 +60,7 @@ def fork_and_capture(&blk) end def fork_and_get_exitstatus(args) - pid = Process.spawn("bundle exec bin/foreman #{args}", :out => "/dev/null", :err => "/dev/null") + pid = Process.spawn("bundle exec bin/foreman #{args}", out: "/dev/null", err: "/dev/null") Process.wait(pid) $?.exitstatus end @@ -73,13 +71,13 @@ def mock_exit(&block) def write_foreman_config(app) File.open("/etc/foreman/#{app}.conf", "w") do |file| - file.puts %{#{app}_processes="alpha bravo"} - file.puts %{#{app}_alpha="1"} - file.puts %{#{app}_bravo="2"} + file.puts %(#{app}_processes="alpha bravo") + file.puts %(#{app}_alpha="1") + file.puts %(#{app}_bravo="2") end end -def write_procfile(procfile="Procfile", alpha_env="") +def write_procfile(procfile = "Procfile", alpha_env = "") FileUtils.mkdir_p(File.dirname(procfile)) File.open(procfile, "w") do |file| file.puts "alpha: ./alpha" + " #{alpha_env}".rstrip @@ -94,12 +92,12 @@ def write_procfile(procfile="Procfile", alpha_env="") def write_file(file) FileUtils.mkdir_p(File.dirname(file)) - File.open(file, 'w') do |f| + File.open(file, "w") do |f| yield(f) if block_given? end end -def write_env(env=".env", options={"FOO"=>"bar"}) +def write_env(env = ".env", options = {"FOO" => "bar"}) File.open(env, "w") do |file| options.each do |key, val| file.puts "#{key}=#{val}" @@ -166,9 +164,9 @@ def capture_stdout RSpec.configure do |config| config.color = true - config.order = 'rand' + config.order = "rand" config.include FakeFS::SpecHelpers, :fakefs - config.before(:each) do - FileUtils.mkdir_p('/tmp') + config.before do + FileUtils.mkdir_p("/tmp") end end diff --git a/tasks/dist.rake b/tasks/dist.rake index 84bfab8e..8a45c26e 100644 --- a/tasks/dist.rake +++ b/tasks/dist.rake @@ -2,7 +2,7 @@ require "erb" require "fileutils" require "tmpdir" -def assemble(source, target, perms=0644) +def assemble(source, target, perms = 0o644) FileUtils.mkdir_p(File.dirname(target)) File.open(target, "w") do |f| f.puts ERB.new(File.read(source)).result(binding) @@ -10,7 +10,7 @@ def assemble(source, target, perms=0644) File.chmod(perms, target) end -def assemble_distribution(target_dir=Dir.pwd) +def assemble_distribution(target_dir = Dir.pwd) distribution_files.each do |source| target = source.gsub(/^#{project_root}/, target_dir) FileUtils.mkdir_p(File.dirname(target)) @@ -18,19 +18,19 @@ def assemble_distribution(target_dir=Dir.pwd) end end -GEM_BLACKLIST = %w( bundler foreman ) +GEM_BLACKLIST = %w[bundler foreman] -def assemble_gems(target_dir=Dir.pwd) - lines = %x{ cd #{project_root} && bundle show }.strip.split("\n") +def assemble_gems(target_dir = Dir.pwd) + lines = `cd #{project_root} && bundle show`.strip.split("\n") raise "error running bundler" unless $?.success? - %x{ env BUNDLE_WITHOUT="development:test" bundle show }.split("\n").each do |line| + `env BUNDLE_WITHOUT="development:test" bundle show`.split("\n").each do |line| if line =~ /^ \* (.*?) \((.*?)\)/ next if GEM_BLACKLIST.include?($1) puts "vendoring: #{$1}-#{$2}" - gem_dir = %x{ bundle show #{$1} }.strip + gem_dir = `bundle show #{$1}`.strip FileUtils.mkdir_p "#{target_dir}/vendor/gems" - %x{ cp -R "#{gem_dir}" "#{target_dir}/vendor/gems" } + `cp -R "#{gem_dir}" "#{target_dir}/vendor/gems"` end end.compact end @@ -43,7 +43,7 @@ def clean(file) rm file if File.exist?(file) end -def distribution_files(type=nil) +def distribution_files(type = nil) require "foreman/distribution" base_files = Foreman::Distribution.files type_files = type ? @@ -81,17 +81,17 @@ def s3_connect end AWS::S3::Base.establish_connection!( - :access_key_id => ENV["FOREMAN_RELEASE_ACCESS"], - :secret_access_key => ENV["FOREMAN_RELEASE_SECRET"] + access_key_id: ENV["FOREMAN_RELEASE_ACCESS"], + secret_access_key: ENV["FOREMAN_RELEASE_SECRET"] ) @s3_connected = true end -def store(package_file, filename, bucket="assets.foreman.io") +def store(package_file, filename, bucket = "assets.foreman.io") s3_connect puts "storing: #{filename}" - AWS::S3::S3Object.store(filename, File.open(package_file), bucket, :access => :public_read) + AWS::S3::S3Object.store(filename, File.open(package_file), bucket, access: :public_read) end def tempdir diff --git a/tasks/release.rake b/tasks/release.rake index eefc1917..bc7a3f36 100644 --- a/tasks/release.rake +++ b/tasks/release.rake @@ -2,8 +2,8 @@ require "time" desc "Build the manual" task :man do - ENV['RONN_MANUAL'] = "Foreman Manual" - ENV['RONN_ORGANIZATION'] = "Foreman #{Foreman::VERSION}" + ENV["RONN_MANUAL"] = "Foreman Manual" + ENV["RONN_ORGANIZATION"] = "Foreman #{Foreman::VERSION}" sh "ronn -w -s toc -r5 --markdown man/*.ronn" end @@ -15,8 +15,8 @@ task "man:commit" => :man do end desc "Generate the Github docs" -task :pages => "man:commit" do - sh %{ +task pages: "man:commit" do + sh %( cp man/foreman.1.html /tmp/foreman.1.html git checkout gh-pages rm ./index.html @@ -25,7 +25,7 @@ task :pages => "man:commit" do git commit -m "saving man page to github docs" git push origin -f gh-pages git checkout main - } + ) end def latest_release @@ -33,7 +33,7 @@ def latest_release end def newer_release - tags = %x{ git tag --contains v#{latest_release} | grep -v pre }.split("\n").sort_by do |tag| + tags = `git tag --contains v#{latest_release} | grep -v pre`.split("\n").sort_by do |tag| Gem::Version.new(tag[1..-1]) end tags[1] @@ -42,12 +42,12 @@ end desc "Generate a Changelog" task :changelog do while release = newer_release - entry = %x{ git show --format="%cd" #{release} | head -n 1 } + entry = `git show --format="%cd" #{release} | head -n 1` puts entry date = Time.parse(entry.chomp).strftime("%Y-%m-%d") - message = "## #{release[1..-1]} (#{date})\n\n" - message += %x{ git log --format="* %s [%an]" v#{latest_release}..#{release} | grep -v "Merge pull request" | grep -v "* #{release[1..-1]}" | grep -v "* update docs" } + message = "## #{release[1..-1]} (#{date})\n\n" + message += `git log --format="* %s [%an]" v#{latest_release}..#{release} | grep -v "Merge pull request" | grep -v "* #{release[1..-1]}" | grep -v "* update docs"` changelog = File.read("Changelog.md") changelog = message + "\n" + changelog diff --git a/tasks/rspec.rake b/tasks/rspec.rake index 898349d6..cde61f87 100644 --- a/tasks/rspec.rake +++ b/tasks/rspec.rake @@ -1,8 +1,8 @@ require "rspec/core/rake_task" -task :default => :spec +task default: :spec desc "Run all specs" RSpec::Core::RakeTask.new(:spec) do |t| - t.pattern = 'spec/**/*_spec.rb' + t.pattern = "spec/**/*_spec.rb" end diff --git a/tasks/vendor.rake b/tasks/vendor.rake index 3991c3ca..f9ad989d 100644 --- a/tasks/vendor.rake +++ b/tasks/vendor.rake @@ -3,11 +3,10 @@ begin desc "Vendor a specific version of thor" Automatiek::RakeTask.new("thor") do |lib| - lib.download = { github: "https://github.com/erikhuda/thor" } + lib.download = {github: "https://github.com/erikhuda/thor"} lib.namespace = "Thor" lib.prefix = "Foreman" lib.vendor_lib = "lib/foreman/vendor/thor" end rescue LoadError end -