wijet-launchy 2.0.6
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/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
|