sphinx_tv 0.9.1
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 +18 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +54 -0
- data/Rakefile +2 -0
- data/bin/sphinx_tv +6 -0
- data/lib/modules/mysql.rb +155 -0
- data/lib/modules/mythtv.rb +198 -0
- data/lib/modules/shepherd.rb +95 -0
- data/lib/modules/sphinx_module.rb +55 -0
- data/lib/sphinx_tv.rb +233 -0
- data/lib/sphinx_tv/cpan.rb +26 -0
- data/lib/sphinx_tv/download.rb +84 -0
- data/lib/sphinx_tv/version.rb +3 -0
- data/resources/MyConfig.pm.erb +49 -0
- data/resources/MythTv/MythBackend.plist.erb +19 -0
- data/sphinx_tv.gemspec +23 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 David Monagle
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= SphinxTV
|
2
|
+
|
3
|
+
The purpose of this gem is to provide an installer/configurator to ease the setup of a Mac Mini as a media server.
|
4
|
+
MythTV is the primary focus for this installer (MythTV + Big Cat in the OS makes for the Sphinx name.) Included in the
|
5
|
+
modules is Shepherd, an Australian TV grabber which integrates well with MythTV and allows for a great free TV guide
|
6
|
+
on the MythTV side of things.
|
7
|
+
|
8
|
+
At this point SphinxTV is regarded to be in extreme Alpha. It is on Github in the interests of the people that are
|
9
|
+
alpha testing it for me. I intend to continue to develop and expand on this as time allows (this is a hobby project
|
10
|
+
for me at this point.)
|
11
|
+
|
12
|
+
The goal is to have a website up and running in the coming months that will help detail the setup of a very functional
|
13
|
+
home entertainment system using Mac Mini hardware.
|
14
|
+
|
15
|
+
== Gem Installation ==
|
16
|
+
|
17
|
+
Easy:
|
18
|
+
|
19
|
+
gem install sphinx_tv
|
20
|
+
|
21
|
+
== Using SphinxTV ==
|
22
|
+
|
23
|
+
=== Setup ===
|
24
|
+
|
25
|
+
sphinx_tv setup
|
26
|
+
|
27
|
+
Turn on the modules that you wish to install and configure.
|
28
|
+
|
29
|
+
=== Download ===
|
30
|
+
|
31
|
+
sphinx_tv download
|
32
|
+
|
33
|
+
Option step but will just do all the necessary downloading for the modules that have been configured in the setup stage.
|
34
|
+
|
35
|
+
=== Installation ===
|
36
|
+
|
37
|
+
sphinx_tv install
|
38
|
+
|
39
|
+
This runs through the install of each module. If the download wasn't run seperately, then the downloads will be done
|
40
|
+
on-demand at ths start of the module install.
|
41
|
+
|
42
|
+
=== Configuration ===
|
43
|
+
|
44
|
+
sphinx_tv configure
|
45
|
+
|
46
|
+
Post installation configuration.
|
47
|
+
|
48
|
+
== Modules ==
|
49
|
+
|
50
|
+
=== MySQL ===
|
51
|
+
|
52
|
+
=== MythTV ===
|
53
|
+
|
54
|
+
=== Shepherd ===
|
data/Rakefile
ADDED
data/bin/sphinx_tv
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
class MySQL < SphinxModule
|
2
|
+
def check(quiet = false)
|
3
|
+
result = true
|
4
|
+
unless mysql_installed?
|
5
|
+
result = false
|
6
|
+
puts "The MySQL server doesn't appear to be installed.'".red unless quiet
|
7
|
+
end
|
8
|
+
unless File.exists? "/etc/paths.d/mysql"
|
9
|
+
result = false
|
10
|
+
puts "MySQL paths.d file is not configured.".red unless quiet
|
11
|
+
end
|
12
|
+
unless File.exists? "/usr/lib/libmysqlclient.18.dylib"
|
13
|
+
result = false
|
14
|
+
puts "MySQL does not have a symbolic link set up for the libmysqlclient dynlib.".red unless quiet
|
15
|
+
end
|
16
|
+
unless File.exists? "/var/mysql/mysql.sock"
|
17
|
+
result = false
|
18
|
+
puts "MySQL socket does not exist.".red unless quiet
|
19
|
+
end
|
20
|
+
|
21
|
+
puts "MySQL is OK.".green if result
|
22
|
+
result
|
23
|
+
end
|
24
|
+
|
25
|
+
def configure
|
26
|
+
unless mysql_installed?
|
27
|
+
puts "\nOnce you have MySQL installed, you may return to this menu to setup root access\n"
|
28
|
+
end
|
29
|
+
exit = false
|
30
|
+
until exit do
|
31
|
+
choose do |menu|
|
32
|
+
menu.header = "\nMySQL Configuration".cyan
|
33
|
+
menu.prompt = "Select an option: "
|
34
|
+
if mysql_installed?
|
35
|
+
menu.choice("Setup root access") { set_mysql_root_access }
|
36
|
+
end
|
37
|
+
menu.choice("Done") {
|
38
|
+
exit = true
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def download
|
45
|
+
url = "http://cdn.mysql.com/Downloads/MySQL-5.5/mysql-5.5.25a-osx10.6-x86_64.dmg"
|
46
|
+
puts "Downloading MySQL".cyan
|
47
|
+
puts url
|
48
|
+
result = Download.url(url, SphinxTv::download_path("mysql.dmg"))
|
49
|
+
end
|
50
|
+
|
51
|
+
def install
|
52
|
+
puts "Installing MySQL".cyan
|
53
|
+
unless check(true)
|
54
|
+
download
|
55
|
+
Download.mount(SphinxTv::download_path("mysql.dmg"), "mysql*") do |volume|
|
56
|
+
self.install_mysql_server volume
|
57
|
+
self.install_mysql_prefpane volume
|
58
|
+
self.install_mysql_startup volume
|
59
|
+
end
|
60
|
+
else
|
61
|
+
puts "MySQL is installed.".green
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def mysql_installed?
|
68
|
+
File.exists?("/usr/local/mysql/bin/mysql")
|
69
|
+
end
|
70
|
+
|
71
|
+
def install_mysql_server volume
|
72
|
+
puts "Installing MySQL Server".cyan
|
73
|
+
puts "This will configure the MySQL server. A graphical installer should open now."
|
74
|
+
files = Dir.glob File.join(volume, "mysql*")
|
75
|
+
if (files.size == 0)
|
76
|
+
puts "Could not find installer file in volume #{volume}".red
|
77
|
+
return
|
78
|
+
end
|
79
|
+
%x[open #{files[0]}]
|
80
|
+
ask "\nPress enter when the install is complete!".magenta
|
81
|
+
|
82
|
+
# Create the paths.d file
|
83
|
+
if mysql_installed?
|
84
|
+
puts "Creating global path file /etc/paths.d/mysql".cyan
|
85
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} bash -c 'echo "/usr/local/mysql/bin" > /etc/paths.d/mysql']
|
86
|
+
end
|
87
|
+
|
88
|
+
# Create the symbolic link to the client library
|
89
|
+
unless File.exists? "/usr/lib/libmysqlclient.18.dylib"
|
90
|
+
puts "Linking dynamic libraries".cyan
|
91
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} ln -s /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/lib]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Create the mysql socket
|
95
|
+
unless File.exists? "/tmp/mysql.sock"
|
96
|
+
puts "Creating link to mysql socket".cyan
|
97
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} mkdir -p /var/mysql]
|
98
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} ln -s /tmp/mysql.sock /var/mysql/]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def install_mysql_prefpane volume
|
103
|
+
puts "Installing MySQL Prefpane\n".cyan
|
104
|
+
puts "Select the option to install for all users of the computer"
|
105
|
+
puts "On the Prefpane, tick the option to start the MySQL Server on Startup"
|
106
|
+
puts "Click the button to start the MySQL Server"
|
107
|
+
files = Dir.glob File.join(volume, "MySQL.prefpane")
|
108
|
+
if (files.size == 0)
|
109
|
+
puts "Could not find Prefpane file in volume #{volume}".red
|
110
|
+
return
|
111
|
+
end
|
112
|
+
%x[open #{files[0]}]
|
113
|
+
ask "\nPress enter when the install is complete!".magenta
|
114
|
+
end
|
115
|
+
|
116
|
+
def install_mysql_startup volume
|
117
|
+
puts "Installing MySQL Startup".cyan
|
118
|
+
files = Dir.glob File.join(volume, "MySQLStartup*")
|
119
|
+
if (files.size == 0)
|
120
|
+
puts "Could not find startup installer file in volume #{volume}".red
|
121
|
+
return
|
122
|
+
end
|
123
|
+
%x[open #{files[0]}]
|
124
|
+
ask "\nPress enter when the install is complete!".magenta
|
125
|
+
end
|
126
|
+
|
127
|
+
def set_mysql_root_access
|
128
|
+
puts "This will allow you to set the root password for your database.".yellow
|
129
|
+
puts "It will give you a more secure SQL server on your network but if you lose".yellow
|
130
|
+
puts "the root password at any point, it will cause you pain.".yellow
|
131
|
+
response = ask("Set up root privileges? ") { |q| q.default = "No" }
|
132
|
+
return if !/Y/i.match(response)
|
133
|
+
old_root_pass = ask("Enter the current root password: ") { |q| q.echo = "*" }
|
134
|
+
root_pass = ask("Enter the new root password: ") { |q| q.echo = "*" }
|
135
|
+
root_pass_confirm = ask("Re-enter the new root password: ") { |q| q.echo = "*" }
|
136
|
+
if root_pass != root_pass_confirm
|
137
|
+
puts "Passwords do not match!".red
|
138
|
+
return
|
139
|
+
end
|
140
|
+
hostname = %x[hostname].strip
|
141
|
+
hostname_short = /^[^\.]+/.match(hostname)
|
142
|
+
mysql_commands = Array.new.tap do |c|
|
143
|
+
c << "DROP USER ''@'localhost';" if old_root_pass.empty?
|
144
|
+
c << "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('#{root_pass}');"
|
145
|
+
c << "SET PASSWORD FOR 'root'@'127.0.0.1' = PASSWORD('#{root_pass}');"
|
146
|
+
c << "SET PASSWORD FOR 'root'@'#{hostname}' = PASSWORD('#{root_pass}');"
|
147
|
+
c << "SET PASSWORD FOR 'root'@'#{hostname_short}' = PASSWORD('#{root_pass}');"
|
148
|
+
end
|
149
|
+
password_param = old_root_pass.empty? ? "" : " --password=#{old_root_pass}"
|
150
|
+
mysql_commands.each do |sql|
|
151
|
+
puts sql
|
152
|
+
%x[/usr/local/mysql/bin/mysql -u root#{password_param} -e "#{sql}"]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
class MythTv < SphinxModule
|
5
|
+
def initialize
|
6
|
+
@config = {
|
7
|
+
:version => SphinxTv::VERSION
|
8
|
+
}
|
9
|
+
load_configuration
|
10
|
+
end
|
11
|
+
|
12
|
+
def check(quiet = false)
|
13
|
+
result = true
|
14
|
+
result = false unless mythtv_backend_installed?(quiet)
|
15
|
+
result = false unless mythtv_frontend_installed?(quiet)
|
16
|
+
unless @config[:database_password]
|
17
|
+
result = false
|
18
|
+
puts "Assuming no database is set up as the MythTV database password is not set.'".red unless quiet
|
19
|
+
end
|
20
|
+
unless File.exists? "/usr/local/bin/mythfilldatabase"
|
21
|
+
result = false
|
22
|
+
puts "No symbolic link to mythfilldatabase found".red unless quiet
|
23
|
+
end
|
24
|
+
|
25
|
+
puts "MythTV is OK.".green if result
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
def configure
|
30
|
+
exit = false
|
31
|
+
until exit do
|
32
|
+
choose do |menu|
|
33
|
+
menu.header = "\nMythTV Configuration".cyan
|
34
|
+
menu.prompt = "Select an option: "
|
35
|
+
if mythtv_backend_installed?
|
36
|
+
menu.choice("Setup database") { setup_database }
|
37
|
+
end
|
38
|
+
menu.choice("Create Storage Directories") { create_storage_directories }
|
39
|
+
if mythtv_backend_running?
|
40
|
+
menu.choice("MythTV Backend Control " + "Loaded".green) { mythtv_backend_control(false) }
|
41
|
+
else
|
42
|
+
menu.choice("MythTV Backend Control " + "Unloaded".red) { mythtv_backend_control(true) }
|
43
|
+
end
|
44
|
+
menu.choice("Done") {
|
45
|
+
exit = true
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def download
|
52
|
+
doc = Nokogiri::HTML(open('http://sourceforge.net/projects/mythtvformacosx/files/'))
|
53
|
+
|
54
|
+
doc.css('tr.file a').each do |link|
|
55
|
+
if /\.dmg\/download$/.match(link[:href])
|
56
|
+
filename = nil
|
57
|
+
if /MythBack.*10\.7/.match(link[:href])
|
58
|
+
filename = "MythBackend.dmg"
|
59
|
+
elsif /MythFront.*10\.7/.match(link[:href])
|
60
|
+
filename = "MythFrontend.dmg"
|
61
|
+
end
|
62
|
+
if filename
|
63
|
+
puts "Downloading #{filename}".cyan
|
64
|
+
puts link[:href]
|
65
|
+
Download::url(link[:href], SphinxTv::download_path(filename))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def install
|
72
|
+
puts "Installing MythTV".cyan
|
73
|
+
unless check(true)
|
74
|
+
download
|
75
|
+
install_mythtv_backend unless mythtv_backend_installed?
|
76
|
+
install_mythtv_frontend unless mythtv_frontend_installed?
|
77
|
+
|
78
|
+
unless File.exists? "/usr/local/bin/mythfilldatabase"
|
79
|
+
puts "Creating link to mythfilldatabase".cyan
|
80
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} mkdir -p /usr/local/bin]
|
81
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} ln -s /Applications/MythBackend.app/Contents/MacOS/mythfilldatabase /usr/local/bin/mythfilldatabase]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def mythtv_backend_running?
|
89
|
+
result = %x[ps ax | grep MythBackend | grep -v grep]
|
90
|
+
return false if result.strip.empty?
|
91
|
+
true
|
92
|
+
end
|
93
|
+
|
94
|
+
def mythtv_backend_control(load)
|
95
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} launchctl #{load ? "load" : "unload"} -w /Library/LaunchDaemons/MythBackend.plist]
|
96
|
+
end
|
97
|
+
|
98
|
+
def mythtv_frontend_installed?(quiet = true)
|
99
|
+
result = true
|
100
|
+
unless File.exists? "/Applications/MythFrontend.app"
|
101
|
+
result = false
|
102
|
+
puts "MythFrontend application not installed.".red unless quiet
|
103
|
+
end
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
def mythtv_backend_installed?(quiet = true)
|
108
|
+
result = true
|
109
|
+
unless File.exists? "/Applications/MythBackend.app"
|
110
|
+
result = false
|
111
|
+
puts "MythBackend application not installed.".red unless quiet
|
112
|
+
end
|
113
|
+
unless File.exists? "/Library/LaunchDaemons/MythBackend.plist"
|
114
|
+
result = false
|
115
|
+
puts "MythBackend LaunchDaemon does not exist.".red unless quiet
|
116
|
+
end
|
117
|
+
result
|
118
|
+
end
|
119
|
+
|
120
|
+
def install_mythtv_backend
|
121
|
+
Download.mount(SphinxTv::download_path("MythBackend.dmg"), "MythBackend*") do |volume|
|
122
|
+
puts "Installing MythTVBackend".cyan
|
123
|
+
mythtv_files = ["MythBackend.app", "MythTv-Setup.app"]
|
124
|
+
mythtv_files.each do |file|
|
125
|
+
%x[cp -Rf #{volume}/#{file} /Applications 2>&1]
|
126
|
+
end
|
127
|
+
@username = Etc.getlogin
|
128
|
+
unless File.exists? "/var/log/mythtv"
|
129
|
+
puts "Creating MythTV log directory...".cyan
|
130
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} mkdir -p /var/log/mythtv]
|
131
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} chmod a+rwx /var/log/mythtv]
|
132
|
+
end
|
133
|
+
|
134
|
+
puts "Creating MythBackend LaunchDaemon file...".cyan
|
135
|
+
SphinxTv::copy_template(SphinxTv::resources_path("MythTv/MythBackend.plist.erb"), SphinxTv::cache_path("MythBackend.plist"), binding)
|
136
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} cp #{SphinxTv::cache_path("MythBackend.plist")} /Library/LaunchDaemons]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def install_mythtv_frontend
|
141
|
+
Download.mount(SphinxTv::download_path("MythFrontend.dmg"), "MythFrontend*") do |volume|
|
142
|
+
puts "Installing MythTVFrontend".cyan
|
143
|
+
mythtv_files = ["MythFrontend.app", "MythWelcome.app", "MythAVTest.app"]
|
144
|
+
mythtv_files.each do |file|
|
145
|
+
%x[cp -Rf #{volume}/#{file} /Applications 2>&1]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def setup_database
|
151
|
+
puts "This will create the MythTV database if it doesn't already exist and set appropriate privileges."
|
152
|
+
root_pass = ask("Enter your mysql root password: ") { |q| q.echo = "*" }
|
153
|
+
@config[:database_password] ||= SphinxTv::get_password_with_confirmation("Enter a password for the mythtv MySQL user: ")
|
154
|
+
return if @config[:database_password].nil?
|
155
|
+
save_configuration
|
156
|
+
hostname = %x[hostname].strip
|
157
|
+
hostname_short = /^[^\.]+/.match(hostname)
|
158
|
+
mysql_commands = Array.new.tap do |c|
|
159
|
+
c << "CREATE DATABASE IF NOT EXISTS mythconverg;"
|
160
|
+
c << "GRANT ALL ON mythconverg.* TO mythtv@localhost IDENTIFIED BY '#{@config[:database_password]}';"
|
161
|
+
c << "GRANT ALL ON mythconverg.* TO mythtv@#{hostname} IDENTIFIED BY '#{@config[:database_password]}';"
|
162
|
+
c << "FLUSH PRIVILEGES;"
|
163
|
+
c << "GRANT CREATE TEMPORARY TABLES ON mythconverg.* TO mythtv@localhost IDENTIFIED BY '#{@config[:database_password]}';"
|
164
|
+
c << "GRANT CREATE TEMPORARY TABLES ON mythconverg.* TO mythtv@#{hostname} IDENTIFIED BY '#{@config[:database_password]}';"
|
165
|
+
c << "FLUSH PRIVILEGES;"
|
166
|
+
c << "ALTER DATABASE mythconverg DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;"
|
167
|
+
end
|
168
|
+
password_param = root_pass.empty? ? "" : " --password=#{root_pass}"
|
169
|
+
mysql_commands.each do |sql|
|
170
|
+
puts sql
|
171
|
+
%x[/usr/local/mysql/bin/mysql -u root#{password_param} -e "#{sql}"]
|
172
|
+
end
|
173
|
+
|
174
|
+
puts "Creating mysql.txt in /etc/mythtv".cyan
|
175
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} mkdir -p /etc/mythtv]
|
176
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} chmod a+rwx /etc/mythtv]
|
177
|
+
outfile = File.open("/etc/mythtv/mysql.txt", "w")
|
178
|
+
outfile.puts("DBHostName=#{hostname}")
|
179
|
+
outfile.puts("DBUserName=mythtv")
|
180
|
+
outfile.puts("DBPassword=#{@config[:database_password]}")
|
181
|
+
outfile.puts("DBName=mythconverg")
|
182
|
+
outfile.puts("DBType=QMYSQL3")
|
183
|
+
outfile.close
|
184
|
+
%x[chmod o-w /etc/mythtv/mysql.txt]
|
185
|
+
end
|
186
|
+
|
187
|
+
def create_storage_directories
|
188
|
+
storage_root = ask("Enter the storage directory root: ") { |q| q.default = "/Volumes/MythTV" }
|
189
|
+
directories = ['Backups', 'Banners', 'Coverart', 'Fanart', 'LiveTV', 'Recordings', 'Screenshots', 'Trailers']
|
190
|
+
directories.each do |directory|
|
191
|
+
full_dir = File.join(storage_root, directory)
|
192
|
+
puts full_dir
|
193
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} mkdir -p #{full_dir}]
|
194
|
+
end
|
195
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} chown -Rf #{Etc.getlogin} #{storage_root}]
|
196
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} chmod -Rf ugo+rwx #{storage_root}]
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
class Shepherd < SphinxModule
|
2
|
+
def initialize
|
3
|
+
@config = {
|
4
|
+
:version => SphinxTv::VERSION
|
5
|
+
}
|
6
|
+
load_configuration
|
7
|
+
end
|
8
|
+
|
9
|
+
def check(quiet = false)
|
10
|
+
result = true
|
11
|
+
|
12
|
+
unless File.exists? "/usr/local/share/xmltv"
|
13
|
+
result = false
|
14
|
+
puts "XMLTV is not installed.".red unless quiet
|
15
|
+
end
|
16
|
+
|
17
|
+
unless File.exists? File.join(Etc.getpwuid.dir, ".shepherd")
|
18
|
+
result = false
|
19
|
+
puts "Shepherd is not installed.".red unless quiet
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "Shepherd is OK.".green if result
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def download
|
27
|
+
doc = Nokogiri::HTML(open('http://sourceforge.net/projects/xmltv/files/xmltv/0.5.63/'))
|
28
|
+
|
29
|
+
url = "http://www.whuffy.com/shepherd/shepherd"
|
30
|
+
puts "Downloading Shepherd".cyan
|
31
|
+
puts url
|
32
|
+
result = Download.url(url, SphinxTv::download_path("shepherd"))
|
33
|
+
|
34
|
+
doc.css('tr.file a').each do |link|
|
35
|
+
if /\.tar\.bz2\/download$/.match(link[:href])
|
36
|
+
filename = nil
|
37
|
+
filename = "xmltv.tar.bz2" if /xmltv/.match(link[:href])
|
38
|
+
if filename
|
39
|
+
puts "Downloading #{filename}".cyan
|
40
|
+
puts link[:href]
|
41
|
+
Download::url(link[:href], SphinxTv::download_path(filename))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def install
|
48
|
+
unless check(true)
|
49
|
+
download
|
50
|
+
install_perl_prerequisites
|
51
|
+
install_xmltv unless File.exists? "/usr/local/share/xmltv"
|
52
|
+
|
53
|
+
unless File.exists? "/Library/Perl/5.12/Shepherd"
|
54
|
+
puts "Creating symlink for Shepherd/MythTV perl library...".cyan
|
55
|
+
home_dir = Etc.getpwuid.dir
|
56
|
+
%x[sudo #{SphinxTv::SUDO_PROMPT} ln -s #{home_dir}/.shepherd/references/Shepherd /Library/Perl/5.12]
|
57
|
+
end
|
58
|
+
puts "Installing Shepherd".cyan
|
59
|
+
system("perl #{SphinxTv::download_path("shepherd")} --configure")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def install_perl_prerequisites
|
64
|
+
|
65
|
+
Cpan::create_config_file
|
66
|
+
|
67
|
+
shepherd_mandatory_perl_modules = "YAML XML::Twig Algorithm::Diff Compress::Zlib Cwd Data::Dumper Date::Manip Getopt::Long \
|
68
|
+
List::Compare LWP::UserAgent POSIX Digest::SHA1"
|
69
|
+
|
70
|
+
shepherd_optional_perl_modules = "DateTime::Format::Strptime File::Basename File::Path HTML::Entities \
|
71
|
+
HTML::TokeParser HTML::TreeBuilder IO::File Storable Time::HiRes XML::DOM \
|
72
|
+
XML::DOM::NodeList XML::Simple Storable HTTP::Cookies File::Basename \
|
73
|
+
LWP::ConnCache Digest::MD5 Archive::Zip IO::String \
|
74
|
+
DateTime::Format::Strptime \
|
75
|
+
HTTP::Cache::Transparent Crypt::SSLeay DBD::mysql "
|
76
|
+
|
77
|
+
perl_modules = shepherd_mandatory_perl_modules.split(" ") + shepherd_optional_perl_modules.split(" ")
|
78
|
+
puts "Installing required perl modules...".cyan
|
79
|
+
Cpan::install(perl_modules)
|
80
|
+
end
|
81
|
+
|
82
|
+
def install_xmltv
|
83
|
+
puts "Extracting XMLTV...".cyan
|
84
|
+
%x[tar -jxf #{SphinxTv::download_path("xmltv.tar.bz2")} -C #{SphinxTv::cache_path}]
|
85
|
+
puts "Compiling XMLTV...".cyan
|
86
|
+
commands = Array.new.tap do |c|
|
87
|
+
c << "cd #{Sphinx.cache_path}/xmltv*"
|
88
|
+
c << "perl Makefile.PL"
|
89
|
+
c << "make"
|
90
|
+
c << "make test"
|
91
|
+
c << "sudo #{SphinxTv::SUDO_PROMPT} make install"
|
92
|
+
end
|
93
|
+
puts %x[#{commands.join(";")}]
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class SphinxModule
|
2
|
+
def initialize
|
3
|
+
@config = {
|
4
|
+
:version => SphinxTv::VERSION
|
5
|
+
}
|
6
|
+
end
|
7
|
+
|
8
|
+
def load_configuration
|
9
|
+
config_file = File.join(SphinxTv::CONFIG_DIRECTORY, "#{self.class.to_s.downcase}.yml")
|
10
|
+
unless File.exists? config_file
|
11
|
+
return false
|
12
|
+
end
|
13
|
+
c = YAML::load_file config_file
|
14
|
+
@config.merge! c
|
15
|
+
return true
|
16
|
+
end
|
17
|
+
|
18
|
+
def save_configuration
|
19
|
+
def save_configuration
|
20
|
+
Dir.mkdir(SphinxTv::CONFIG_DIRECTORY) unless File.exists? SphinxTv::CONFIG_DIRECTORY
|
21
|
+
File.open(File.join(SphinxTv::CONFIG_DIRECTORY, "#{self.class.to_s.downcase}.yml"), "w") do |file|
|
22
|
+
file.write @config.to_yaml
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def check(quiet = false)
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup
|
32
|
+
puts "#{self.class.to_s} does not have a setup menu.".red
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
|
36
|
+
def configure
|
37
|
+
puts "#{self.class.to_s} does not have a configuration menu.".red
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
|
41
|
+
def download
|
42
|
+
end
|
43
|
+
|
44
|
+
def install
|
45
|
+
puts "#{self.class.to_s} does not have an install function.".red
|
46
|
+
end
|
47
|
+
|
48
|
+
def uninstall
|
49
|
+
puts "#{self.class.to_s} does not have an uninstall function.".red
|
50
|
+
end
|
51
|
+
|
52
|
+
def update
|
53
|
+
puts "#{self.class.to_s} does not have an update function.".red
|
54
|
+
end
|
55
|
+
end
|
data/lib/sphinx_tv.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
require "colorize"
|
2
|
+
require "etc"
|
3
|
+
require "yaml"
|
4
|
+
require 'optparse'
|
5
|
+
require "highline/import"
|
6
|
+
require "modules/sphinx_module"
|
7
|
+
require "sphinx_tv/download"
|
8
|
+
require "sphinx_tv/cpan"
|
9
|
+
require "erb"
|
10
|
+
require "version"
|
11
|
+
|
12
|
+
class SphinxTv
|
13
|
+
SUDO_PROMPT = "-p \"#{"Your administrator password is required to peform this step: ".yellow}\""
|
14
|
+
CONFIG_DIRECTORY = File.join(Etc.getpwuid.dir, ".sphinx_tv")
|
15
|
+
MODULES = ["MySQL", "MythTv", "Shepherd"]
|
16
|
+
MODULE_DEFAULTS = {
|
17
|
+
"MySQL" => {
|
18
|
+
:active => true,
|
19
|
+
:setup => false,
|
20
|
+
:configure => true,
|
21
|
+
},
|
22
|
+
"MythTv" => {
|
23
|
+
:active => true,
|
24
|
+
:setup => false,
|
25
|
+
:configure => true,
|
26
|
+
:depends => ["MySQL"],
|
27
|
+
},
|
28
|
+
"Shepherd" => {
|
29
|
+
:active => false,
|
30
|
+
:setup => false,
|
31
|
+
:configure => true,
|
32
|
+
:depends => ["MythTv"],
|
33
|
+
},
|
34
|
+
}
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
@config = {
|
38
|
+
:version => VERSION,
|
39
|
+
:modules => MODULE_DEFAULTS
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.root_directory
|
44
|
+
File.expand_path '../..', __FILE__
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.resources_path(file = "")
|
48
|
+
File.join(root_directory, "resources", file)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.download_path(file = "")
|
52
|
+
download_directory = File.join(CONFIG_DIRECTORY, "downloads")
|
53
|
+
Dir.mkdir(download_directory) unless File.exists? download_directory
|
54
|
+
return File.join(download_directory, file)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.cache_path(file = "")
|
58
|
+
cache_directory = File.join(CONFIG_DIRECTORY, "cache")
|
59
|
+
Dir.mkdir(cache_directory) unless File.exists? cache_directory
|
60
|
+
return File.join(cache_directory, file)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.copy_template(source, dest, b)
|
64
|
+
t = ERB.new File.new(source).read, nil, "%"
|
65
|
+
outfile = File.open(dest, "w")
|
66
|
+
outfile.write(t.result(b || binding))
|
67
|
+
outfile.close
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.get_password_with_confirmation(prompt = nil)
|
71
|
+
pass = ask(prompt || "Enter a password: ") { |q| q.echo = "*" }
|
72
|
+
pass_confirm = ask("Re-enter the password: ") { |q| q.echo = "*" }
|
73
|
+
if pass != pass_confirm
|
74
|
+
puts "Passwords do not match!".red
|
75
|
+
return nil
|
76
|
+
end
|
77
|
+
pass
|
78
|
+
end
|
79
|
+
|
80
|
+
def load_configuration
|
81
|
+
config_file = File.join(CONFIG_DIRECTORY, "sphinx.yml")
|
82
|
+
unless File.exists? config_file
|
83
|
+
puts "Configuration file does not exist. Using defaults.".yellow
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
c = YAML::load_file config_file
|
87
|
+
@config.merge! c
|
88
|
+
return true
|
89
|
+
end
|
90
|
+
|
91
|
+
def save_configuration
|
92
|
+
Dir.mkdir(CONFIG_DIRECTORY) unless File.exists? CONFIG_DIRECTORY
|
93
|
+
File.open(File.join(CONFIG_DIRECTORY, "sphinx.yml"), "w") do |file|
|
94
|
+
file.write @config.to_yaml
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def module_select
|
99
|
+
exit = false
|
100
|
+
until exit do
|
101
|
+
choose do |menu|
|
102
|
+
menu.header = "\nSelect Modules".cyan
|
103
|
+
menu.prompt = "Select optional modules to toggle: "
|
104
|
+
MODULES.each do |m|
|
105
|
+
options = @config[:modules][m]
|
106
|
+
menu.choice("#{m}: " + (options[:active] ? "On".green : "Off".red)) do |choice|
|
107
|
+
m = /^([^:]*)/.match(choice)[0]
|
108
|
+
toggle_module m
|
109
|
+
end
|
110
|
+
end
|
111
|
+
menu.choice(:done) {
|
112
|
+
exit = true
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def toggle_module(m)
|
119
|
+
options = @config[:modules][m]
|
120
|
+
|
121
|
+
options[:active] = !options[:active]
|
122
|
+
if (options[:active])
|
123
|
+
if (options[:depends])
|
124
|
+
options[:depends].each do |d|
|
125
|
+
toggle_module d unless @config[:modules][d][:active]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def module_menu(action, title)
|
132
|
+
exit = false
|
133
|
+
until exit do
|
134
|
+
choose do |menu|
|
135
|
+
menu.header = "\n#{title}".cyan
|
136
|
+
menu.prompt = "Select a module: "
|
137
|
+
MODULES.each do |m|
|
138
|
+
options = @config[:modules][m]
|
139
|
+
if (options[action])
|
140
|
+
menu.choice(m) do |m|
|
141
|
+
require File.join("modules", m)
|
142
|
+
mod = eval("#{m}.new")
|
143
|
+
mod.send(action)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
menu.choice(:done) {
|
148
|
+
exit = true
|
149
|
+
}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def run_selected_modules &block
|
155
|
+
MODULES.each do |m|
|
156
|
+
if @config[:modules][m][:active]
|
157
|
+
require File.join("modules", m)
|
158
|
+
mod = eval("#{m}.new")
|
159
|
+
yield mod
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def setup
|
165
|
+
exit = false
|
166
|
+
until exit do
|
167
|
+
choose do |menu|
|
168
|
+
menu.header = "\nSphinx Installer".cyan
|
169
|
+
menu.prompt = "Select an option: "
|
170
|
+
|
171
|
+
menu.choice("Select Modules") { module_select }
|
172
|
+
menu.choice("Setup Modules") { module_menu(:setup, "Module Setup") }
|
173
|
+
menu.choice("Save Configuration") {
|
174
|
+
save_configuration
|
175
|
+
puts "Configuration Saved.".green
|
176
|
+
exit = true
|
177
|
+
}
|
178
|
+
menu.choice("Cancel") {
|
179
|
+
puts "Exiting without saving configuration.".red
|
180
|
+
exit = true
|
181
|
+
}
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def run
|
187
|
+
@no_config = load_configuration
|
188
|
+
|
189
|
+
action = nil
|
190
|
+
|
191
|
+
optparse = OptionParser.new do |opts|
|
192
|
+
# Set a banner, displayed at the top
|
193
|
+
# of the help screen.
|
194
|
+
opts.banner = "Usage: sphinx [options] action"
|
195
|
+
|
196
|
+
# This displays the help screen, all programs are
|
197
|
+
# assumed to have this option.
|
198
|
+
opts.on('-h', '--help', 'Display this screen') do
|
199
|
+
puts opts
|
200
|
+
exit
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Parse the command-line. Remember there are two forms
|
205
|
+
# of the parse method. The 'parse' method simply parses
|
206
|
+
# ARGV, while the 'parse!' method parses ARGV and removes
|
207
|
+
# any options found there, as well as any parameters for
|
208
|
+
# the options. What's left is the list of files to resize.
|
209
|
+
optparse.parse!
|
210
|
+
# Set the selected modules unless it was overridden
|
211
|
+
|
212
|
+
action = ARGV[0]
|
213
|
+
case action
|
214
|
+
when "setup"
|
215
|
+
setup
|
216
|
+
when "configure"
|
217
|
+
module_menu(:configure, "Configure Modules")
|
218
|
+
when "check"
|
219
|
+
run_selected_modules { |m| m.check }
|
220
|
+
when "install"
|
221
|
+
run_selected_modules { |m| m.install }
|
222
|
+
when "uninstall"
|
223
|
+
run_selected_modules { |m| m.uninstall }
|
224
|
+
when "download"
|
225
|
+
run_selected_modules { |m| m.download }
|
226
|
+
when "update"
|
227
|
+
run_selected_modules { |m| m.update }
|
228
|
+
else
|
229
|
+
puts "Use the --help switch if you need a list of valid actions"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'expect'
|
2
|
+
require 'pty'
|
3
|
+
|
4
|
+
class Cpan
|
5
|
+
def self.install modules
|
6
|
+
modules.each do |m|
|
7
|
+
result = %x[perl -M#{m} -e 1 2>&1].strip
|
8
|
+
if result.empty?
|
9
|
+
puts "Module '#{m}' is installed".green
|
10
|
+
else
|
11
|
+
puts "Installing perl module: #{m}".cyan
|
12
|
+
system("sudo #{Sphinx::SUDO_PROMPT} cpan -j #{Sphinx::cache_path("MyConfig.pm")} -f -i #{m}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.create_config_file
|
18
|
+
unless File.exists? Sphinx::cache_path("MyConfig.pm")
|
19
|
+
puts "Creating cpan config...".cyan
|
20
|
+
|
21
|
+
@cache_dir = Sphinx::cache_path
|
22
|
+
Sphinx::copy_template(Sphinx::resources_path("MyConfig.pm.erb"), Sphinx::cache_path("MyConfig.pm"), binding)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Download
|
2
|
+
def self.url file_url, filename
|
3
|
+
Dir::mkdir("cache") unless FileTest::directory?("cache")
|
4
|
+
|
5
|
+
z_option = (File.exists?(filename) ? " -z #{filename}" : "")
|
6
|
+
result = %x[curl -L -w "%{http_code} %{url_effective}"#{z_option} -o #{filename}.download #{file_url}]
|
7
|
+
if /304/.match(result)
|
8
|
+
puts "Up to date: ".green + filename
|
9
|
+
return false
|
10
|
+
else
|
11
|
+
if /200/.match(result)
|
12
|
+
begin
|
13
|
+
File.rename "#{filename}.download", filename
|
14
|
+
rescue
|
15
|
+
end
|
16
|
+
puts "Updated: ".yellow + filename
|
17
|
+
return true
|
18
|
+
else
|
19
|
+
File.delete "#{filename}.download" if File.exists? "#{filename}.download"
|
20
|
+
puts "File not found: ".red + file_url
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.open_volume(filename, volume_search, &block)
|
27
|
+
if File.exists?(filename)
|
28
|
+
result = %x[open #{filename}]
|
29
|
+
volume = find_mounted_volume volume_search
|
30
|
+
if volume.size == 0
|
31
|
+
puts "Could not find #{filename} volume".red
|
32
|
+
else
|
33
|
+
yield volume
|
34
|
+
end
|
35
|
+
else
|
36
|
+
puts "File hasn't been downloaded #{filename}".red
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.exists?
|
41
|
+
if File.exists?(filename)
|
42
|
+
return true
|
43
|
+
else
|
44
|
+
puts "File hasn't been downloaded #{filename}".red
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.mount(filename, volume_search, &block)
|
50
|
+
if File.exists?(filename)
|
51
|
+
result = %x[open #{filename}]
|
52
|
+
volume = self.find_mounted_volume volume_search
|
53
|
+
if volume.size == 0
|
54
|
+
puts "Could not find #{filename} volume".red
|
55
|
+
else
|
56
|
+
yield volume
|
57
|
+
end
|
58
|
+
else
|
59
|
+
yield filename
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.find_mounted_volume search
|
64
|
+
not_found = true
|
65
|
+
retries = 0
|
66
|
+
while not_found && retries < 30
|
67
|
+
volumes = Dir.glob "/Volumes/#{search}"
|
68
|
+
if volumes.size == 0
|
69
|
+
retries += 1
|
70
|
+
sleep 2
|
71
|
+
elsif volumes.size > 1
|
72
|
+
puts "Too many similar disk images mounted, please unmount all but latest version".red
|
73
|
+
puts "Here are the mounted matching images:"
|
74
|
+
volumes.each do |volume|
|
75
|
+
puts volume
|
76
|
+
end
|
77
|
+
return ""
|
78
|
+
else
|
79
|
+
return volumes[0]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return ""
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
$CPAN::Config = {
|
2
|
+
'auto_commit' => q[0],
|
3
|
+
'build_cache' => q[100],
|
4
|
+
'build_dir' => q[<%= @cache_dir %>/.cpan/build],
|
5
|
+
'build_dir_reuse' => q[0],
|
6
|
+
'build_requires_install_policy' => q[yes],
|
7
|
+
'cache_metadata' => q[1],
|
8
|
+
'check_sigs' => q[0],
|
9
|
+
'commandnumber_in_prompt' => q[1],
|
10
|
+
'connect_to_internet_ok' => q[1],
|
11
|
+
'cpan_home' => q[<%= @cache_dir %>/.cpan],
|
12
|
+
'ftp_passive' => q[1],
|
13
|
+
'ftp_proxy' => q[],
|
14
|
+
'getcwd' => q[cwd],
|
15
|
+
'halt_on_failure' => q[0],
|
16
|
+
'http_proxy' => q[],
|
17
|
+
'inactivity_timeout' => q[0],
|
18
|
+
'index_expire' => q[1],
|
19
|
+
'inhibit_startup_message' => q[0],
|
20
|
+
'keep_source_where' => q[<%= @cache_dir %>/.cpan/sources],
|
21
|
+
'load_module_verbosity' => q[none],
|
22
|
+
'make_arg' => q[],
|
23
|
+
'make_install_arg' => q[],
|
24
|
+
'make_install_make_command' => q[],
|
25
|
+
'makepl_arg' => q[],
|
26
|
+
'mbuild_arg' => q[],
|
27
|
+
'mbuild_install_arg' => q[],
|
28
|
+
'mbuild_install_build_command' => q[./Build],
|
29
|
+
'mbuildpl_arg' => q[],
|
30
|
+
'no_proxy' => q[],
|
31
|
+
'pager' => q[/usr/bin/less],
|
32
|
+
'perl5lib_verbosity' => q[none],
|
33
|
+
'prefer_installer' => q[MB],
|
34
|
+
'prefs_dir' => q[<%= @cache_dir %>/.cpan/prefs],
|
35
|
+
'prerequisites_policy' => q[follow],
|
36
|
+
'scan_cache' => q[atstart],
|
37
|
+
'shell' => q[/bin/bash],
|
38
|
+
'show_upload_date' => q[0],
|
39
|
+
'tar_verbosity' => q[none],
|
40
|
+
'term_is_latin' => q[1],
|
41
|
+
'term_ornaments' => q[1],
|
42
|
+
'trust_test_report_history' => q[0],
|
43
|
+
'urllist' => [],
|
44
|
+
'use_sqlite' => q[0],
|
45
|
+
'version_timeout' => q[15],
|
46
|
+
'yaml_load_code' => q[0],
|
47
|
+
};
|
48
|
+
1;
|
49
|
+
__END__
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>KeepAlive</key>
|
6
|
+
<true/>
|
7
|
+
<key>Label</key>
|
8
|
+
<string>MythBackend</string>
|
9
|
+
<key>ProgramArguments</key>
|
10
|
+
<array>
|
11
|
+
<string>/Applications/MythBackend.app/Contents/MacOS/MythBackend</string>
|
12
|
+
<string>--logpath</string>
|
13
|
+
<string>/var/log/mythtv</string>
|
14
|
+
</array>
|
15
|
+
<key>UserName</key>
|
16
|
+
<string><%= @username %></string>
|
17
|
+
</dict>
|
18
|
+
</plist>
|
19
|
+
|
data/sphinx_tv.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/sphinx_tv/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["David Monagle"]
|
6
|
+
gem.email = ["david.monagle@intrica.com.au"]
|
7
|
+
gem.date = '2012-07-15'
|
8
|
+
gem.summary = "SphinxTV is an installer/configurator for MythTV (and others) for OSX"
|
9
|
+
gem.description = "SphinxTV is an installer/configurator for MythTV (and others) for OSX"
|
10
|
+
gem.homepage = ""
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "sphinx_tv"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = SphinxTv::VERSION
|
18
|
+
gem.homepage =
|
19
|
+
'http://sphinxtv.intrica.com.au'
|
20
|
+
gem.add_dependency 'colorize'
|
21
|
+
gem.add_dependency 'highline'
|
22
|
+
gem.add_dependency 'nokogiri'
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sphinx_tv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Monagle
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: colorize
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: highline
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: nokogiri
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: SphinxTV is an installer/configurator for MythTV (and others) for OSX
|
63
|
+
email:
|
64
|
+
- david.monagle@intrica.com.au
|
65
|
+
executables:
|
66
|
+
- sphinx_tv
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- MIT-LICENSE
|
73
|
+
- README.rdoc
|
74
|
+
- Rakefile
|
75
|
+
- bin/sphinx_tv
|
76
|
+
- lib/modules/mysql.rb
|
77
|
+
- lib/modules/mythtv.rb
|
78
|
+
- lib/modules/shepherd.rb
|
79
|
+
- lib/modules/sphinx_module.rb
|
80
|
+
- lib/sphinx_tv.rb
|
81
|
+
- lib/sphinx_tv/cpan.rb
|
82
|
+
- lib/sphinx_tv/download.rb
|
83
|
+
- lib/sphinx_tv/version.rb
|
84
|
+
- resources/MyConfig.pm.erb
|
85
|
+
- resources/MythTv/MythBackend.plist.erb
|
86
|
+
- sphinx_tv.gemspec
|
87
|
+
homepage: http://sphinxtv.intrica.com.au
|
88
|
+
licenses: []
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.8.24
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: SphinxTV is an installer/configurator for MythTV (and others) for OSX
|
111
|
+
test_files: []
|