appear 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in appear.gemspec
4
+ gemspec
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
@@ -0,0 +1,7 @@
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/command'
7
+ command = Appear::Command.new.execute(ARGV)
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
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
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