clamshell 0.2
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/.gitignore +2 -0
- data/.rspec +1 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +22 -0
- data/README.md +126 -0
- data/Rakefile +4 -0
- data/bin/clamshell +14 -0
- data/clamshell.gemspec +27 -0
- data/lib/clamshell.rb +19 -0
- data/lib/clamshell/cli.rb +41 -0
- data/lib/clamshell/dsl.rb +8 -0
- data/lib/clamshell/environment.rb +94 -0
- data/lib/clamshell/version.rb +3 -0
- data/spec/clamshell/cli_spec.rb +73 -0
- data/spec/clamshell/environment_spec.rb +194 -0
- data/spec/fixtures/Shell.env +24 -0
- data/spec/spec_helper.rb +23 -0
- data/tasks/rspec.rake +22 -0
- metadata +112 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
rake (0.8.7)
|
6
|
+
rspec (2.4.0)
|
7
|
+
rspec-core (~> 2.4.0)
|
8
|
+
rspec-expectations (~> 2.4.0)
|
9
|
+
rspec-mocks (~> 2.4.0)
|
10
|
+
rspec-core (2.4.0)
|
11
|
+
rspec-expectations (2.4.0)
|
12
|
+
diff-lcs (~> 1.1.2)
|
13
|
+
rspec-mocks (2.4.0)
|
14
|
+
thor (0.14.6)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
rake
|
21
|
+
rspec
|
22
|
+
thor
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# Clamshell
|
2
|
+
|
3
|
+
Clamshell is a tool that converts generic shell statements into shell specific
|
4
|
+
statements that can be sourced to set up an environment.
|
5
|
+
|
6
|
+
## Motivation
|
7
|
+
|
8
|
+
While working on a legacy project that used tcsh as its primary shell, I wanted
|
9
|
+
to use bash, but realized that some of the old schoolers actually liked tcsh.
|
10
|
+
This was the compromise.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
gem install clamshell
|
15
|
+
|
16
|
+
## Setting up an environment file
|
17
|
+
|
18
|
+
Sometimes your project has a dependency that is shell specific (environment variables,
|
19
|
+
aliases). Setup a `Shell.env` file in your project root with the following:
|
20
|
+
|
21
|
+
Environment.setup ("bash") do
|
22
|
+
env_var "LC_CTYPE", "en_US"
|
23
|
+
env_var "PATH", :prepend => "~/bin", :delimiter => ":"
|
24
|
+
env_var "PATH", :append => "/usr/bin", :delimiter => ":"
|
25
|
+
env_alias editor "vim"
|
26
|
+
end
|
27
|
+
|
28
|
+
You can convert these statements to bash statements as follows:
|
29
|
+
|
30
|
+
clamshell convert SHELL.env
|
31
|
+
|
32
|
+
which will print the following to standard out (or to a file using the `--shell-out=FILE` flag).
|
33
|
+
|
34
|
+
export LC_CTYPE=en_US
|
35
|
+
export PATH=~/bin:$PATH
|
36
|
+
export PATH=$PATH:/usr/bin
|
37
|
+
alias editor=vim
|
38
|
+
|
39
|
+
### Shell independence
|
40
|
+
|
41
|
+
Your environment file doesn't even need to specify a shell:
|
42
|
+
|
43
|
+
Environment.setup do
|
44
|
+
...
|
45
|
+
end
|
46
|
+
|
47
|
+
But you must pass the flag `--shell=SHELLNAME`.
|
48
|
+
Best practices for multi-shell environments use the following command:
|
49
|
+
|
50
|
+
--shell=`ps -p $$ | awk 'NR==2 {print $4}'`
|
51
|
+
|
52
|
+
which will set the shell flag to the type of shell currently being ran.
|
53
|
+
|
54
|
+
Currently, the shells supported are tcsh and bash. However, I am assuming that
|
55
|
+
csh and zsh are supported as well since they are closely related to tcsh and
|
56
|
+
bash, respectively. Hence, aliases are set up for their respective shells.
|
57
|
+
|
58
|
+
### Generic shell statements
|
59
|
+
|
60
|
+
You can also call generic shell statements that are valid in all shells:
|
61
|
+
|
62
|
+
echo -n FOO
|
63
|
+
|
64
|
+
But you must be verbose that you are doing so:
|
65
|
+
|
66
|
+
cmd "echo -n FOO"
|
67
|
+
|
68
|
+
### Unique shell statements
|
69
|
+
|
70
|
+
If you need to setup the environment and produce a shell command that is
|
71
|
+
different depending on the shell being used, the global variable `$SHELL`
|
72
|
+
is available:
|
73
|
+
|
74
|
+
Environment.setup do
|
75
|
+
if $SHELL == "tcsh"
|
76
|
+
cmd "unlimit coredumpsize"
|
77
|
+
elsif $SHELL == "bash"
|
78
|
+
cmd "ulimit -c unlimited"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
### Splitting the environment
|
83
|
+
|
84
|
+
If you want to split your environment files up, the `include_file` command
|
85
|
+
is as your disposal.
|
86
|
+
|
87
|
+
Environment.setup do
|
88
|
+
include_file "/path/to/another.file"
|
89
|
+
end
|
90
|
+
|
91
|
+
`another.file`'s contents:
|
92
|
+
|
93
|
+
env_var "CLASSPATH", :append => "~/java"
|
94
|
+
cmd "echo FOOBAR"
|
95
|
+
|
96
|
+
If you definitely need to split your environment up, take this approach.
|
97
|
+
|
98
|
+
#### Pitfall
|
99
|
+
|
100
|
+
Another approach you might have considered is to generate multiple
|
101
|
+
files and source each one.
|
102
|
+
|
103
|
+
__DON'T!__
|
104
|
+
|
105
|
+
In tcsh, appending to an environment variable that doesn't exist throws an
|
106
|
+
error. There is an internal mechanism in clamshell that detects if an
|
107
|
+
environment variable doesn't exist. If it doesn't it creates one and sets
|
108
|
+
it to an empty string before appending.
|
109
|
+
|
110
|
+
So the previous example would generate the following statements:
|
111
|
+
|
112
|
+
setenv CLASSPATH ""
|
113
|
+
setenv CLASSPATH ${CLASSPATH}:~/java
|
114
|
+
echo FOOBAR
|
115
|
+
|
116
|
+
This can cause some headaches if more than one file is generated.
|
117
|
+
|
118
|
+
*Rule of thumb: generate one file, source one file.*
|
119
|
+
|
120
|
+
### Conversion on the fly
|
121
|
+
|
122
|
+
If you need to convert a generic statement without using a file, you can
|
123
|
+
use the `convert_string` action, but you must specify a shell.
|
124
|
+
|
125
|
+
clamshell convert_string "env_var 'FOO' 'BAR'" --shell=tcsh
|
126
|
+
=> setenv FOO BAR\n
|
data/Rakefile
ADDED
data/bin/clamshell
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/clamshell'
|
4
|
+
require File.dirname(__FILE__) + '/../lib/clamshell/cli'
|
5
|
+
|
6
|
+
begin
|
7
|
+
Clamshell::CLI.start
|
8
|
+
rescue StandardError => e
|
9
|
+
puts e.message
|
10
|
+
exit 1
|
11
|
+
rescue Interrupt => e
|
12
|
+
puts "\nQuitting..."
|
13
|
+
exit 1
|
14
|
+
end
|
data/clamshell.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "clamshell/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "clamshell"
|
7
|
+
s.version = Clamshell::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Eric Thomas"]
|
10
|
+
s.email = ["eric.l.m.thomas@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/et/clamshell"
|
12
|
+
s.summary = %q{Clamshell manages your environment in a shell-independent setup.}
|
13
|
+
s.description = %q{Clamshell allows you to setup shell statements which configure
|
14
|
+
your project's environment that doesn't care about which shell
|
15
|
+
(bash, tcsh) the target user will be using.}
|
16
|
+
|
17
|
+
s.rubyforge_project = "clamshell"
|
18
|
+
|
19
|
+
s.add_dependency('thor')
|
20
|
+
|
21
|
+
s.add_development_dependency('rspec')
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
data/lib/clamshell.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
module Clamshell
|
5
|
+
|
6
|
+
autoload :Dsl, 'clamshell/dsl'
|
7
|
+
autoload :Environment, 'clamshell/environment'
|
8
|
+
|
9
|
+
class SafeExit < StandardError; end
|
10
|
+
class DslError < StandardError; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_writer :settings
|
14
|
+
|
15
|
+
def settings
|
16
|
+
@settings ||= {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Clamshell
|
4
|
+
class CLI < Thor
|
5
|
+
|
6
|
+
def initialize(*)
|
7
|
+
super
|
8
|
+
Clamshell.settings = options
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "convert FILE", "Converts an environment file to shell statements"
|
12
|
+
method_option :shell, :type => :string, :banner => "Shell to create statements for"
|
13
|
+
method_option :shell_out, :type => :string, :banner => "File to output to"
|
14
|
+
def convert(file)
|
15
|
+
check_file(file)
|
16
|
+
|
17
|
+
file_out = Clamshell.settings[:shell_out]
|
18
|
+
if file_out
|
19
|
+
File.open(file_out, "w") {|f| f.write(Dsl.build(file) + "\n") }
|
20
|
+
else
|
21
|
+
puts Dsl.build(file)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "convert_string STRING", "Converts a string on the fly."
|
26
|
+
method_option :shell, :type => :string, :banner => "Shell to create statements for", :required => true
|
27
|
+
def convert_string(string)
|
28
|
+
input = <<-I
|
29
|
+
Environment.setup do
|
30
|
+
#{string}
|
31
|
+
end
|
32
|
+
I
|
33
|
+
puts instance_eval(input).inspect
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def check_file(file)
|
38
|
+
abort("File: #{file}, not found.") unless File.exist?(file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Clamshell
|
2
|
+
class Environment
|
3
|
+
|
4
|
+
attr_reader :shell
|
5
|
+
|
6
|
+
def self.setup(shell = nil, &block)
|
7
|
+
$SHELL = shell ||= Clamshell.settings[:shell]
|
8
|
+
raise "No shell specified" unless shell
|
9
|
+
|
10
|
+
e = new(shell)
|
11
|
+
e.instance_eval(&block)
|
12
|
+
return e
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(shell)
|
16
|
+
@shell = case shell
|
17
|
+
when "csh", "tcsh" then TcshAdapter
|
18
|
+
when "zsh", "bash" then BashAdapter
|
19
|
+
else
|
20
|
+
raise "Unsupported shell"
|
21
|
+
end
|
22
|
+
@stmts = []
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def env_var(name, *args)
|
27
|
+
case
|
28
|
+
when args[0].class == String # direct assignment
|
29
|
+
@stmts << @shell.env_var(name, args[0])
|
30
|
+
|
31
|
+
else # appending or prepending to existing variable
|
32
|
+
|
33
|
+
# In csh, concatting to an undefined environment variable
|
34
|
+
# results in an error. This is a safe guard that sets the
|
35
|
+
# environment variable to an empty string before appending/prepending.
|
36
|
+
unless ENV[name]
|
37
|
+
ENV[name] = %q{""}
|
38
|
+
@stmts << @shell.env_var(name, ENV[name])
|
39
|
+
end
|
40
|
+
|
41
|
+
delimiter = args[0][:delimiter] || ""
|
42
|
+
if args[0][:prepend]
|
43
|
+
val = args[0][:prepend] + delimiter + "${#{name}}"
|
44
|
+
elsif args[0][:append]
|
45
|
+
val = "${#{name}}" + delimiter + args[0][:append]
|
46
|
+
else
|
47
|
+
raise DslError, "Must specify prepend or append"
|
48
|
+
end
|
49
|
+
@stmts << @shell.env_var(name, val)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def env_alias(name, val)
|
54
|
+
@stmts << @shell.env_alias(name, val)
|
55
|
+
end
|
56
|
+
|
57
|
+
def cmd(stmt)
|
58
|
+
@stmts << stmt
|
59
|
+
end
|
60
|
+
|
61
|
+
def include_file(file)
|
62
|
+
instance_eval File.read(file), file
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
@stmts.join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def quote(val)
|
71
|
+
%Q{"#{val}"}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class BashAdapter
|
76
|
+
def self.env_var(name, val)
|
77
|
+
"export #{name}=#{val}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.env_alias(name, val)
|
81
|
+
"alias #{name}=#{val}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class TcshAdapter
|
86
|
+
def self.env_var(name, val)
|
87
|
+
"setenv #{name} #{val}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.env_alias(name, val)
|
91
|
+
"alias #{name} #{val}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'clamshell/cli'
|
5
|
+
|
6
|
+
describe Clamshell::CLI do
|
7
|
+
|
8
|
+
# explicit subject
|
9
|
+
subject { Clamshell::CLI }
|
10
|
+
|
11
|
+
after :each do
|
12
|
+
Clamshell.settings = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#initialize" do
|
16
|
+
|
17
|
+
it "shows the help listing with no args" do
|
18
|
+
capture(:stdout){ subject.start }.should =~ /Tasks:/
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#convert" do
|
23
|
+
before do
|
24
|
+
@action = "convert"
|
25
|
+
@file_in = "#{FIXTURES_DIR}/Shell.env"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "shows an error for a file not found" do
|
29
|
+
test_missing_file([@action, "missing_file"])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "#--shell, it should set a shell option" do
|
33
|
+
capture(:stdout){ subject.start([@action, @file_in, "--shell=bash"])}
|
34
|
+
Clamshell.settings[:shell].should == "bash"
|
35
|
+
end
|
36
|
+
|
37
|
+
context "output" do
|
38
|
+
it "should print to standard out" do
|
39
|
+
capture(:stdout){ subject.start [@action, @file_in]}.should_not be_empty
|
40
|
+
end
|
41
|
+
|
42
|
+
it "#--shell-out, should output to a file" do
|
43
|
+
file = mock('file')
|
44
|
+
File.should_receive(:open).with("filename", "w").and_yield(file)
|
45
|
+
file.should_receive(:write)
|
46
|
+
subject.start ["convert", @file_in, "--shell-out=filename"]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#convert_string" do
|
52
|
+
before do
|
53
|
+
@action = "convert_string"
|
54
|
+
@string_in = %q{env_var "FOO", "BAR"}
|
55
|
+
end
|
56
|
+
|
57
|
+
it "show an error when --shell is not used" do
|
58
|
+
capture(:stderr) {
|
59
|
+
subject.start [@action, @string_in]
|
60
|
+
}.should =~ /No value provided for required options '--shell'/
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should convert a string" do
|
64
|
+
capture(:stdout) {
|
65
|
+
subject.start [@action, @string_in, "--shell=tcsh"]
|
66
|
+
}.should == "setenv FOO BAR\n"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_missing_file(argv)
|
72
|
+
expect { capture(:stderr){ subject.start(argv)}}.to raise_error(SystemExit, /File: \S*, not found/)
|
73
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Clamshell::Environment do
|
4
|
+
|
5
|
+
describe "setup" do
|
6
|
+
it "should raise an error when no shell is given" do
|
7
|
+
expect { Clamshell::Environment.setup( & proc{})}.to raise_error(RuntimeError, /No shell specified/)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return an Environment object" do
|
11
|
+
Clamshell::Environment.setup("bash", & proc{}).should be_an_instance_of Clamshell::Environment
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "shell initializer" do
|
16
|
+
it "should set up a tcsh shell" do
|
17
|
+
Clamshell::Environment.new("tcsh").shell.should be Clamshell::TcshAdapter
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should set up a csh(tcsh) shell" do
|
21
|
+
Clamshell::Environment.new("csh").shell.should be Clamshell::TcshAdapter
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should set up a bash shell" do
|
25
|
+
Clamshell::Environment.new("bash").shell.should be Clamshell::BashAdapter
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should set up a zsh(bash) shell" do
|
29
|
+
Clamshell::Environment.new("zsh").shell.should be Clamshell::BashAdapter
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should raise an error on an unknown shell" do
|
33
|
+
expect { Clamshell::Environment.new("sea")}.to raise_error(RuntimeError, /Unsupported shell/)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'shell specific' do
|
38
|
+
before :each do
|
39
|
+
@bash = Clamshell::Environment.new("bash")
|
40
|
+
@tcsh = Clamshell::Environment.new("tcsh")
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "env_alias" do
|
44
|
+
it "should set a tcsh alias" do
|
45
|
+
@tcsh.env_alias("FOO", "BAR")
|
46
|
+
@tcsh.inspect.should == %q{alias FOO BAR}
|
47
|
+
end
|
48
|
+
it "should set a bash alias" do
|
49
|
+
@bash.env_alias("FOO", "BAR")
|
50
|
+
@bash.inspect.should == %q{alias FOO=BAR}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "environment variable" do
|
55
|
+
describe "set" do
|
56
|
+
|
57
|
+
it "should set up a bash environment variable" do
|
58
|
+
@bash.env_var("FOO", "BAR")
|
59
|
+
@bash.inspect.should == "export FOO=BAR"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should set up a tcsh environment variable" do
|
63
|
+
@tcsh.env_var("FOO", "BAR")
|
64
|
+
@tcsh.inspect.should == "setenv FOO BAR"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "concat" do
|
69
|
+
|
70
|
+
before :all do
|
71
|
+
ENV['FOO'] = 'FOO'
|
72
|
+
end
|
73
|
+
|
74
|
+
after :all do
|
75
|
+
ENV['FOO'] = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "prepend" do
|
79
|
+
it "should prepend to a bash environment variable" do
|
80
|
+
@bash.env_var("FOO", :prepend => "BAR")
|
81
|
+
@bash.inspect.should == "export FOO=BAR${FOO}"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should prepend to a tcsh environment variable" do
|
85
|
+
@tcsh.env_var("FOO", :prepend => "BAR")
|
86
|
+
@tcsh.inspect.should == "setenv FOO BAR${FOO}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "append" do
|
91
|
+
it "should append to a bash environment variable" do
|
92
|
+
@bash.env_var("FOO", :append => "BAR")
|
93
|
+
@bash.inspect.should == %q{export FOO=${FOO}BAR}
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should append to a tcsh environment variable" do
|
97
|
+
@tcsh.env_var("FOO", :append => "BAR")
|
98
|
+
@tcsh.inspect.should == %q{setenv FOO ${FOO}BAR}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "safe concat" do
|
103
|
+
before :each do
|
104
|
+
ENV['UNDEFINED'] = nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should set the environment variable to empty string if not set" do
|
108
|
+
@tcsh.env_var("UNDEFINED", :append => "FOO")
|
109
|
+
@tcsh.inspect.should == %Q{setenv UNDEFINED ""\nsetenv UNDEFINED ${UNDEFINED}FOO}
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should not try to keep setting the environment variable" do
|
113
|
+
@tcsh.env_var("UNDEFINED", :append => "FOO")
|
114
|
+
@tcsh.env_var("UNDEFINED", :append => "BAR")
|
115
|
+
@tcsh.inspect.should == %Q{setenv UNDEFINED ""\nsetenv UNDEFINED ${UNDEFINED}FOO\nsetenv UNDEFINED ${UNDEFINED}BAR}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "delimiter" do
|
121
|
+
it "should raise an error when prepend/append not defined" do
|
122
|
+
expect { @bash.env_var("FOO", :delimiter => ":")}.to raise_error(Clamshell::DslError, /Must specify prepend or append/)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should use a delimiter to append a variable" do
|
126
|
+
@bash.env_var("FOO", :append => "BAR", :delimiter => ":")
|
127
|
+
@bash.inspect.should == %q{export FOO=${FOO}:BAR}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "generic statement" do
|
134
|
+
it "should print out what it receives" do
|
135
|
+
@bash.cmd "echo blah"
|
136
|
+
@bash.inspect.should == %q{echo blah}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "include_file" do
|
141
|
+
it "should include a file" do
|
142
|
+
input = <<-I.gsub(/^\s+/, "").chop
|
143
|
+
env_var "FOO", "BAR"
|
144
|
+
cmd "echo blah"
|
145
|
+
I
|
146
|
+
File.stub!(:read).with("included_file.txt").and_return(input)
|
147
|
+
@bash.include_file("included_file.txt")
|
148
|
+
@bash.inspect.should == %Q{export FOO=BAR\necho blah}
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "to_s" do
|
154
|
+
it "should convert a block" do
|
155
|
+
block = proc {
|
156
|
+
env_var "FOO", "BAR"
|
157
|
+
env_var "BAZ", "BUZZ"
|
158
|
+
}
|
159
|
+
|
160
|
+
out = <<-O.gsub(/^\s+/, "").chop
|
161
|
+
export FOO=BAR
|
162
|
+
export BAZ=BUZZ
|
163
|
+
O
|
164
|
+
|
165
|
+
Clamshell::Environment.setup("bash", &block).inspect.should == out
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should convert a block with generic statements" do
|
169
|
+
block = proc {
|
170
|
+
env_var "FOO", "BAR"
|
171
|
+
cmd "echo -n blah"
|
172
|
+
env_var "BAZ", "BUZZ"
|
173
|
+
}
|
174
|
+
|
175
|
+
out = <<-O.gsub(/^\s+/, "").chop
|
176
|
+
setenv FOO BAR
|
177
|
+
echo -n blah
|
178
|
+
setenv BAZ BUZZ
|
179
|
+
O
|
180
|
+
Clamshell::Environment.setup("tcsh", &block).inspect.should == out
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should provide a $SHELL global variable" do
|
184
|
+
block = proc {
|
185
|
+
if $SHELL == "tcsh"
|
186
|
+
cmd "unlimited coredumpsize"
|
187
|
+
elsif $SHELL == "bash"
|
188
|
+
cmd "ulimit -c unlimited"
|
189
|
+
end
|
190
|
+
}
|
191
|
+
Clamshell::Environment.setup("tcsh", &block).inspect.should == "unlimited coredumpsize"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
######################################
|
2
|
+
# The following will return:
|
3
|
+
# export LC_CTYPE=en_US
|
4
|
+
# export PATH=/usr/bin
|
5
|
+
# export PATH=~/usr/bin:${PATH}
|
6
|
+
# export PATH=~alice/bin:${PATH}
|
7
|
+
# export PATH=~bob/bin:${PATH}
|
8
|
+
# export PATH=~eve/bin:${PATH}
|
9
|
+
# alias EDITOR=vim
|
10
|
+
# echo -e FOO
|
11
|
+
#
|
12
|
+
Environment.setup("bash") do
|
13
|
+
env_var "LC_CTYPE", "en_US"
|
14
|
+
env_var "PATH", "/usr/bin"
|
15
|
+
env_var "PATH", :prepend => "~/usr/bin", :delimiter => ":"
|
16
|
+
|
17
|
+
["~alice/bin", "~bob/bin", "~eve/bin"].each do |p|
|
18
|
+
env_var "PATH", :prepend => p, :delimiter => ":"
|
19
|
+
end
|
20
|
+
|
21
|
+
env_alias "EDITOR", "vim"
|
22
|
+
|
23
|
+
cmd "echo -e FOO"
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
require 'clamshell'
|
3
|
+
require 'rspec'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
FIXTURES_DIR = File.dirname(__FILE__) + '/fixtures'
|
7
|
+
|
8
|
+
ARGV.clear
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
def capture(stream)
|
12
|
+
begin
|
13
|
+
stream = stream.to_s
|
14
|
+
eval "$#{stream} = StringIO.new"
|
15
|
+
yield
|
16
|
+
result = eval("$#{stream}").string
|
17
|
+
ensure
|
18
|
+
eval("$#{stream} = #{stream.upcase}")
|
19
|
+
end
|
20
|
+
|
21
|
+
result
|
22
|
+
end
|
23
|
+
end
|
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'rake'
|
3
|
+
require 'rspec'
|
4
|
+
rescue LoadError
|
5
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
6
|
+
require 'rspec'
|
7
|
+
end
|
8
|
+
begin
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
rescue LoadError
|
11
|
+
puts <<-EOS
|
12
|
+
To use rspec for testing you must install rspec gem:
|
13
|
+
gem install rspec
|
14
|
+
EOS
|
15
|
+
exit(0)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Run all of the spec tests"
|
19
|
+
Rspec::Core::RakeTask.new do |t|
|
20
|
+
t.rspec_opts = ['--options', "spec/spec.opts"]
|
21
|
+
t.pattern = FileList['spec/**/*_spec.rb']
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: clamshell
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
version: "0.2"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Eric Thomas
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2011-04-02 00:00:00 -04:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: thor
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rspec
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :development
|
44
|
+
version_requirements: *id002
|
45
|
+
description: |-
|
46
|
+
Clamshell allows you to setup shell statements which configure
|
47
|
+
your project's environment that doesn't care about which shell
|
48
|
+
(bash, tcsh) the target user will be using.
|
49
|
+
email:
|
50
|
+
- eric.l.m.thomas@gmail.com
|
51
|
+
executables:
|
52
|
+
- clamshell
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- .rspec
|
60
|
+
- Gemfile
|
61
|
+
- Gemfile.lock
|
62
|
+
- README.md
|
63
|
+
- Rakefile
|
64
|
+
- bin/clamshell
|
65
|
+
- clamshell.gemspec
|
66
|
+
- lib/clamshell.rb
|
67
|
+
- lib/clamshell/cli.rb
|
68
|
+
- lib/clamshell/dsl.rb
|
69
|
+
- lib/clamshell/environment.rb
|
70
|
+
- lib/clamshell/version.rb
|
71
|
+
- spec/clamshell/cli_spec.rb
|
72
|
+
- spec/clamshell/environment_spec.rb
|
73
|
+
- spec/fixtures/Shell.env
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
- tasks/rspec.rake
|
76
|
+
has_rdoc: true
|
77
|
+
homepage: https://github.com/et/clamshell
|
78
|
+
licenses: []
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project: clamshell
|
104
|
+
rubygems_version: 1.3.7
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Clamshell manages your environment in a shell-independent setup.
|
108
|
+
test_files:
|
109
|
+
- spec/clamshell/cli_spec.rb
|
110
|
+
- spec/clamshell/environment_spec.rb
|
111
|
+
- spec/fixtures/Shell.env
|
112
|
+
- spec/spec_helper.rb
|