launchy 2.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +28 -0
- data/.gitignore +6 -0
- data/HISTORY +90 -0
- data/LICENSE +16 -0
- data/NOTES +1 -0
- data/README +53 -0
- data/Rakefile +58 -0
- data/bin/launchy +4 -0
- data/lib/launchy.rb +119 -0
- data/lib/launchy/application.rb +81 -0
- data/lib/launchy/applications/browser.rb +68 -0
- data/lib/launchy/cli.rb +70 -0
- data/lib/launchy/descendant_tracker.rb +49 -0
- data/lib/launchy/detect.rb +10 -0
- data/lib/launchy/detect/host_os.rb +31 -0
- data/lib/launchy/detect/host_os_family.rb +71 -0
- data/lib/launchy/detect/nix_desktop_environment.rb +60 -0
- data/lib/launchy/detect/ruby_engine.rb +78 -0
- data/lib/launchy/detect/runner.rb +96 -0
- data/lib/launchy/error.rb +4 -0
- data/lib/launchy/os_family.rb +8 -0
- data/lib/launchy/version.rb +18 -0
- data/spec/application_spec.rb +41 -0
- data/spec/detect/host_os_family_spec.rb +40 -0
- data/spec/detect/host_os_spec.rb +19 -0
- data/spec/detect/nix_desktop_environment_spec.rb +13 -0
- data/spec/detect/ruby_engine_spec.rb +37 -0
- data/spec/launchy_spec.rb +42 -0
- data/spec/mock_scheme.rb +5 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/tattle-host-os.yaml +427 -0
- data/spec/version_spec.rb +10 -0
- metadata +170 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
class Launchy::Application
|
2
|
+
#
|
3
|
+
# The class handling the browser application and all of its schemes
|
4
|
+
#
|
5
|
+
class Browser < Launchy::Application
|
6
|
+
def self.schemes
|
7
|
+
%w[ http https ftp file ]
|
8
|
+
end
|
9
|
+
|
10
|
+
def windows_app_list
|
11
|
+
[ 'start "Launchy" /d']
|
12
|
+
end
|
13
|
+
|
14
|
+
def cygwin_app_list
|
15
|
+
[ "cmd /C start 'launchy' /d" ]
|
16
|
+
end
|
17
|
+
|
18
|
+
def darwin_app_list
|
19
|
+
[ find_executable( "open" ) ]
|
20
|
+
end
|
21
|
+
|
22
|
+
def nix_app_list
|
23
|
+
nix_de = Launchy::Detect::NixDekstopEnvironment.browser
|
24
|
+
app_list = %w[ xdg-open ]
|
25
|
+
app_list << nix_de.browser
|
26
|
+
app_list << nix_de.fallback_browsers
|
27
|
+
app_list.flatten!
|
28
|
+
app_list.delete_if { |b| b.nil? || (b.strip.size == 0) }
|
29
|
+
app_list.collect { |bin| find_executable( bin ) }.find_all { |x| not x.nil? }
|
30
|
+
end
|
31
|
+
|
32
|
+
# use a call back mechanism to get the right app_list that is decided by the
|
33
|
+
# host_os_family class.
|
34
|
+
def app_list
|
35
|
+
host_os_family.app_list( self )
|
36
|
+
end
|
37
|
+
|
38
|
+
def browser_env
|
39
|
+
return [] unless ENV['BROWSER']
|
40
|
+
browser_env = ENV['BROWSER'].split( File::PATH_SEPARATOR )
|
41
|
+
browser_env.flatten!
|
42
|
+
browser_env.delete_if { |b| b.nil? || (b.strip.size == 0) }
|
43
|
+
return browser_env
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get the full commandline of what we are going to add the uri to
|
47
|
+
def browser
|
48
|
+
possibilities = (browser_env + app_list).flatten
|
49
|
+
possibilities.each do |p|
|
50
|
+
Launchy.log "#{self.class.name} : possibility : #{p}"
|
51
|
+
end
|
52
|
+
b = possibilities.shift
|
53
|
+
Launchy.log "#{self.class.name} : Using browser value '#{b}'"
|
54
|
+
return b
|
55
|
+
end
|
56
|
+
|
57
|
+
# final assembly of the command and do %s substitution
|
58
|
+
# http://www.catb.org/~esr/BROWSER/index.html
|
59
|
+
def open( uri, options = {} )
|
60
|
+
b = browser
|
61
|
+
args = [ uri.to_s ]
|
62
|
+
if b =~ /%s/ then
|
63
|
+
b.gsub!( /%s/, args.shift )
|
64
|
+
end
|
65
|
+
run( b, args )
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/launchy/cli.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Launchy
|
4
|
+
class Cli
|
5
|
+
|
6
|
+
attr_reader :options
|
7
|
+
def initialize
|
8
|
+
@options = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def parser
|
12
|
+
@parser ||= OptionParser.new do |op|
|
13
|
+
op.banner = "Usage: launchy [options] thing-to-launch"
|
14
|
+
|
15
|
+
op.separator ""
|
16
|
+
op.separator "Launch Options:"
|
17
|
+
|
18
|
+
op.on( "-a", "--application APPLICATION",
|
19
|
+
"Explicitly specify the application class to use in the launch") do |app|
|
20
|
+
options[:application] = app
|
21
|
+
end
|
22
|
+
|
23
|
+
op.on( "-d", "--debug",
|
24
|
+
"Force debug. Output lots of information.") do |d|
|
25
|
+
options[:debug] = 'true'
|
26
|
+
end
|
27
|
+
|
28
|
+
op.on( "-e", "--engine RUBY_ENGINE",
|
29
|
+
"Force launchy to behave as if it was on a particular ruby engine.") do |e|
|
30
|
+
options[:ruby_engine] = e
|
31
|
+
end
|
32
|
+
|
33
|
+
op.on( "-n", "--dry-run", "Don't launchy, print the command to be executed on stdout" ) do |x|
|
34
|
+
options[:dry_run] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
op.on( "-o", "--host-os HOST_OS",
|
38
|
+
"Force launchy to behave as if it was on a particular host os.") do |os|
|
39
|
+
options[:host_os] = os
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
op.separator ""
|
44
|
+
op.separator "Standard Options:"
|
45
|
+
|
46
|
+
op.on( "-h", "--help", "Print this message.") do |h|
|
47
|
+
puts op.to_s
|
48
|
+
exit 0
|
49
|
+
end
|
50
|
+
|
51
|
+
op.on( "-v", "--version", "Output the version of Launchy") do |v|
|
52
|
+
puts "Launchy version #{Launchy::VERSION}"
|
53
|
+
exit 0
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def run( argv = ARGV, env = ENV )
|
60
|
+
begin
|
61
|
+
parser.parse!( argv )
|
62
|
+
Launchy.open( argv.shift, options )
|
63
|
+
rescue ::OptionParser::ParseError => pe
|
64
|
+
$stderr.puts "#{parser.program_name}: #{pe}"
|
65
|
+
$stderr.puts "Try `#{parser.program_name} --help for more information."
|
66
|
+
exit 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Launchy
|
4
|
+
#
|
5
|
+
# Use by either
|
6
|
+
#
|
7
|
+
# class Foo
|
8
|
+
# extend DescendantTracker
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# or
|
12
|
+
#
|
13
|
+
# class Foo
|
14
|
+
# class << self
|
15
|
+
# include DescendantTracker
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# It will track all the classes that inherit from the extended class and keep
|
20
|
+
# them in a Set that is available via the 'children' method.
|
21
|
+
#
|
22
|
+
module DescendantTracker
|
23
|
+
def inherited( klass )
|
24
|
+
return unless klass.instance_of?( Class )
|
25
|
+
self.children << klass
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# The list of children that are registered
|
30
|
+
#
|
31
|
+
def children
|
32
|
+
unless defined? @children
|
33
|
+
@children = Set.new
|
34
|
+
end
|
35
|
+
return @children
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Find one of the child classes by calling the given method
|
40
|
+
# and passing all the rest of the parameters to that method in
|
41
|
+
# each child
|
42
|
+
def find_child( method, *args )
|
43
|
+
klass = children.find do |child|
|
44
|
+
Launchy.log "Checking if class #{child} is the one for #{method}(#{args.join(', ')})}"
|
45
|
+
child.send( method, *args )
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
module Launchy::Detect
|
4
|
+
class HostOs
|
5
|
+
|
6
|
+
attr_reader :host_os
|
7
|
+
alias to_s host_os
|
8
|
+
|
9
|
+
def initialize( host_os = nil )
|
10
|
+
@host_os = host_os
|
11
|
+
|
12
|
+
if not @host_os then
|
13
|
+
if @host_os = override_host_os then
|
14
|
+
Launchy.log "Using LAUNCHY_HOST_OS override value of '#{Launchy.host_os}'"
|
15
|
+
else
|
16
|
+
@host_os = default_host_os
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_host_os
|
22
|
+
::RbConfig::CONFIG['host_os']
|
23
|
+
end
|
24
|
+
|
25
|
+
def override_host_os
|
26
|
+
Launchy.host_os
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Launchy::Detect
|
2
|
+
# Detect the current host os family
|
3
|
+
#
|
4
|
+
# If the current host familiy cannot be detected then return
|
5
|
+
# HostOsFamily::Unknown
|
6
|
+
class HostOsFamily
|
7
|
+
class NotFoundError < Launchy::Error; end
|
8
|
+
extend ::Launchy::DescendantTracker
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def detect( host_os = HostOs.new )
|
13
|
+
found = find_child( :matches?, host_os )
|
14
|
+
return found.new( host_os ) if found
|
15
|
+
raise NotFoundError, "Unknown OS family for host os '#{host_os}'. #{Launchy.bug_report_message}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches?( host_os )
|
19
|
+
matching_regex.match( host_os.to_s )
|
20
|
+
end
|
21
|
+
|
22
|
+
def windows?() self == Windows; end
|
23
|
+
def darwin?() self == Darwin; end
|
24
|
+
def nix?() self == Nix; end
|
25
|
+
def cygwin?() self == Cygwin; end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
attr_reader :host_os
|
30
|
+
def initialize( host_os = HostOs.new )
|
31
|
+
@host_os = host_os
|
32
|
+
end
|
33
|
+
|
34
|
+
def windows?() self.class.windows?; end
|
35
|
+
def darwin?() self.class.darwin?; end
|
36
|
+
def nix?() self.class.nix?; end
|
37
|
+
def cygwin?() self.class.cygwin?; end
|
38
|
+
|
39
|
+
#---------------------------
|
40
|
+
# All known host os families
|
41
|
+
#---------------------------
|
42
|
+
#
|
43
|
+
class Windows < HostOsFamily
|
44
|
+
def self.matching_regex
|
45
|
+
/(mingw|mswin|windows)/i
|
46
|
+
end
|
47
|
+
def app_list( app ) app.windows_app_list; end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Darwin < HostOsFamily
|
51
|
+
def self.matching_regex
|
52
|
+
/(darwin|mac os)/i
|
53
|
+
end
|
54
|
+
def app_list( app ) app.darwin_app_list; end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Nix < HostOsFamily
|
58
|
+
def self.matching_regex
|
59
|
+
/(linux|bsd|aix|solaris)/i
|
60
|
+
end
|
61
|
+
def app_list( app ) app.nix_app_list; end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Cygwin < HostOsFamily
|
65
|
+
def self.matching_regex
|
66
|
+
/cygwin/i
|
67
|
+
end
|
68
|
+
def app_list( app ) app.cygwin_app_list; end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Launchy::Detect
|
2
|
+
#
|
3
|
+
# Detect the current desktop environment for *nix machines
|
4
|
+
# Currently this is Linux centric. The detection is based upon the detection
|
5
|
+
# used by xdg-open from http://portland.freedesktop.org/wiki/XdgUtils
|
6
|
+
class NixDesktopEnvironment
|
7
|
+
class NotFoundError < Launchy::Error; end
|
8
|
+
|
9
|
+
extend ::Launchy::DescendantTracker
|
10
|
+
|
11
|
+
# Detect the current *nix desktop environment
|
12
|
+
#
|
13
|
+
# If the current dekstop environment be detected, the return
|
14
|
+
# NixDekstopEnvironment::Unknown
|
15
|
+
def self.detect
|
16
|
+
found = find_child( :is_current_desktop_environment? )
|
17
|
+
return found if found
|
18
|
+
raise NotFoundError, "Current Desktop environment not found. #{Launchy.bug_report_message}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.fallback_browsers
|
22
|
+
%w[ firefox seamonkey opera mozilla netscape galeon ]
|
23
|
+
end
|
24
|
+
|
25
|
+
#---------------------------------------
|
26
|
+
# The list of known desktop environments
|
27
|
+
#---------------------------------------
|
28
|
+
|
29
|
+
class Kde < NixDesktopEnvironment
|
30
|
+
def self.is_current_desktop_environment?
|
31
|
+
ENV['KDE_FULL_SESSION']
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.browser
|
35
|
+
'kfmclient'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Gnome < NixDesktopEnvironment
|
40
|
+
def self.is_current_desktop_environment?
|
41
|
+
ENV['GNOME_DESKTOP_SESSION_ID']
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.browser
|
45
|
+
'gnome-open'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Xfce < NixDesktopEnvironment
|
50
|
+
def self.is_current_desktop_environment?
|
51
|
+
%x[ xprop -root _DT_SAVE_MODE | grep ' = \"xfce\"$' ].strip.size > 0
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.browser
|
55
|
+
'exo-open'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Launchy::Detect
|
2
|
+
class RubyEngine
|
3
|
+
class NotFoundError < Launchy::Error; end
|
4
|
+
|
5
|
+
extend ::Launchy::DescendantTracker
|
6
|
+
|
7
|
+
# Detect the current ruby engine.
|
8
|
+
#
|
9
|
+
# If the current ruby engine cannot be detected, the return
|
10
|
+
# RubyEngine::Unknown
|
11
|
+
def self.detect( ruby_engine = RubyEngine.new )
|
12
|
+
found = find_child( :is_current_engine?, ruby_engine.to_s )
|
13
|
+
return found if found
|
14
|
+
raise NotFoundError, "#{ruby_engine_error_message( ruby_engine )} #{Launchy.bug_report_message}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.ruby_engine_error_message( ruby_engine )
|
18
|
+
msg = "Unkonwn RUBY_ENGINE "
|
19
|
+
if ruby_engine then
|
20
|
+
msg += " '#{ruby_engine}'."
|
21
|
+
elsif defined?( RUBY_ENGINE ) then
|
22
|
+
msg += " '#{RUBY_ENGINE}'."
|
23
|
+
else
|
24
|
+
msg = "RUBY_ENGINE not defined for #{RUBY_DESCRIPTION}."
|
25
|
+
end
|
26
|
+
return msg
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.is_current_engine?( ruby_engine )
|
30
|
+
return ruby_engine == self.engine_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.mri?() self == Mri; end
|
34
|
+
def self.jruby?() self == Jruby; end
|
35
|
+
def self.rbx?() self == Rbx; end
|
36
|
+
def self.macruby?() self == MacRuby; end
|
37
|
+
|
38
|
+
attr_reader :ruby_engine
|
39
|
+
alias to_s ruby_engine
|
40
|
+
def initialize( ruby_engine = Launchy.ruby_engine )
|
41
|
+
if ruby_engine then
|
42
|
+
@ruby_engine = ruby_engine
|
43
|
+
else
|
44
|
+
@ruby_engine = defined?( RUBY_ENGINE ) ? RUBY_ENGINE : "ruby"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
#-------------------------------
|
50
|
+
# The list of known ruby engines
|
51
|
+
#-------------------------------
|
52
|
+
|
53
|
+
#
|
54
|
+
# This is the ruby engine if the RUBY_ENGINE constant is not defined
|
55
|
+
class Mri < RubyEngine
|
56
|
+
def self.engine_name() "ruby"; end
|
57
|
+
def self.is_current_engine?( ruby_engine )
|
58
|
+
if ruby_engine then
|
59
|
+
super( ruby_engine )
|
60
|
+
else
|
61
|
+
return true if not Launchy.ruby_engine and not defined?( RUBY_ENGINE )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Jruby < RubyEngine
|
67
|
+
def self.engine_name() "jruby"; end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Rbx < RubyEngine
|
71
|
+
def self.engine_name() "rbx"; end
|
72
|
+
end
|
73
|
+
|
74
|
+
class MacRuby < RubyEngine
|
75
|
+
def self.engine_name() "macruby"; end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module Launchy::Detect
|
4
|
+
class Runner
|
5
|
+
class NotFoundError < Launchy::Error; end
|
6
|
+
|
7
|
+
extend ::Launchy::DescendantTracker
|
8
|
+
|
9
|
+
# Detect the current command runner
|
10
|
+
#
|
11
|
+
# If a runner cannot be detected then raise Runner::NotFoundError
|
12
|
+
def self.detect
|
13
|
+
host_os_family = Launchy::Detect::HostOsFamily.detect
|
14
|
+
ruby_engine = Launchy::Detect::RubyEngine.detect
|
15
|
+
|
16
|
+
return Windows.new if host_os_family.windows?
|
17
|
+
if ruby_engine.jruby? then
|
18
|
+
require 'spoon'
|
19
|
+
return Jruby.new
|
20
|
+
end
|
21
|
+
return Forkable.new
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# cut it down to just the shell commands that will be passed to exec or
|
26
|
+
# posix_spawn. The cmd argument is split according to shell rules and the
|
27
|
+
# args are escaped according to shell rules.
|
28
|
+
#
|
29
|
+
def shell_commands( cmd, args )
|
30
|
+
cmdline = [ cmd.shellsplit ]
|
31
|
+
cmdline << args.collect{ |a| a.to_s.shellescape }
|
32
|
+
return commanddline_normalize( cmdline )
|
33
|
+
end
|
34
|
+
|
35
|
+
def commandline_normalize( cmdline )
|
36
|
+
c = cmdline.flatten!
|
37
|
+
c = c.find_all { |a| (not a.nil?) and ( a.size > 0 ) }
|
38
|
+
Launchy.log "ARGV => #{c.inspect}"
|
39
|
+
return c
|
40
|
+
end
|
41
|
+
|
42
|
+
def run( cmd, *args )
|
43
|
+
if Launchy.dry_run? then
|
44
|
+
puts dry_run( cmd, *args )
|
45
|
+
else
|
46
|
+
wet_run( cmd, *args )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
#---------------------------------------
|
52
|
+
# The list of known runners
|
53
|
+
#---------------------------------------
|
54
|
+
|
55
|
+
class Windows < Runner
|
56
|
+
def dry_run( cmd, *args )
|
57
|
+
"cmd /c #{shell_commands( cmd, args).join(" " )}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def shell_commands( cmd, args )
|
61
|
+
cmdline = [ cmd ]
|
62
|
+
cmdline << args.collect { |a| a.to_s.gsub("&", "^&") }
|
63
|
+
return commandline_normalize( cmdline )
|
64
|
+
end
|
65
|
+
|
66
|
+
def wet_run( cmd, *args )
|
67
|
+
system( 'cmd', '/c', *shell_commands( cmd, *args ) )
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Jruby < Runner
|
72
|
+
|
73
|
+
def dry_run( cmd, *args )
|
74
|
+
shell_commands(cmd, args).join(" ")
|
75
|
+
end
|
76
|
+
|
77
|
+
def wet_run( cmd, *args )
|
78
|
+
Spoon.spawnp( *shell_commands( cmd, args ) )
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Forkable < Runner
|
83
|
+
def dry_run( cmd, *args )
|
84
|
+
shell_commands(cmd, args).join(" ")
|
85
|
+
end
|
86
|
+
|
87
|
+
def wet_run( cmd, *args )
|
88
|
+
child_pid = fork do
|
89
|
+
exec( *shell_commands( cmd, args ))
|
90
|
+
exit!
|
91
|
+
end
|
92
|
+
Process.detach( child_pid )
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|