shelr 0.9.7
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/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +31 -0
- data/LICENSE.txt +674 -0
- data/README.md +41 -0
- data/Rakefile +46 -0
- data/TODO.org +7 -0
- data/VERSION +1 -0
- data/bin/shelr +63 -0
- data/lib/shelr/player.rb +92 -0
- data/lib/shelr/publisher.rb +44 -0
- data/lib/shelr/recorder.rb +93 -0
- data/lib/shelr.rb +33 -0
- data/shelr.1 +107 -0
- data/shelr.1.ronn +63 -0
- data/spec/shelr/player_spec.rb +0 -0
- data/spec/shelr/publisher_spec.rb +9 -0
- data/spec/shelr/recorder_spec.rb +41 -0
- data/spec/shelr_spec.rb +15 -0
- data/spec/spec_helper.rb +14 -0
- metadata +128 -0
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Shelr -- screencasting for [shell ninjas][TV].
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
You'll need ruby and rubygems installed.
|
6
|
+
|
7
|
+
gem install shelr
|
8
|
+
|
9
|
+
See [shellcast](http://shelr.tv/records/4d1c5458905ba77eb7000002) for details :)
|
10
|
+
|
11
|
+
## Watching other's records
|
12
|
+
|
13
|
+
shelr play http://shelr.tv/records/4d1c5458905ba77eb7000002
|
14
|
+
|
15
|
+
You can watch them online at [http://shelr.tv/][TV]
|
16
|
+
|
17
|
+
## Recording
|
18
|
+
|
19
|
+
shelr record
|
20
|
+
...
|
21
|
+
do something in your shell
|
22
|
+
..
|
23
|
+
exit
|
24
|
+
|
25
|
+
## Publishing
|
26
|
+
|
27
|
+
shelr list
|
28
|
+
<select id of your record>
|
29
|
+
shelr push <ID>
|
30
|
+
|
31
|
+
## Dependencies
|
32
|
+
|
33
|
+
You need `script` and `scriptreplay` tools from BSD Utils.
|
34
|
+
Tey are already installed if You use Debian/Ubuntu/BSD variants.
|
35
|
+
Not sure about other OSes.
|
36
|
+
|
37
|
+
## Copyright
|
38
|
+
|
39
|
+
Copyright (c) 2010 Antono Vasiljev. See LICENSE.txt for further details.
|
40
|
+
|
41
|
+
[TV]: http://shelr.tv/ "Shell records from shell ninjas"
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
begin
|
5
|
+
Bundler.setup(:default, :development)
|
6
|
+
rescue Bundler::BundlerError => e
|
7
|
+
$stderr.puts e.message
|
8
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
9
|
+
exit e.status_code
|
10
|
+
end
|
11
|
+
require 'rake'
|
12
|
+
|
13
|
+
require 'jeweler'
|
14
|
+
Jeweler::Tasks.new do |gem|
|
15
|
+
gem.name = "shelr"
|
16
|
+
gem.homepage = "http://shelr.tv/"
|
17
|
+
gem.license = "GPLv3"
|
18
|
+
gem.summary = %Q{Screencasts for Shell Ninjas}
|
19
|
+
gem.description = %Q{Screencast utility for unix shell junkies :)}
|
20
|
+
gem.email = "self@antono.info"
|
21
|
+
gem.authors = ["Antono Vasiljev", "Pete Clark"]
|
22
|
+
end
|
23
|
+
Jeweler::RubygemsDotOrgTasks.new
|
24
|
+
|
25
|
+
require 'rspec/core'
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
28
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
32
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
33
|
+
spec.rcov = true
|
34
|
+
end
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "shelr #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/TODO.org
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
* DONE Remove dependencies for easier packaging
|
2
|
+
* TODO Port to termrec or ttyrec
|
3
|
+
git clone http://angband.pl/git/termrec
|
4
|
+
http://angband.pl/termrec.html
|
5
|
+
* TODO Port Figlet from artii gem to ruby 1.9.2
|
6
|
+
and use it instead hardcoded headers and footers
|
7
|
+
* TODO Think about terminal setup before shellcasting
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9.7
|
data/bin/shelr
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'shelr'
|
7
|
+
|
8
|
+
BASENAME = File.basename(__FILE__)
|
9
|
+
HELP = <<-HELP
|
10
|
+
|
11
|
+
Usage: #{BASENAME} command [arg]
|
12
|
+
|
13
|
+
Commands:
|
14
|
+
setup API_KEY - setup
|
15
|
+
record - record new shellcast
|
16
|
+
push RECORD_ID - publish
|
17
|
+
list - print list of records
|
18
|
+
play RECORD_ID - play local record
|
19
|
+
play RECORD_URL - play remote record
|
20
|
+
|
21
|
+
Visit: http://shelr.tv/ for more info.
|
22
|
+
|
23
|
+
HELP
|
24
|
+
|
25
|
+
case ARGV[0]
|
26
|
+
when '-h', '--help'
|
27
|
+
puts HELP
|
28
|
+
when 'record'
|
29
|
+
Shelr::Recorder.record!
|
30
|
+
when 'list'
|
31
|
+
Shelr::Player.list
|
32
|
+
when 'play'
|
33
|
+
if ARGV[1]
|
34
|
+
if ARGV[1] =~ /^http:.*/
|
35
|
+
Shelr::Player.play_remote(ARGV[1])
|
36
|
+
else
|
37
|
+
Shelr::Player.play(ARGV[1])
|
38
|
+
end
|
39
|
+
else
|
40
|
+
puts "Missing id for shellcast"
|
41
|
+
Shelr::Player.list
|
42
|
+
puts "Select one..."
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
when 'push'
|
46
|
+
if ARGV[1]
|
47
|
+
Shelr::Publisher.new.publish(ARGV[1])
|
48
|
+
else
|
49
|
+
puts "What do you want to publish?"
|
50
|
+
Shelr::Player.list
|
51
|
+
puts "Select one..."
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
when 'setup'
|
55
|
+
if ARGV[1]
|
56
|
+
Shelr.api_key = ARGV[1]
|
57
|
+
else
|
58
|
+
puts "\n\tUsage: #{BASENAME} setup API_KEY\n\n"
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
else
|
62
|
+
puts HELP
|
63
|
+
end
|
data/lib/shelr/player.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'net/http'
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
module Shelr
|
8
|
+
class Player
|
9
|
+
|
10
|
+
HEADER = <<-EOH
|
11
|
+
|
12
|
+
____ _ _ _ ____ _
|
13
|
+
/ ___|| |__ ___| | |/ ___|__ _ ___| |_
|
14
|
+
\___ \| '_ \ / _ \ | | | / _` / __| __|
|
15
|
+
___) | | | | __/ | | |__| (_| \__ \ |_
|
16
|
+
|____/|_| |_|\___|_|_|\____\__,_|___/\__|
|
17
|
+
|
18
|
+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
19
|
+
|
20
|
+
|
21
|
+
EOH
|
22
|
+
|
23
|
+
FOOTER = <<-EOF
|
24
|
+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
25
|
+
_____ _ _____ _
|
26
|
+
|_ _| |__ ___ | ____|_ __ __| |
|
27
|
+
| | | '_ \ / _ \ | _| | '_ \ / _` |
|
28
|
+
| | | | | | __/ | |___| | | | (_| |
|
29
|
+
|_| |_| |_|\___| |_____|_| |_|\__,_|
|
30
|
+
|
31
|
+
EOF
|
32
|
+
|
33
|
+
|
34
|
+
def self.play(id)
|
35
|
+
new(id).play
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.play_remote(url)
|
39
|
+
puts ".==> Fetching #{url}"
|
40
|
+
resp = Net::HTTP.get(URI.parse(url))
|
41
|
+
parts = JSON.parse(resp)
|
42
|
+
|
43
|
+
print "Title:\t"
|
44
|
+
puts parts['title']
|
45
|
+
print "Description:\t"
|
46
|
+
puts parts['description']
|
47
|
+
|
48
|
+
Dir.mktmpdir do |dir|
|
49
|
+
%w(typescript timing).each do |type|
|
50
|
+
File.open(File.join(dir, type), 'w') { |f| f.puts(parts[type]) }
|
51
|
+
end
|
52
|
+
puts "+==> Playing... "
|
53
|
+
system "scriptreplay #{File.join(dir, 'timing')} #{File.join(dir, 'typescript')}"
|
54
|
+
puts "+\n+"
|
55
|
+
print "| Title:\t"
|
56
|
+
puts parts['title']
|
57
|
+
print "| Description:\t"
|
58
|
+
puts parts['description']
|
59
|
+
puts "`==> The end... "
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.list
|
64
|
+
Dir[File.join(Shelr::DATA_DIR, "**", 'meta')].each do |path|
|
65
|
+
metadata = JSON.parse(IO.read(path))
|
66
|
+
puts "#{metadata["created_at"]}: #{metadata["title"]}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(id)
|
71
|
+
@record_id = id
|
72
|
+
end
|
73
|
+
|
74
|
+
def play
|
75
|
+
puts HEADER
|
76
|
+
puts
|
77
|
+
system(scriptreplay_cmd)
|
78
|
+
puts
|
79
|
+
puts FOOTER
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def record_file(name)
|
85
|
+
File.join(Shelr.data_dir(@record_id), name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def scriptreplay_cmd
|
89
|
+
"scriptreplay #{record_file('timing')} #{record_file('typescript')}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Shelr
|
5
|
+
class Publisher
|
6
|
+
|
7
|
+
def publish(id)
|
8
|
+
uri = URI.parse(Shelr::API_URL + '/records')
|
9
|
+
params = { 'record' => prepare(id) }
|
10
|
+
params.merge!({'api_key' => Shelr.api_key}) if api_key
|
11
|
+
res = Net::HTTP.post_form(uri, params)
|
12
|
+
res = JSON.parse(res.body)
|
13
|
+
if res['ok']
|
14
|
+
puts res['message']
|
15
|
+
puts Shelr::API_URL + '/records/' + res['id']
|
16
|
+
else
|
17
|
+
puts res['message']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def api_key
|
22
|
+
unless Shelr.api_key
|
23
|
+
print 'Paste your API KEY [or Enter to publish as Anonymous]: '
|
24
|
+
key = STDIN.gets.strip
|
25
|
+
Shelr.api_key = key unless key.empty?
|
26
|
+
end
|
27
|
+
Shelr.api_key
|
28
|
+
end
|
29
|
+
|
30
|
+
def prepare(id)
|
31
|
+
out = {}
|
32
|
+
['meta', 'timing', 'typescript'].each do |file|
|
33
|
+
out[file] = File.read(File.join(Shelr.data_dir(id), file))
|
34
|
+
end
|
35
|
+
meta = JSON.parse(out.delete('meta'))
|
36
|
+
meta.each { |k,v| out[k] = v }
|
37
|
+
print 'Description: '
|
38
|
+
out['description'] = STDIN.gets.strip
|
39
|
+
print 'Tags (ex: howto, linux): '
|
40
|
+
out['tags'] = STDIN.gets.strip
|
41
|
+
return out.to_json
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Shelr
|
3
|
+
class Recorder
|
4
|
+
|
5
|
+
HEADER = <<-EOH
|
6
|
+
____ _ _
|
7
|
+
| _ \ ___ ___ ___ _ __ __| (_)_ __ __ _
|
8
|
+
| |_) / _ \/ __/ _ \| '__/ _` | | '_ \ / _` |
|
9
|
+
| _ < __/ (_| (_) | | | (_| | | | | | (_| |
|
10
|
+
|_| \_\___|\___\___/|_| \__,_|_|_| |_|\__, |
|
11
|
+
|___/
|
12
|
+
EOH
|
13
|
+
|
14
|
+
FOOTER = <<-EOF
|
15
|
+
_____ _ _ _ _
|
16
|
+
| ___(_)_ __ (_)___| |__ ___ __| |
|
17
|
+
| |_ | | '_ \| / __| '_ \ / _ \/ _` |
|
18
|
+
| _| | | | | | \__ \ | | | __/ (_| |
|
19
|
+
|_| |_|_| |_|_|___/_| |_|\___|\__,_|
|
20
|
+
|
21
|
+
EOF
|
22
|
+
|
23
|
+
def self.record!
|
24
|
+
new.record!
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@meta = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def record!
|
32
|
+
check_record_dir
|
33
|
+
request_metadata
|
34
|
+
puts HEADER
|
35
|
+
puts "Your session started"
|
36
|
+
puts "Type Ctrl+D or exit to finish recording"
|
37
|
+
system(script_cmd)
|
38
|
+
restore_terminal
|
39
|
+
puts FOOTER
|
40
|
+
puts
|
41
|
+
puts "hint $ #{Shelr::APP_NAME} play #{record_id}"
|
42
|
+
puts "hint $ #{Shelr::APP_NAME} push #{record_id}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def request_metadata
|
46
|
+
init_terminal
|
47
|
+
print "Provide HUMAN NAME for Your shellcast: "
|
48
|
+
@meta["title"] = STDIN.gets.strip
|
49
|
+
@meta["created_at"] = record_id
|
50
|
+
@meta["columns"] = @user_columns
|
51
|
+
@meta["rows"] = @user_rows
|
52
|
+
puts record_file('meta')
|
53
|
+
File.open(record_file('meta'), 'w+') do |meta|
|
54
|
+
meta.puts @meta.to_json
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def check_record_dir
|
61
|
+
FileUtils.mkdir_p(record_dir) unless File.exists?(record_dir)
|
62
|
+
end
|
63
|
+
|
64
|
+
def init_terminal
|
65
|
+
stty_data = `stty -a`
|
66
|
+
@user_columns = stty_data.match(/columns (\d+)/)[1]
|
67
|
+
@user_rows = stty_data.match(/rows (\d+)/)[1]
|
68
|
+
puts "Saved terminal size #{@user_columns}X#{@user_rows}"
|
69
|
+
# system("stty columns 80 rows 24")
|
70
|
+
end
|
71
|
+
|
72
|
+
def restore_terminal
|
73
|
+
# system("stty columns #{@user_columns} rows #{@user_rows}")
|
74
|
+
end
|
75
|
+
|
76
|
+
def record_dir
|
77
|
+
@record_dir ||= Shelr.data_dir(record_id)
|
78
|
+
end
|
79
|
+
|
80
|
+
def record_id
|
81
|
+
@record_id ||= Time.now.to_i.to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def record_file(name)
|
85
|
+
File.join(Shelr.data_dir(record_id), name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def script_cmd
|
89
|
+
"script -c 'bash' #{record_file('typescript')} -t 2> #{record_file('timing')}"
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
data/lib/shelr.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Shelr
|
6
|
+
|
7
|
+
APP_NAME = 'shelr'
|
8
|
+
DATA_DIR = File.join(ENV['HOME'], '.share', APP_NAME)
|
9
|
+
CONFIG_DIR = File.join(ENV['HOME'], '.config', APP_NAME)
|
10
|
+
API_KEY = File.join(CONFIG_DIR, 'api_key')
|
11
|
+
API_URL = ENV['SHELR_LOCAL'] ? 'http://localhost:3000' : 'http://shelr.tv'
|
12
|
+
|
13
|
+
autoload :Recorder, 'shelr/recorder.rb'
|
14
|
+
autoload :Player, 'shelr/player.rb'
|
15
|
+
autoload :Publisher, 'shelr/publisher.rb'
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def api_key
|
19
|
+
return false unless File.exist?(API_KEY)
|
20
|
+
@api_key ||= File.read(API_KEY).strip
|
21
|
+
end
|
22
|
+
|
23
|
+
def api_key=(key)
|
24
|
+
FileUtils.mkdir_p(CONFIG_DIR) unless File.exist?(CONFIG_DIR)
|
25
|
+
File.open(API_KEY, 'w+') { |f| f.puts(key.strip) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def data_dir(record_id)
|
29
|
+
File.join(Shelr::DATA_DIR, record_id.to_s)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/shelr.1
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
.\" generated with Ronn/v0.7.3
|
2
|
+
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
3
|
+
.
|
4
|
+
.TH "SHELR" "1" "August 2011" "" ""
|
5
|
+
.
|
6
|
+
.SH "NAME"
|
7
|
+
\fBshelr\fR \- screencasting for shell junkies
|
8
|
+
.
|
9
|
+
.SH "SYNOPSIS"
|
10
|
+
\fBshelr\fR command [id]
|
11
|
+
.
|
12
|
+
.SH "DESCRIPTION"
|
13
|
+
\fBShelr\fR records terminal output and can replay it
|
14
|
+
.
|
15
|
+
.SH "COMMANDS"
|
16
|
+
.
|
17
|
+
.TP
|
18
|
+
\fBrecord\fR
|
19
|
+
Will record your terminal unless you type \fBexit\fR or Ctrl+D and store it to $HOME/\.local/share/shellcast/
|
20
|
+
.
|
21
|
+
.TP
|
22
|
+
\fBlist\fR
|
23
|
+
lists all your shellcasts\.
|
24
|
+
.
|
25
|
+
.TP
|
26
|
+
\fBplay\fR
|
27
|
+
plays local or remote shellcast\.
|
28
|
+
.
|
29
|
+
.TP
|
30
|
+
\fBpush\fR
|
31
|
+
publish your shellcast
|
32
|
+
.
|
33
|
+
.SH "EXAMPLES"
|
34
|
+
Record your shellcast:
|
35
|
+
.
|
36
|
+
.IP "" 4
|
37
|
+
.
|
38
|
+
.nf
|
39
|
+
|
40
|
+
$ shelr record
|
41
|
+
\.\.\. do something \.\.\.
|
42
|
+
$ exit
|
43
|
+
.
|
44
|
+
.fi
|
45
|
+
.
|
46
|
+
.IP "" 0
|
47
|
+
.
|
48
|
+
.P
|
49
|
+
List recorded shellcasts:
|
50
|
+
.
|
51
|
+
.IP "" 4
|
52
|
+
.
|
53
|
+
.nf
|
54
|
+
|
55
|
+
$ shelr list
|
56
|
+
.
|
57
|
+
.fi
|
58
|
+
.
|
59
|
+
.IP "" 0
|
60
|
+
.
|
61
|
+
.P
|
62
|
+
Play local shellcast:
|
63
|
+
.
|
64
|
+
.IP "" 4
|
65
|
+
.
|
66
|
+
.nf
|
67
|
+
|
68
|
+
$ shelr play 1293702847
|
69
|
+
.
|
70
|
+
.fi
|
71
|
+
.
|
72
|
+
.IP "" 0
|
73
|
+
.
|
74
|
+
.P
|
75
|
+
Play remote shellcast:
|
76
|
+
.
|
77
|
+
.IP "" 4
|
78
|
+
.
|
79
|
+
.nf
|
80
|
+
|
81
|
+
$ shelr play http://shelr\.tv/records/4d1f7c3890820d6144000002\.json
|
82
|
+
.
|
83
|
+
.fi
|
84
|
+
.
|
85
|
+
.IP "" 0
|
86
|
+
.
|
87
|
+
.P
|
88
|
+
Publish your shellcast:
|
89
|
+
.
|
90
|
+
.IP "" 4
|
91
|
+
.
|
92
|
+
.nf
|
93
|
+
|
94
|
+
$ shelr push 1293702847
|
95
|
+
.
|
96
|
+
.fi
|
97
|
+
.
|
98
|
+
.IP "" 0
|
99
|
+
.
|
100
|
+
.SH "BUGS"
|
101
|
+
\fBshelr\fR is written in Ruby and depends on \fBscript\fR and \fBscriptreplay\fR, commands libraries that are non\-trivial to install on some systems\.
|
102
|
+
.
|
103
|
+
.SH "COPYRIGHT"
|
104
|
+
Shelr is Copyright (C) 2011 Antono Vasiljev \fIhttp://antono\.info/\fR
|
105
|
+
.
|
106
|
+
.SH "SEE ALSO"
|
107
|
+
script(1), scriptreplay(1)
|
data/shelr.1.ronn
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
shelr(1) -- screencasting for shell junkies
|
2
|
+
===============================================
|
3
|
+
|
4
|
+
## SYNOPSIS
|
5
|
+
|
6
|
+
`shelr` command [id]
|
7
|
+
|
8
|
+
## DESCRIPTION
|
9
|
+
|
10
|
+
**Shelr** records terminal output and can replay it
|
11
|
+
|
12
|
+
## COMMANDS
|
13
|
+
|
14
|
+
* `record`:
|
15
|
+
Will record your terminal unless you type `exit` or Ctrl+D and
|
16
|
+
store it to $HOME/.local/share/shellcast/
|
17
|
+
|
18
|
+
* `list`:
|
19
|
+
lists all your shellcasts.
|
20
|
+
|
21
|
+
* `play`:
|
22
|
+
plays local or remote shellcast.
|
23
|
+
|
24
|
+
* `push`:
|
25
|
+
publish your shellcast
|
26
|
+
|
27
|
+
## EXAMPLES
|
28
|
+
|
29
|
+
Record your shellcast:
|
30
|
+
|
31
|
+
$ shelr record
|
32
|
+
... do something ...
|
33
|
+
$ exit
|
34
|
+
|
35
|
+
List recorded shellcasts:
|
36
|
+
|
37
|
+
$ shelr list
|
38
|
+
|
39
|
+
Play local shellcast:
|
40
|
+
|
41
|
+
$ shelr play 1293702847
|
42
|
+
|
43
|
+
Play remote shellcast:
|
44
|
+
|
45
|
+
$ shelr play http://shelr.tv/records/4d1f7c3890820d6144000002.json
|
46
|
+
|
47
|
+
Publish your shellcast:
|
48
|
+
|
49
|
+
$ shelr push 1293702847
|
50
|
+
|
51
|
+
|
52
|
+
## BUGS
|
53
|
+
|
54
|
+
**shelr** is written in Ruby and depends on `script` and `scriptreplay`,
|
55
|
+
commands libraries that are non-trivial to install on some systems.
|
56
|
+
|
57
|
+
## COPYRIGHT
|
58
|
+
|
59
|
+
Shelr is Copyright (C) 2011 Antono Vasiljev <http://antono.info/>
|
60
|
+
|
61
|
+
## SEE ALSO
|
62
|
+
|
63
|
+
script(1), scriptreplay(1)
|
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shelr::Recorder do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
STDIN.stubs(:gets).returns('my shellcast')
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#record!" do
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
subject.stubs(:system).with(anything).returns(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should set tty to 80x24" do
|
16
|
+
subject.expects("system").with(regexp_matches(/stty columns 80 rows 24/))
|
17
|
+
subject.record!
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should restore tty to user defined values" do
|
21
|
+
subject.expects(:restore_terminal)
|
22
|
+
subject.record!
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should start script session" do
|
26
|
+
subject.expects("system").with(regexp_matches Regexp.compile("script -c 'bash'"))
|
27
|
+
subject.record!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#restore_terminal" do
|
32
|
+
it "should call tty with saved dimensions" do
|
33
|
+
subject.expects(:system).with(
|
34
|
+
all_of(regexp_matches(/stty/),
|
35
|
+
regexp_matches(/columns/),
|
36
|
+
regexp_matches(/rows/))
|
37
|
+
)
|
38
|
+
subject.send :restore_terminal
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/shelr_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shelr do
|
4
|
+
it "should have ::APP_NAME defined" do
|
5
|
+
Shelr::APP_NAME.should == 'shelr'
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should provide XDG and APP_NAME based ::DATA_DIR" do
|
9
|
+
Shelr::DATA_DIR.should == File.join(XDG['DATA_HOME'].to_s, Shelr::APP_NAME)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should provide XDG config path" do
|
13
|
+
Shelr::CONFIG_DIR.should == File.join(XDG['CONFIG_HOME'].to_s, Shelr::APP_NAME)
|
14
|
+
end
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'shelr'
|
5
|
+
require "rubygems"
|
6
|
+
require "bundler/setup"
|
7
|
+
|
8
|
+
# Requires supporting files with custom matchers and macros, etc,
|
9
|
+
# in ./support/ and its subdirectories.
|
10
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.mock_with :mocha
|
14
|
+
end
|