appear 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.doc-coverage +1 -0
- data/.gitignore +51 -0
- data/.rspec +2 -0
- data/.travis.yml +19 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +101 -0
- data/Rakefile +53 -0
- data/appear.gemspec +44 -0
- data/bin/appear +7 -0
- data/bin/console +14 -0
- data/bin/pparents +23 -0
- data/bin/setup +7 -0
- data/lib/appear.rb +14 -0
- data/lib/appear/command.rb +57 -0
- data/lib/appear/config.rb +24 -0
- data/lib/appear/constants.rb +17 -0
- data/lib/appear/instance.rb +54 -0
- data/lib/appear/join.rb +100 -0
- data/lib/appear/lsof.rb +153 -0
- data/lib/appear/mac_os.rb +42 -0
- data/lib/appear/output.rb +30 -0
- data/lib/appear/processes.rb +88 -0
- data/lib/appear/revealers.rb +183 -0
- data/lib/appear/runner.rb +101 -0
- data/lib/appear/service.rb +65 -0
- data/lib/appear/tmux.rb +77 -0
- data/screenshot.gif +0 -0
- data/tools/macOS-helper.js +349 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 49e7e4587f6725e9cf308bd49827e9b4a155904d
|
4
|
+
data.tar.gz: b62a655a7a4173118aa423bf8247c3407c39bd56
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 276900ee030c9bdeba0fe2c85fd60034d7f6e34e976651525809b334afe9075ab74fe3c9555e6eaf3b29ff0b64d9f579eb804cd085539ee0babb23d2f92d3542
|
7
|
+
data.tar.gz: 10859c80d30ad2c950a3f809b0c6a260faf4233436c533f668802af4426c0f0265ec53293d01153ef8984828f685babaec34853dc3d849c7bfeeb820a1585c48
|
data/.doc-coverage
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
73.05
|
data/.gitignore
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
/logs/
|
13
|
+
|
14
|
+
# Used by dotenv library to load environment variables.
|
15
|
+
# .env
|
16
|
+
|
17
|
+
## Specific to RubyMotion:
|
18
|
+
.dat*
|
19
|
+
.repl_history
|
20
|
+
build/
|
21
|
+
*.bridgesupport
|
22
|
+
build-iPhoneOS/
|
23
|
+
build-iPhoneSimulator/
|
24
|
+
|
25
|
+
## Specific to RubyMotion (use of CocoaPods):
|
26
|
+
#
|
27
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
28
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
29
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
30
|
+
#
|
31
|
+
# vendor/Pods/
|
32
|
+
|
33
|
+
## Documentation cache and generated files:
|
34
|
+
/.yardoc/
|
35
|
+
/_yardoc/
|
36
|
+
/doc/
|
37
|
+
/rdoc/
|
38
|
+
|
39
|
+
## Environment normalization:
|
40
|
+
/.bundle/
|
41
|
+
/vendor/bundle
|
42
|
+
/lib/bundler/man/
|
43
|
+
|
44
|
+
# for a library or gem, you might want to ignore these files since the code is
|
45
|
+
# intended to run in multiple environments; otherwise, check them in:
|
46
|
+
Gemfile.lock
|
47
|
+
.ruby-version
|
48
|
+
.ruby-gemset
|
49
|
+
|
50
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
51
|
+
.rvmrc
|
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
language: ruby
|
2
|
+
matrix:
|
3
|
+
# see https://docs.travis-ci.com/user/customizing-the-build/#Build-Matrix
|
4
|
+
# see https://docs.travis-ci.com/user/osx-ci-environment/
|
5
|
+
allow_failures:
|
6
|
+
- os: linux
|
7
|
+
include:
|
8
|
+
- os: linux
|
9
|
+
rvm: 1.9.3
|
10
|
+
- os: linux
|
11
|
+
rvm: 2.2.3
|
12
|
+
- os: osx
|
13
|
+
osx_image: xcode7 # 10.10
|
14
|
+
# - os: osx
|
15
|
+
# - osx_image: xcode7.2 # 10.11
|
16
|
+
script:
|
17
|
+
# Please add to Rakefile instead of this section.
|
18
|
+
- bundle exec rake
|
19
|
+
before_install: gem install bundler -v 1.10.6
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016 Airbnb
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# Appear
|
2
|
+
|
3
|
+
Appear your terminal programs in your gui!
|
4
|
+
|
5
|
+
[![Build Status](https://secure.travis-ci.org/airbnb/appear.svg?branch=master)](http://travis-ci.org/airbnb/appear)
|
6
|
+
|
7
|
+
![screenshot demo thing](./screenshot.gif)
|
8
|
+
|
9
|
+
Appear is a tool for revealing a given process in your terminal. Given a
|
10
|
+
process ID, `appear` finds the terminal emulator view (be it a window, tab, or
|
11
|
+
pane) containing that process and shows it to you. Appear understands terminal
|
12
|
+
multiplexers like `tmux`, so if your target process is in a multiplexer
|
13
|
+
session, `appear` will reveal a client connected to that session, or start one
|
14
|
+
if needed.
|
15
|
+
|
16
|
+
This project intends to support all POSIX operating systems eventually, but
|
17
|
+
currently only supports macOS.
|
18
|
+
|
19
|
+
## usage
|
20
|
+
|
21
|
+
```
|
22
|
+
Usage: appear [options] PID - appear PID in your user interface
|
23
|
+
-l, --log-file [PATH] log to a file
|
24
|
+
-v, --verbose tell many tales about how the appear process is going
|
25
|
+
--record-runs record every executed command as a JSON file
|
26
|
+
```
|
27
|
+
|
28
|
+
Appear will exit 0 if it managed to reveal something.
|
29
|
+
Appear will exit 1 if an exception occured.
|
30
|
+
Appear will exit 2 if there were no errors, but nothing was revealed.
|
31
|
+
|
32
|
+
## supported terminal emulators
|
33
|
+
|
34
|
+
macOS:
|
35
|
+
|
36
|
+
- iTerm2
|
37
|
+
- Terminal
|
38
|
+
|
39
|
+
cross-platform:
|
40
|
+
|
41
|
+
- tmux
|
42
|
+
|
43
|
+
GNU Screen support is a non-goal. It's time for screen users to switch to tmux.
|
44
|
+
|
45
|
+
## system requirements
|
46
|
+
|
47
|
+
- `ruby` >= 2
|
48
|
+
- `lsof` command
|
49
|
+
- `ps` command
|
50
|
+
- `pgrep` command
|
51
|
+
- if you're a mac, then you should have macOS >= 10.10
|
52
|
+
|
53
|
+
Appear depends only on the Ruby standard library.
|
54
|
+
|
55
|
+
## how it works
|
56
|
+
|
57
|
+
Here's how Appear works in a nutshell, given a `target_pid`
|
58
|
+
|
59
|
+
1. get all the parent processes of `target_pid`, up to pid1. We end up with a
|
60
|
+
list of ProcessInfos, which have fields `{pid, parent_pid, command, name}`
|
61
|
+
2. go through our list of "revealers", one for each terminal emulator (tmux,
|
62
|
+
iterm2, terminal.app) and ask the revealer if it can apply itself to the
|
63
|
+
process tree.
|
64
|
+
3. if a revealer finds an associated process in the tree (eg, tmux revealer
|
65
|
+
finds the tmux server process), it performs its reveal action
|
66
|
+
- this usually involves invoking `lsof` on a `/dev/ttys*` device to see what
|
67
|
+
processes are talking on what ttys to each other, which takes a bunch of
|
68
|
+
time
|
69
|
+
- `lsof` in Appear is parallel, so grouped lsof calls are less expensive
|
70
|
+
- the Tmux revealer is smart enough to both focus the pane that the
|
71
|
+
`target_pid` is running in, AND to recurse the revealing process with the
|
72
|
+
tmux client id, to reveal the tmux client.
|
73
|
+
4. the revealer sends some instructions to the terminal emulator that contains
|
74
|
+
the view for the PID
|
75
|
+
- for our Mac apps, this involves a helper process using [Javascript for
|
76
|
+
Automation][jfora], a JavaScript x Applescript crossover episode.
|
77
|
+
- for tmux this is just some shell commands, super easy.
|
78
|
+
|
79
|
+
[jfora]: https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-10.html#//apple_ref/doc/uid/TP40014508-CH109-SW1
|
80
|
+
|
81
|
+
## ruby api
|
82
|
+
|
83
|
+
The method documented here is the only part of Appear that should be considered
|
84
|
+
stable.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
require 'appear'
|
88
|
+
|
89
|
+
# super simple
|
90
|
+
Appear.appear(pid)
|
91
|
+
|
92
|
+
# You may customize logging, if needed, using the Config class
|
93
|
+
config = Appear::Config.new
|
94
|
+
|
95
|
+
# print debug info to STDOUT
|
96
|
+
config.silent = false
|
97
|
+
# also write to a log file
|
98
|
+
config.log_file = '/tmp/my-app-appear.log'
|
99
|
+
|
100
|
+
Appear.appear(pid, config)
|
101
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "yard"
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
module BasicDocCoverage
|
8
|
+
MINIMUM_COVERAGE = 25.0
|
9
|
+
YARD_COVERAGE_REGEX = /\s(?<percent>[\d\.]+)% documented/
|
10
|
+
|
11
|
+
ROOT_PATH = Pathname.new(File.dirname(File.expand_path(__FILE__)))
|
12
|
+
MINIMUM_COVERAGE_FILE = ROOT_PATH.join('.doc-coverage')
|
13
|
+
|
14
|
+
def self.define_task(task_name)
|
15
|
+
YARD::Rake::YardocTask.new(task_name) do |t|
|
16
|
+
t.files = ['lib/**/*.rb', '-', 'README.md']
|
17
|
+
t.options = ['--protected', '--no-private']
|
18
|
+
|
19
|
+
# make sure we doc the things
|
20
|
+
t.after = proc do
|
21
|
+
|
22
|
+
min_coverage = MINIMUM_COVERAGE
|
23
|
+
if MINIMUM_COVERAGE_FILE.exist?
|
24
|
+
min_coverage = [min_coverage, MINIMUM_COVERAGE_FILE.read.strip.to_f].max
|
25
|
+
end
|
26
|
+
|
27
|
+
yard_result = `bundle exec yard stats --list-undoc`
|
28
|
+
match = YARD_COVERAGE_REGEX.match(yard_result)
|
29
|
+
if !match
|
30
|
+
raise "Could not determine doc coverage using RE #{RE} from YARD output\n" \
|
31
|
+
">>> start YARD output\n#{yard_result}\n<<< end YARD output"
|
32
|
+
end
|
33
|
+
|
34
|
+
percent = match[:percent].to_f
|
35
|
+
failure = percent < min_coverage
|
36
|
+
|
37
|
+
if failure
|
38
|
+
raise "FAILURE: doc coverage percent #{percent} < #{min_coverage}\n" \
|
39
|
+
" please write good docs for your methods and attributes!\n" \
|
40
|
+
" run `bundle exec yard stats --list-undoc` for details"
|
41
|
+
else
|
42
|
+
puts "SUCCESS: doc coverage percent #{percent} >= #{min_coverage}"
|
43
|
+
end
|
44
|
+
|
45
|
+
File.write(MINIMUM_COVERAGE_FILE, [percent, min_coverage].max.to_s)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
BasicDocCoverage.define_task(:doc)
|
52
|
+
|
53
|
+
task default: [:spec, :doc]
|
data/appear.gemspec
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'appear/constants'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "appear"
|
8
|
+
spec.version = Appear::VERSION
|
9
|
+
spec.authors = ["Jake Teton-Landis"]
|
10
|
+
spec.email = ["just.1.jake@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Appear your terminal programs in your gui!}
|
13
|
+
spec.description = <<-EOS
|
14
|
+
Appear is a tool for revealing a given process in your terminal. Given a
|
15
|
+
process ID, `appear` finds the terminal emulator view (be it a window, tab, or
|
16
|
+
pane) containing that process and shows it to you. Appear understands terminal
|
17
|
+
multiplexers like `tmux`, so if your target process is in a multiplexer
|
18
|
+
session, `appear` will reveal a client connected to that session, or start one
|
19
|
+
if needed.
|
20
|
+
|
21
|
+
This project intends to support all POSIX operating systems eventually, but
|
22
|
+
currently only supports macOS.
|
23
|
+
EOS
|
24
|
+
spec.homepage = "https://github.com/airbnb/appear"
|
25
|
+
|
26
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
27
|
+
# delete this section to allow pushing this gem to any host.
|
28
|
+
# if spec.respond_to?(:metadata)
|
29
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
30
|
+
# else
|
31
|
+
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
32
|
+
# end
|
33
|
+
|
34
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
35
|
+
spec.bindir = "exe"
|
36
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
37
|
+
spec.require_paths = ["lib"]
|
38
|
+
|
39
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
40
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
41
|
+
spec.add_development_dependency "rspec"
|
42
|
+
spec.add_development_dependency "pry"
|
43
|
+
spec.add_development_dependency "yard", "~> 0.8.0"
|
44
|
+
end
|
data/bin/appear
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "appear"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/pparents
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
$:.unshift(Pathname.new(__FILE__).realpath.dirname.dirname.join('./lib').to_s)
|
5
|
+
|
6
|
+
require 'appear'
|
7
|
+
|
8
|
+
module Appear::PParents
|
9
|
+
def self.main
|
10
|
+
pid = ARGV[0].to_i
|
11
|
+
|
12
|
+
output = Appear::Output.new(nil, true)
|
13
|
+
runner = Appear::Runner.new(:output => output)
|
14
|
+
processes = Appear::Processes.new(:output => output, :runner => runner)
|
15
|
+
|
16
|
+
tree = processes.process_tree(pid)
|
17
|
+
tree.each do |info|
|
18
|
+
puts "#{info.pid} #{info.command.join(' ')}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Appear::PParents.main
|
data/bin/setup
ADDED
data/lib/appear.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Appear
|
2
|
+
# This method is an easy public interface to Appear for ruby consumers.
|
3
|
+
# Appear the given PID in your user interfaces.
|
4
|
+
# @param pid [Number] pid to Appear.
|
5
|
+
# @param config [Appear::Config, nil] a config for adjusting verbosity and logging.
|
6
|
+
def self.appear(pid, config = nil)
|
7
|
+
config ||= Appear::Config.new
|
8
|
+
instance = Appear::Instance.new(config)
|
9
|
+
instance.call(pid)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'appear/config'
|
14
|
+
require 'appear/instance'
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'appear/constants'
|
2
|
+
require 'appear/config'
|
3
|
+
require 'appear/instance'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
module Appear
|
7
|
+
class InvalidPidError < Error; end
|
8
|
+
|
9
|
+
# Entrypoint and manager for the command-line `appear` tool.
|
10
|
+
class Command
|
11
|
+
def initialize
|
12
|
+
@config = Appear::Config.new
|
13
|
+
@config.silent = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def option_parser
|
17
|
+
@option_parser ||= OptionParser.new do |o|
|
18
|
+
o.banner = 'Usage: appear [options] PID - appear PID in your user interface'
|
19
|
+
o.on('-l', '--log-file [PATH]', 'log to a file') do |file|
|
20
|
+
@config.log_file = file
|
21
|
+
end
|
22
|
+
|
23
|
+
o.on('-v', '--verbose', 'tell many tales about how the appear process is going') do |flag|
|
24
|
+
@config.silent = false if flag
|
25
|
+
end
|
26
|
+
|
27
|
+
o.on('--record-runs', 'record every executed command as a JSON file') do |flag|
|
28
|
+
@config.record_runs = flag
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute(all_args)
|
34
|
+
argv = option_parser.parse!(all_args)
|
35
|
+
|
36
|
+
pid = argv[0].to_i
|
37
|
+
if pid == 0
|
38
|
+
raise InvalidPidError.new("Invalid PID #{argv[0].inspect} given (parsed to 0).")
|
39
|
+
end
|
40
|
+
|
41
|
+
start = Time.now
|
42
|
+
revealer = Appear::Instance.new(@config)
|
43
|
+
revealer.output("STARTING. pid: #{pid}")
|
44
|
+
result = revealer.call(pid)
|
45
|
+
finish = Time.now
|
46
|
+
revealer.output("DONE. total time: #{finish - start} seconds, success: #{result}")
|
47
|
+
|
48
|
+
if result
|
49
|
+
# success! revealed something!
|
50
|
+
exit 0
|
51
|
+
else
|
52
|
+
# did not appear, but no errors encountered
|
53
|
+
exit 2
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|