wijet-launchy 2.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +111 -0
- data/LICENSE +16 -0
- data/NOTES +1 -0
- data/README +100 -0
- data/Rakefile +70 -0
- data/bin/launchy +4 -0
- data/lib/launchy.rb +115 -0
- data/lib/launchy/application.rb +62 -0
- data/lib/launchy/applications/browser.rb +79 -0
- data/lib/launchy/cli.rb +83 -0
- data/lib/launchy/deprecated.rb +52 -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 +111 -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 +43 -0
- data/spec/applications/browser_spec.rb +54 -0
- data/spec/cli_spec.rb +75 -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 +33 -0
- data/spec/detect/ruby_engine_spec.rb +37 -0
- data/spec/detect/runner_spec.rb +98 -0
- data/spec/launchy_spec.rb +58 -0
- data/spec/mock_application.rb +9 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/tattle-host-os.yaml +427 -0
- data/spec/version_spec.rb +11 -0
- data/tasks/bundler.rake +13 -0
- data/tasks/contribute.rake +36 -0
- metadata +200 -0
@@ -0,0 +1,111 @@
|
|
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
|
+
# This will return an instance of the Runner to be used to do the
|
12
|
+
# application launching.
|
13
|
+
#
|
14
|
+
# If a runner cannot be detected then raise Runner::NotFoundError
|
15
|
+
#
|
16
|
+
# The runner rules are, in order:
|
17
|
+
#
|
18
|
+
# 1) If you are on windows, you use the Windows Runner no matter what
|
19
|
+
# 2) If you are using the jruby engine, use the Jruby Runner. Unless rule
|
20
|
+
# (1) took effect
|
21
|
+
# 3) Use Forkable (barring rules (1) and (2))
|
22
|
+
def self.detect
|
23
|
+
host_os_family = Launchy::Detect::HostOsFamily.detect
|
24
|
+
ruby_engine = Launchy::Detect::RubyEngine.detect
|
25
|
+
|
26
|
+
return Windows.new if host_os_family.windows?
|
27
|
+
if ruby_engine.jruby? then
|
28
|
+
require 'spoon'
|
29
|
+
return Jruby.new
|
30
|
+
end
|
31
|
+
return Forkable.new
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# cut it down to just the shell commands that will be passed to exec or
|
36
|
+
# posix_spawn. The cmd argument is split according to shell rules and the
|
37
|
+
# args are not escaped because they whole set is passed to system as *args
|
38
|
+
# and in that case system shell escaping rules are not done.
|
39
|
+
#
|
40
|
+
def shell_commands( cmd, args )
|
41
|
+
cmdline = [ cmd.shellsplit ]
|
42
|
+
cmdline << args.flatten.collect{ |a| a.to_s }
|
43
|
+
return commandline_normalize( cmdline )
|
44
|
+
end
|
45
|
+
|
46
|
+
def commandline_normalize( cmdline )
|
47
|
+
c = cmdline.flatten!
|
48
|
+
c = c.find_all { |a| (not a.nil?) and ( a.size > 0 ) }
|
49
|
+
Launchy.log "commandline_normalized => #{c.join(' ')}"
|
50
|
+
return c
|
51
|
+
end
|
52
|
+
|
53
|
+
def dry_run( cmd, *args )
|
54
|
+
shell_commands(cmd, args).join(" ")
|
55
|
+
end
|
56
|
+
|
57
|
+
def run( cmd, *args )
|
58
|
+
if Launchy.dry_run? then
|
59
|
+
$stdout.puts dry_run( cmd, *args )
|
60
|
+
else
|
61
|
+
wet_run( cmd, *args )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
#---------------------------------------
|
67
|
+
# The list of known runners
|
68
|
+
#---------------------------------------
|
69
|
+
|
70
|
+
class Windows < Runner
|
71
|
+
|
72
|
+
def all_args( cmd, *args )
|
73
|
+
args = [ 'cmd', '/c', *shell_commands( cmd, *args ) ]
|
74
|
+
Launchy.log "Windows: all_args => #{args.inspect}"
|
75
|
+
return args
|
76
|
+
end
|
77
|
+
|
78
|
+
def dry_run( cmd, *args )
|
79
|
+
all_args( cmd, *args ).join(" ")
|
80
|
+
end
|
81
|
+
|
82
|
+
# escape the reserved shell characters in windows command shell
|
83
|
+
# http://technet.microsoft.com/en-us/library/cc723564.aspx
|
84
|
+
def shell_commands( cmd, *args )
|
85
|
+
cmdline = [ cmd.shellsplit ]
|
86
|
+
cmdline << args.flatten.collect { |a| a.to_s.gsub(/([&|()<>^])/, "^\\1") }
|
87
|
+
return commandline_normalize( cmdline )
|
88
|
+
end
|
89
|
+
|
90
|
+
def wet_run( cmd, *args )
|
91
|
+
system( *all_args( cmd, *args ) )
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Jruby < Runner
|
96
|
+
def wet_run( cmd, *args )
|
97
|
+
Spoon.spawnp( *shell_commands( cmd, *args ) )
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class Forkable < Runner
|
102
|
+
def wet_run( cmd, *args )
|
103
|
+
child_pid = fork do
|
104
|
+
exec( *shell_commands( cmd, *args ))
|
105
|
+
exit!
|
106
|
+
end
|
107
|
+
Process.detach( child_pid )
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Launchy
|
2
|
+
VERSION = "2.0.6"
|
3
|
+
|
4
|
+
module Version
|
5
|
+
|
6
|
+
MAJOR = Integer(VERSION.split('.')[0])
|
7
|
+
MINOR = Integer(VERSION.split('.')[1])
|
8
|
+
PATCH = Integer(VERSION.split('.')[2])
|
9
|
+
|
10
|
+
def self.to_a
|
11
|
+
[MAJOR, MINOR, PATCH]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.to_s
|
15
|
+
VERSION
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mock_application'
|
3
|
+
|
4
|
+
class JunkApp < Launchy::Application
|
5
|
+
def self.handles?( uri )
|
6
|
+
uri.scheme == "junk"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Launchy::Application do
|
11
|
+
it 'registers inherited classes' do
|
12
|
+
class Junk2App < Launchy::Application
|
13
|
+
def self.handles?( uri )
|
14
|
+
uri.scheme == "junk2"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
Launchy::Application.children.must_include( Junk2App )
|
18
|
+
Launchy::Application.children.delete( Junk2App )
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can find an app" do
|
22
|
+
Launchy::Application.children.must_include( JunkApp )
|
23
|
+
Launchy::Application.children.size.must_equal 3
|
24
|
+
uri = Addressable::URI.parse( "junk:///foo" )
|
25
|
+
Launchy::Application.handling( uri ).must_equal( JunkApp )
|
26
|
+
end
|
27
|
+
|
28
|
+
it "raises an error if an application cannot be found for the given scheme" do
|
29
|
+
uri = Addressable::URI.parse( "foo:///bar" )
|
30
|
+
lambda { Launchy::Application.handling( uri ) }.must_raise( Launchy::ApplicationNotFoundError )
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can find open or curl" do
|
34
|
+
found = %w[ open curl ].any? do |app|
|
35
|
+
Launchy::Application.find_executable( app )
|
36
|
+
end
|
37
|
+
found.must_equal true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "does not find xyzzy" do
|
41
|
+
Launchy::Application.find_executable( "xyzzy" ).must_equal nil
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Launchy::Application::Browser do
|
4
|
+
before do
|
5
|
+
Launchy.reset_global_options
|
6
|
+
ENV['KDE_FULL_SESSION'] = "launchy"
|
7
|
+
@test_url = "http://example.com/"
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
Launchy.reset_global_options
|
12
|
+
ENV.delete( 'KDE_FULL_SESSION' )
|
13
|
+
end
|
14
|
+
|
15
|
+
{ 'windows' => 'start /b' ,
|
16
|
+
'darwin' => '/usr/bin/open',
|
17
|
+
'cygwin' => 'cmd /C start /b',
|
18
|
+
|
19
|
+
# when running these tests on a linux box, this test will fail
|
20
|
+
'linux' => nil }.each do |host_os, cmdline|
|
21
|
+
it "when host_os is '#{host_os}' the appropriate 'app_list' method is called" do
|
22
|
+
Launchy.host_os = host_os
|
23
|
+
browser = Launchy::Application::Browser.new
|
24
|
+
browser.app_list.first.must_equal cmdline
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
%w[ linux windows darwin cygwin ].each do |host_os|
|
29
|
+
it "the BROWSER environment variable overrides any host defaults on '#{host_os}'" do
|
30
|
+
ENV['BROWSER'] = "my_special_browser --new-tab '%s'"
|
31
|
+
Launchy.host_os = host_os
|
32
|
+
browser = Launchy::Application::Browser.new
|
33
|
+
cmd, args = browser.cmd_and_args( @test_url )
|
34
|
+
cmd.must_equal "my_special_browser --new-tab 'http://example.com/'"
|
35
|
+
args.must_equal []
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "handles a file on the file system when there is no file:// scheme" do
|
40
|
+
uri = Addressable::URI.parse( __FILE__ )
|
41
|
+
Launchy::Application::Browser.handles?( uri ).must_equal true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "handles the case where $BROWSER is set and no *nix desktop environment is found" do
|
45
|
+
ENV.delete( "KDE_FULL_SESSION" )
|
46
|
+
ENV.delete( "GNOME_DESKTOP_SESSION_ID" )
|
47
|
+
ENV['BROWSER'] = "do-this-instead"
|
48
|
+
Launchy.host_os = 'linux'
|
49
|
+
browser = Launchy::Application::Browser.new
|
50
|
+
browser.browser_cmdline.must_equal "do-this-instead"
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Launchy::Cli do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@old_stderr = $stderr
|
7
|
+
$stderr = StringIO.new
|
8
|
+
|
9
|
+
@old_stdout = $stdout
|
10
|
+
$stdout = StringIO.new
|
11
|
+
Launchy.reset_global_options
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
Launchy.reset_global_options
|
16
|
+
$stderr = @old_stderr
|
17
|
+
$stdout = @old_stdout
|
18
|
+
end
|
19
|
+
|
20
|
+
def cli_test( argv, env, exit_val, stderr_regex, stdout_regex )
|
21
|
+
begin
|
22
|
+
Launchy::Cli.new.run( argv, env )
|
23
|
+
rescue SystemExit => se
|
24
|
+
se.status.must_equal exit_val
|
25
|
+
$stderr.string.must_match stderr_regex if stderr_regex
|
26
|
+
$stdout.string.must_match stdout_regex if stdout_regex
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "exits 1 when invalid options are given" do
|
31
|
+
cli_test( %w[ -z foo ], {}, 1, /invalid option/, nil )
|
32
|
+
end
|
33
|
+
|
34
|
+
%w[ -h --help ].each do |opt|
|
35
|
+
it "output help and exits 0 when using #{opt}" do
|
36
|
+
cli_test( [ opt ], {}, 0, nil, /Print this message/m )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
%w[ -v --version ].each do |opt|
|
41
|
+
it "outputs version and exits 0 when using #{opt}" do
|
42
|
+
cli_test( [ opt ], {}, 0, nil, /Launchy version/ )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "leaves the url on argv after parsing" do
|
47
|
+
l = Launchy::Cli.new
|
48
|
+
argv = %w[ --debug --dry-run http://github.com/copiousfreetime/launchy ]
|
49
|
+
l.parse( argv , {} )
|
50
|
+
argv.size.must_equal 1
|
51
|
+
argv[0].must_equal "http://github.com/copiousfreetime/launchy"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "prints the command on stdout when using --dry-run" do
|
55
|
+
argv = %w[ --debug --dry-run http://github.com/copiousfreetime/launchy ]
|
56
|
+
rc = Launchy::Cli.new.good_run( argv, {} )
|
57
|
+
$stdout.string.must_match %r[github.com]
|
58
|
+
end
|
59
|
+
|
60
|
+
{
|
61
|
+
'--application' => [ :application, 'Browser'],
|
62
|
+
'--engine' => [ :ruby_engine, 'rbx'],
|
63
|
+
'--host-os' => [ :host_os, 'cygwin'] }.each_pair do |opt, val|
|
64
|
+
it "the commandline option #{opt} sets the program option #{val[0]}" do
|
65
|
+
argv = [ opt, val[1], "http://github.com/copiousfreetime/launchy" ]
|
66
|
+
l = Launchy::Cli.new
|
67
|
+
rc = l.parse( argv, {} )
|
68
|
+
rc.must_equal true
|
69
|
+
argv.size.must_equal 1
|
70
|
+
argv[0].must_equal "http://github.com/copiousfreetime/launchy"
|
71
|
+
l.options[val[0]].must_equal val[1]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
describe Launchy::Detect::HostOsFamily do
|
5
|
+
|
6
|
+
before do
|
7
|
+
Launchy.reset_global_options
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
Launchy.reset_global_options
|
12
|
+
end
|
13
|
+
|
14
|
+
YAML::load( IO.read( File.expand_path( "../../tattle-host-os.yaml", __FILE__ ) ) )['host_os'].keys.sort.each do |os|
|
15
|
+
it "OS family of #{os} is detected" do
|
16
|
+
Launchy::Detect::HostOsFamily.detect( os ).must_be_kind_of Launchy::Detect::HostOsFamily
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
{ 'mswin' => :windows?,
|
21
|
+
'darwin' => :darwin?,
|
22
|
+
'linux' => :nix?,
|
23
|
+
'cygwin' => :cygwin? }.each_pair do |os, method|
|
24
|
+
it "#{method} returns true for #{os} " do
|
25
|
+
Launchy::Detect::HostOsFamily.detect( os ).send( method ).must_equal true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "uses the global host_os overrides" do
|
30
|
+
ENV['LAUNCHY_HOST_OS'] = "fake-os-2"
|
31
|
+
lambda { Launchy::Detect::HostOsFamily.detect }.must_raise Launchy::Detect::HostOsFamily::NotFoundError
|
32
|
+
ENV.delete('LAUNCHY_HOST_OS')
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
it "does not find an os of 'dos'" do
|
37
|
+
lambda { Launchy::Detect::HostOsFamily.detect( 'dos' ) }.must_raise Launchy::Detect::HostOsFamily::NotFoundError
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Launchy::Detect::HostOs do
|
4
|
+
|
5
|
+
it "uses the defult host os from ruby's config" do
|
6
|
+
Launchy::Detect::HostOs.new.host_os.must_equal RbConfig::CONFIG['host_os']
|
7
|
+
end
|
8
|
+
|
9
|
+
it "uses the passed in value as the host os" do
|
10
|
+
Launchy::Detect::HostOs.new( "fake-os-1").host_os.must_equal "fake-os-1"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "uses the environment variable LAUNCHY_HOST_OS to override ruby's config" do
|
14
|
+
ENV['LAUNCHY_HOST_OS'] = "fake-os-2"
|
15
|
+
Launchy::Detect::HostOs.new.host_os.must_equal "fake-os-2"
|
16
|
+
ENV.delete('LAUNCHY_HOST_OS')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Launchy::Detect::NixDesktopEnvironment do
|
4
|
+
|
5
|
+
before do
|
6
|
+
Launchy.reset_global_options
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
Launchy.reset_global_options
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
{ "KDE_FULL_SESSION" => Launchy::Detect::NixDesktopEnvironment::Kde,
|
15
|
+
"GNOME_DESKTOP_SESSION_ID" => Launchy::Detect::NixDesktopEnvironment::Gnome }.each_pair do |k,v|
|
16
|
+
it "can detect the desktop environment of a *nix machine using ENV[#{k}]" do
|
17
|
+
ENV[k] = "launchy-test"
|
18
|
+
nix_env = Launchy::Detect::NixDesktopEnvironment.detect
|
19
|
+
nix_env.must_equal( v )
|
20
|
+
nix_env.browser.must_equal( v.browser )
|
21
|
+
ENV.delete( k )
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
it "returns nil if it cannot determine the *nix desktop environment" do
|
27
|
+
Launchy.host_os = "linux"
|
28
|
+
ENV.delete( "KDE_FULL_SESSION" )
|
29
|
+
ENV.delete( "GNOME_DESKTOP_SESSION_ID" )
|
30
|
+
Launchy::Detect::NixDesktopEnvironment.detect.must_equal( nil )
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Launchy::Detect::RubyEngine do
|
4
|
+
|
5
|
+
before do
|
6
|
+
Launchy.reset_global_options
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
Launchy.reset_global_options
|
11
|
+
end
|
12
|
+
|
13
|
+
%w[ ruby jruby rbx macruby ].each do |ruby|
|
14
|
+
it "detects the #{ruby} RUBY_ENGINE" do
|
15
|
+
Launchy::Detect::RubyEngine.detect( ruby ).ancestors.must_include Launchy::Detect::RubyEngine
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "uses the global ruby_engine overrides" do
|
20
|
+
ENV['LAUNCHY_RUBY_ENGINE'] = "rbx"
|
21
|
+
Launchy::Detect::RubyEngine.detect.must_equal Launchy::Detect::RubyEngine::Rbx
|
22
|
+
ENV.delete('LAUNCHY_RUBY_ENGINE')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "does not find a ruby engine of 'foo'" do
|
26
|
+
lambda { Launchy::Detect::RubyEngine.detect( 'foo' ) }.must_raise Launchy::Detect::RubyEngine::NotFoundError
|
27
|
+
end
|
28
|
+
|
29
|
+
{ 'rbx' => :rbx?,
|
30
|
+
'ruby' => :mri?,
|
31
|
+
'macruby' => :macruby?,
|
32
|
+
'jruby' => :jruby? }.each_pair do |engine, method|
|
33
|
+
it "#{method} returns true for #{engine} " do
|
34
|
+
Launchy::Detect::RubyEngine.detect( engine ).send( method ).must_equal true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|