Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Preparing to resolve #9503. This PR imports https://github.com/fohte/rubocop-daemon into RuboCop core. The rubocop-daemon's original license (MIT) is written at the beginning of the imported files.
- Loading branch information
Showing
18 changed files
with
784 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# frozen_string_literal: true | ||
|
||
# | ||
# This code is based on https://github.com/fohte/rubocop-daemon. | ||
# | ||
# Copyright (c) 2018 Hayato Kawai | ||
# | ||
# The MIT License (MIT) | ||
# | ||
# https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt | ||
# | ||
module RuboCop | ||
module Daemon | ||
TIMEOUT = 20 | ||
|
||
autoload :CLI, 'rubocop/daemon/cli' | ||
autoload :Cache, 'rubocop/daemon/cache' | ||
autoload :ClientCommand, 'rubocop/daemon/client_command' | ||
autoload :Helper, 'rubocop/daemon/helper' | ||
autoload :Server, 'rubocop/daemon/server' | ||
autoload :ServerCommand, 'rubocop/daemon/server_command' | ||
autoload :SocketReader, 'rubocop/daemon/socket_reader' | ||
|
||
def self.running? | ||
Cache.dir.exist? && Cache.pid_path.file? && Cache.pid_running? | ||
end | ||
|
||
def self.wait_for_running_status!(expected) | ||
start_time = Time.now | ||
while Daemon.running? != expected | ||
sleep 0.1 | ||
next unless Time.now - start_time > TIMEOUT | ||
|
||
warn "running? was not #{expected} after #{TIMEOUT} seconds!" | ||
exit 1 | ||
end | ||
end | ||
end | ||
end | ||
|
||
require 'rubocop/daemon/errors' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'pathname' | ||
|
||
# | ||
# This code is based on https://github.com/fohte/rubocop-daemon. | ||
# | ||
# Copyright (c) 2018 Hayato Kawai | ||
# | ||
# The MIT License (MIT) | ||
# | ||
# https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt | ||
# | ||
module RuboCop | ||
module Daemon | ||
class Cache | ||
class << self | ||
# Searches for Gemfile or gems.rb in the current dir or any parent dirs | ||
def project_dir | ||
current_dir = Dir.pwd | ||
while current_dir != '/' | ||
return current_dir if %w[Gemfile gems.rb].any? do |gemfile| | ||
File.exist?(File.join(current_dir, gemfile)) | ||
end | ||
|
||
current_dir = File.expand_path('..', current_dir) | ||
end | ||
# If we can't find a Gemfile, just use the current directory | ||
Dir.pwd | ||
end | ||
|
||
def project_dir_cache_key | ||
@project_dir_cache_key ||= project_dir[1..-1].tr('/', '+') | ||
end | ||
|
||
def dir | ||
cache_path = File.expand_path('~/.cache/rubocop-daemon') | ||
Pathname.new(File.join(cache_path, project_dir_cache_key)).tap do |d| | ||
d.mkpath unless d.exist? | ||
end | ||
end | ||
|
||
def port_path | ||
dir.join('port') | ||
end | ||
|
||
def token_path | ||
dir.join('token') | ||
end | ||
|
||
def pid_path | ||
dir.join('pid') | ||
end | ||
|
||
def lock_path | ||
dir.join('lock') | ||
end | ||
|
||
def status_path | ||
dir.join('status') | ||
end | ||
|
||
def pid_running? | ||
Process.kill(0, pid_path.read.to_i) == 1 | ||
rescue Errno::ESRCH | ||
false | ||
end | ||
|
||
def acquire_lock | ||
lock_file = File.open(lock_path, File::CREAT) | ||
# flock returns 0 if successful, and false if not. | ||
flock_result = lock_file.flock(File::LOCK_EX | File::LOCK_NB) | ||
yield flock_result != false | ||
ensure | ||
lock_file.flock(File::LOCK_UN) | ||
lock_file.close | ||
end | ||
|
||
def write_port_and_token_files(port:, token:) | ||
port_path.write(port) | ||
token_path.write(token) | ||
end | ||
|
||
def write_pid_file | ||
pid_path.write(Process.pid) | ||
yield | ||
ensure | ||
dir.rmtree | ||
end | ||
|
||
def write_status_file(status) | ||
status_path.write(status) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'optparse' | ||
|
||
# | ||
# This code is based on https://github.com/fohte/rubocop-daemon. | ||
# | ||
# Copyright (c) 2018 Hayato Kawai | ||
# | ||
# The MIT License (MIT) | ||
# | ||
# https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt | ||
# | ||
module RuboCop | ||
module Daemon | ||
class CLI | ||
def self.new_parser(&_block) | ||
OptionParser.new do |opts| | ||
yield(opts) | ||
end | ||
end | ||
|
||
def run(argv = ARGV) | ||
parser.order!(argv) | ||
return if argv.empty? | ||
|
||
create_subcommand_instance(argv) | ||
rescue OptionParser::InvalidOption => e | ||
warn "error: #{e.message}" | ||
exit 1 | ||
rescue UnknownClientCommandError => e | ||
warn "rubocop-daemon: #{e.message}. See 'rubocop-daemon --help'." | ||
exit 1 | ||
end | ||
|
||
def parser | ||
@parser ||= self.class.new_parser do |opts| | ||
opts.banner = 'usage: rubocop-daemon <command> [<args>]' | ||
end | ||
end | ||
|
||
private | ||
|
||
def create_subcommand_instance(argv) | ||
subcommand, *args = argv | ||
find_subcommand_class(subcommand).new(args).run | ||
end | ||
|
||
def find_subcommand_class(subcommand) | ||
case subcommand | ||
when 'exec' then ClientCommand::Exec | ||
when 'restart' then ClientCommand::Restart | ||
when 'start' then ClientCommand::Start | ||
when 'status' then ClientCommand::Status | ||
when 'stop' then ClientCommand::Stop | ||
else | ||
raise UnknownClientCommandError, "#{subcommand.inspect} is not a rubocop-daemon command" | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
# | ||
# This code is based on https://github.com/fohte/rubocop-daemon. | ||
# | ||
# Copyright (c) 2018 Hayato Kawai | ||
# | ||
# The MIT License (MIT) | ||
# | ||
# https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt | ||
# | ||
module RuboCop | ||
module Daemon | ||
module ClientCommand | ||
autoload :Base, 'rubocop/daemon/client_command/base' | ||
autoload :Exec, 'rubocop/daemon/client_command/exec' | ||
autoload :Restart, 'rubocop/daemon/client_command/restart' | ||
autoload :Start, 'rubocop/daemon/client_command/start' | ||
autoload :Status, 'rubocop/daemon/client_command/status' | ||
autoload :Stop, 'rubocop/daemon/client_command/stop' | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'shellwords' | ||
require 'socket' | ||
|
||
# | ||
# This code is based on https://github.com/fohte/rubocop-daemon. | ||
# | ||
# Copyright (c) 2018 Hayato Kawai | ||
# | ||
# The MIT License (MIT) | ||
# | ||
# https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt | ||
# | ||
module RuboCop | ||
module Daemon | ||
module ClientCommand | ||
class Base | ||
def initialize(argv) | ||
@argv = argv.dup | ||
@options = {} | ||
end | ||
|
||
def run; end | ||
|
||
private | ||
|
||
def send_request(command:, args: [], body: '') | ||
TCPSocket.open('127.0.0.1', Cache.port_path.read) do |socket| | ||
socket.puts [Cache.token_path.read, Dir.pwd, command, *args].shelljoin | ||
socket.write body | ||
socket.close_write | ||
STDOUT.write socket.read(4096) until socket.eof? | ||
end | ||
end | ||
|
||
def check_running_server | ||
Daemon.running?.tap do |running| | ||
warn 'rubocop-daemon: server is not running.' unless running | ||
end | ||
end | ||
|
||
def ensure_server! | ||
return if check_running_server | ||
|
||
ClientCommand::Start.new([]).run | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# frozen_string_literal: true | ||
|
||
# | ||
# This code is based on https://github.com/fohte/rubocop-daemon. | ||
# | ||
# Copyright (c) 2018 Hayato Kawai | ||
# | ||
# The MIT License (MIT) | ||
# | ||
# https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt | ||
# | ||
module RuboCop | ||
module Daemon | ||
module ClientCommand | ||
class Exec < Base | ||
def run | ||
args = parser.parse(@argv) | ||
ensure_server! | ||
Cache.status_path.delete if Cache.status_path.file? | ||
send_request( | ||
command: 'exec', | ||
args: args, | ||
body: $stdin.tty? ? '' : $stdin.read, | ||
) | ||
exit_with_status! | ||
end | ||
|
||
private | ||
|
||
def parser | ||
@parser ||= CLI.new_parser do |p| | ||
p.banner = 'usage: rubocop-daemon exec [options] [files...] [-- [rubocop-options]]' | ||
end | ||
end | ||
|
||
def exit_with_status! | ||
raise "rubocop-daemon: Could not find status file at: #{Cache.status_path}" unless Cache.status_path.file? | ||
|
||
status = Cache.status_path.read | ||
raise "rubocop-daemon: '#{status}' is not a valid status!" if (status =~ /^\d+$/).nil? | ||
|
||
exit status.to_i | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# frozen_string_literal: true | ||
|
||
# | ||
# This code is based on https://github.com/fohte/rubocop-daemon. | ||
# | ||
# Copyright (c) 2018 Hayato Kawai | ||
# | ||
# The MIT License (MIT) | ||
# | ||
# https://github.com/fohte/rubocop-daemon/blob/master/LICENSE.txt | ||
# | ||
module RuboCop | ||
module Daemon | ||
module ClientCommand | ||
class Restart < Base | ||
def run | ||
parser.parse(@argv) | ||
|
||
ClientCommand::Stop.new([]).run | ||
ClientCommand::Start.new(@argv).run | ||
end | ||
|
||
private | ||
|
||
def parser | ||
@parser ||= CLI.new_parser do |p| | ||
p.banner = 'usage: rubocop-daemon restart' | ||
|
||
p.on('-p', '--port [PORT]') { |v| @options[:port] = v } | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.