launchy 2.0.0-java
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.
- 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
|