libisi 0.3.0
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/LICENSE +677 -0
- data/Manifest +89 -0
- data/Rakefile +34 -0
- data/lib/inifile.rb +119 -0
- data/lib/libisi.rb +948 -0
- data/lib/libisi/attribute.rb +32 -0
- data/lib/libisi/attribute/activerecord.rb +34 -0
- data/lib/libisi/attribute/base.rb +33 -0
- data/lib/libisi/base.rb +109 -0
- data/lib/libisi/bridge.rb +21 -0
- data/lib/libisi/bridge/base.rb +23 -0
- data/lib/libisi/bridge/java.rb +71 -0
- data/lib/libisi/bridge/python.rb +37 -0
- data/lib/libisi/cache.rb +21 -0
- data/lib/libisi/cache/base.rb +67 -0
- data/lib/libisi/cache/file_cache.rb +24 -0
- data/lib/libisi/chart.rb +21 -0
- data/lib/libisi/chart/base.rb +320 -0
- data/lib/libisi/chart/jfreechart.rb +682 -0
- data/lib/libisi/chart/jfreechart_generator.rb +206 -0
- data/lib/libisi/color.rb +21 -0
- data/lib/libisi/color/base.rb +66 -0
- data/lib/libisi/color/colortools.rb +92 -0
- data/lib/libisi/color/java.rb +44 -0
- data/lib/libisi/concept.rb +33 -0
- data/lib/libisi/concept/activerecord.rb +39 -0
- data/lib/libisi/concept/base.rb +58 -0
- data/lib/libisi/doc.rb +35 -0
- data/lib/libisi/doc/base.rb +414 -0
- data/lib/libisi/doc/html.rb +85 -0
- data/lib/libisi/doc/text.rb +98 -0
- data/lib/libisi/doc/wiki.rb +55 -0
- data/lib/libisi/environment.rb +21 -0
- data/lib/libisi/environment/base.rb +36 -0
- data/lib/libisi/environment/http.rb +105 -0
- data/lib/libisi/environment/rails.rb +27 -0
- data/lib/libisi/environment/root.rb +23 -0
- data/lib/libisi/fake_logger/logger.rb +61 -0
- data/lib/libisi/function/base.rb +30 -0
- data/lib/libisi/hal.rb +558 -0
- data/lib/libisi/instance.rb +27 -0
- data/lib/libisi/instance/activerecord.rb +21 -0
- data/lib/libisi/instance/base.rb +42 -0
- data/lib/libisi/log.rb +237 -0
- data/lib/libisi/mail/base.rb +32 -0
- data/lib/libisi/mail/tmail.rb +120 -0
- data/lib/libisi/parameter/base.rb +41 -0
- data/lib/libisi/property.rb +27 -0
- data/lib/libisi/property/base.rb +28 -0
- data/lib/libisi/reciever/base.rb +31 -0
- data/lib/libisi/reciever/socket.rb +31 -0
- data/lib/libisi/relation.rb +23 -0
- data/lib/libisi/request.rb +22 -0
- data/lib/libisi/request/base.rb +29 -0
- data/lib/libisi/request/http.rb +129 -0
- data/lib/libisi/response/base.rb +27 -0
- data/lib/libisi/task/base.rb +27 -0
- data/lib/libisi/task/http.rb +90 -0
- data/lib/libisi/tee.rb +296 -0
- data/lib/libisi/ui/base.rb +116 -0
- data/lib/libisi/ui/console.rb +238 -0
- data/lib/libisi/ui/kde.rb +94 -0
- data/lib/libisi/ui/nobody.rb +29 -0
- data/lib/libisi/ui/rails.rb +150 -0
- data/lib/libisi/ui/x11.rb +55 -0
- data/lib/libisi/uri.rb +42 -0
- data/lib/libisi/uri/activerecord.rb +152 -0
- data/lib/libisi/uri/base.rb +115 -0
- data/lib/libisi/uri/file.rb +43 -0
- data/lib/libisi/uri/ldap.rb +72 -0
- data/lib/libisi/uri/mysql.rb +98 -0
- data/lib/libisi/value.rb +31 -0
- data/lib/libisi/value/attribute_value.rb +19 -0
- data/lib/libisi/value/base.rb +55 -0
- data/lib/libisi/value/property_value.rb +19 -0
- data/lib/libisi/value/relation_value.rb +19 -0
- data/lib/ordered_hash.rb +228 -0
- data/libisi.gemspec +31 -0
- data/test/bridge_test.rb +77 -0
- data/test/cache_test.rb +65 -0
- data/test/chart_test.rb +179 -0
- data/test/color_test.rb +64 -0
- data/test/concept_test.rb +56 -0
- data/test/doc_test.rb +172 -0
- data/test/fixtures/test.db +0 -0
- data/test/ordered_hash_test.rb +39 -0
- data/test/profile_test.rb +36 -0
- data/test/request_test.rb +121 -0
- data/test/test +0 -0
- data/test/ui_test.rb +62 -0
- metadata +244 -0
data/Manifest
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
Rakefile
|
|
3
|
+
lib/inifile.rb
|
|
4
|
+
lib/libisi.rb
|
|
5
|
+
lib/libisi/attribute.rb
|
|
6
|
+
lib/libisi/attribute/activerecord.rb
|
|
7
|
+
lib/libisi/attribute/base.rb
|
|
8
|
+
lib/libisi/base.rb
|
|
9
|
+
lib/libisi/bridge.rb
|
|
10
|
+
lib/libisi/bridge/base.rb
|
|
11
|
+
lib/libisi/bridge/java.rb
|
|
12
|
+
lib/libisi/bridge/python.rb
|
|
13
|
+
lib/libisi/cache.rb
|
|
14
|
+
lib/libisi/cache/base.rb
|
|
15
|
+
lib/libisi/cache/file_cache.rb
|
|
16
|
+
lib/libisi/chart.rb
|
|
17
|
+
lib/libisi/chart/base.rb
|
|
18
|
+
lib/libisi/chart/jfreechart.rb
|
|
19
|
+
lib/libisi/chart/jfreechart_generator.rb
|
|
20
|
+
lib/libisi/color.rb
|
|
21
|
+
lib/libisi/color/base.rb
|
|
22
|
+
lib/libisi/color/colortools.rb
|
|
23
|
+
lib/libisi/color/java.rb
|
|
24
|
+
lib/libisi/concept.rb
|
|
25
|
+
lib/libisi/concept/activerecord.rb
|
|
26
|
+
lib/libisi/concept/base.rb
|
|
27
|
+
lib/libisi/doc.rb
|
|
28
|
+
lib/libisi/doc/base.rb
|
|
29
|
+
lib/libisi/doc/html.rb
|
|
30
|
+
lib/libisi/doc/text.rb
|
|
31
|
+
lib/libisi/doc/wiki.rb
|
|
32
|
+
lib/libisi/environment.rb
|
|
33
|
+
lib/libisi/environment/base.rb
|
|
34
|
+
lib/libisi/environment/http.rb
|
|
35
|
+
lib/libisi/environment/rails.rb
|
|
36
|
+
lib/libisi/environment/root.rb
|
|
37
|
+
lib/libisi/fake_logger/logger.rb
|
|
38
|
+
lib/libisi/function/base.rb
|
|
39
|
+
lib/libisi/hal.rb
|
|
40
|
+
lib/libisi/instance.rb
|
|
41
|
+
lib/libisi/instance/activerecord.rb
|
|
42
|
+
lib/libisi/instance/base.rb
|
|
43
|
+
lib/libisi/log.rb
|
|
44
|
+
lib/libisi/mail/base.rb
|
|
45
|
+
lib/libisi/mail/tmail.rb
|
|
46
|
+
lib/libisi/parameter/base.rb
|
|
47
|
+
lib/libisi/property.rb
|
|
48
|
+
lib/libisi/property/base.rb
|
|
49
|
+
lib/libisi/reciever/base.rb
|
|
50
|
+
lib/libisi/reciever/socket.rb
|
|
51
|
+
lib/libisi/relation.rb
|
|
52
|
+
lib/libisi/request.rb
|
|
53
|
+
lib/libisi/request/base.rb
|
|
54
|
+
lib/libisi/request/http.rb
|
|
55
|
+
lib/libisi/response/base.rb
|
|
56
|
+
lib/libisi/task/base.rb
|
|
57
|
+
lib/libisi/task/http.rb
|
|
58
|
+
lib/libisi/tee.rb
|
|
59
|
+
lib/libisi/ui/base.rb
|
|
60
|
+
lib/libisi/ui/console.rb
|
|
61
|
+
lib/libisi/ui/kde.rb
|
|
62
|
+
lib/libisi/ui/nobody.rb
|
|
63
|
+
lib/libisi/ui/rails.rb
|
|
64
|
+
lib/libisi/ui/x11.rb
|
|
65
|
+
lib/libisi/uri.rb
|
|
66
|
+
lib/libisi/uri/activerecord.rb
|
|
67
|
+
lib/libisi/uri/base.rb
|
|
68
|
+
lib/libisi/uri/file.rb
|
|
69
|
+
lib/libisi/uri/ldap.rb
|
|
70
|
+
lib/libisi/uri/mysql.rb
|
|
71
|
+
lib/libisi/value.rb
|
|
72
|
+
lib/libisi/value/attribute_value.rb
|
|
73
|
+
lib/libisi/value/base.rb
|
|
74
|
+
lib/libisi/value/property_value.rb
|
|
75
|
+
lib/libisi/value/relation_value.rb
|
|
76
|
+
lib/ordered_hash.rb
|
|
77
|
+
test/bridge_test.rb
|
|
78
|
+
test/cache_test.rb
|
|
79
|
+
test/chart_test.rb
|
|
80
|
+
test/color_test.rb
|
|
81
|
+
test/concept_test.rb
|
|
82
|
+
test/doc_test.rb
|
|
83
|
+
test/fixtures/test.db
|
|
84
|
+
test/ordered_hash_test.rb
|
|
85
|
+
test/profile_test.rb
|
|
86
|
+
test/request_test.rb
|
|
87
|
+
test/test
|
|
88
|
+
test/ui_test.rb
|
|
89
|
+
Manifest
|
data/Rakefile
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright (C) 2007-2010 Logintas AG Switzerland
|
|
2
|
+
#
|
|
3
|
+
# This file is part of Libisi.
|
|
4
|
+
#
|
|
5
|
+
# Libisi is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# Libisi is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with Libisi. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
require 'rubygems'
|
|
19
|
+
require 'rake'
|
|
20
|
+
require 'echoe'
|
|
21
|
+
|
|
22
|
+
# Echoe
|
|
23
|
+
# See http://blog.evanweaver.com/files/doc/fauna/echoe/files/README.html
|
|
24
|
+
|
|
25
|
+
Echoe.new('libisi', '0.3.0') do |p|
|
|
26
|
+
p.description = "Library for easy and fast shell script developing"
|
|
27
|
+
p.url = "http://rubyforge.org/projects/libisi/"
|
|
28
|
+
p.author = "Pellanda Flavio, Copyright Logintas AG"
|
|
29
|
+
p.email = "flavio.pellanda@logintas.ch"
|
|
30
|
+
# p.ignore_pattern = ["svn_user.yml", "svn_project.rake"]
|
|
31
|
+
# p.project = "ucbrb"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/lib/inifile.rb
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Copyright (C) 2004 Gregoire Lejeune <gregoire.lejeune@free.fr>
|
|
2
|
+
#
|
|
3
|
+
# This program is free software; you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16
|
+
|
|
17
|
+
class IniFile
|
|
18
|
+
|
|
19
|
+
public
|
|
20
|
+
|
|
21
|
+
def initialize( file = nil )
|
|
22
|
+
clear( )
|
|
23
|
+
if file.nil? == false and file.empty? == false
|
|
24
|
+
load( file )
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def load( file )
|
|
29
|
+
clear( )
|
|
30
|
+
@hhxData = Hash::new( )
|
|
31
|
+
@sectionList = []
|
|
32
|
+
@xIniFile = file
|
|
33
|
+
parseFile( )
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def write( file = nil )
|
|
37
|
+
xWriteFile = @xIniFile
|
|
38
|
+
if file.nil? == false
|
|
39
|
+
xWriteFile = file
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
fIni = open( xWriteFile, "w" )
|
|
43
|
+
@sectionList.each {|xSection|
|
|
44
|
+
hxPairs = @hhData[xSection]
|
|
45
|
+
fIni.print "[", xSection, "]\n"
|
|
46
|
+
hxPairs.each{ |xKey, xValue|
|
|
47
|
+
fIni.print xKey, " = ", xValue, "\n"
|
|
48
|
+
}
|
|
49
|
+
fIni.puts "\n"
|
|
50
|
+
}
|
|
51
|
+
fIni.close( )
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def sections
|
|
55
|
+
if @hhxData.nil? == false
|
|
56
|
+
@sectionList.each {|k|
|
|
57
|
+
yield( k )
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def clear
|
|
63
|
+
@hhxData = nil
|
|
64
|
+
@sectionList = nil
|
|
65
|
+
@xIniFile = nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def [](section)
|
|
69
|
+
if @hhxData.nil? == false
|
|
70
|
+
return @hhxData[section]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def []=(section, hash)
|
|
75
|
+
if @hhxData.nil? == true
|
|
76
|
+
@hhxData = Hash::new( )
|
|
77
|
+
@sectionList = []
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
@hhxData[section] = hash
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
@xIniFile
|
|
86
|
+
@hhxData
|
|
87
|
+
@sectionList
|
|
88
|
+
|
|
89
|
+
def parseFile
|
|
90
|
+
xCurrentSection = nil
|
|
91
|
+
|
|
92
|
+
open( @xIniFile, 'r' ) do |f|
|
|
93
|
+
xLine = ''
|
|
94
|
+
until f.eof?
|
|
95
|
+
xLine = f.gets.chomp.gsub(/;.*/, '').strip;
|
|
96
|
+
|
|
97
|
+
if xLine.empty? == false
|
|
98
|
+
case xLine
|
|
99
|
+
when /^\[(.*)\]$/
|
|
100
|
+
xCurrentSection = $1
|
|
101
|
+
if @hhxData.has_key?( xCurrentSection ) == false
|
|
102
|
+
@hhxData[xCurrentSection] = Hash::new( )
|
|
103
|
+
@sectionList << xCurrentSection
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
when /^([^=]+?)=/
|
|
107
|
+
xKey = $1.strip
|
|
108
|
+
xValue = $'.strip
|
|
109
|
+
@hhxData[xCurrentSection][xKey] = xValue
|
|
110
|
+
|
|
111
|
+
else
|
|
112
|
+
print "ERROR !!!\n"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
data/lib/libisi.rb
ADDED
|
@@ -0,0 +1,948 @@
|
|
|
1
|
+
# Copyright (C) 2007-2010 Logintas AG Switzerland
|
|
2
|
+
#
|
|
3
|
+
# This file is part of Libisi.
|
|
4
|
+
#
|
|
5
|
+
# Libisi is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# Libisi is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with Libisi. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
require "open3"
|
|
19
|
+
require "ordered_hash"
|
|
20
|
+
|
|
21
|
+
module LibIsi
|
|
22
|
+
|
|
23
|
+
LOG_FORMAT = "[%l] %d :: %m"
|
|
24
|
+
LIBISI = true
|
|
25
|
+
def init_libisi(options = {})
|
|
26
|
+
require "date"
|
|
27
|
+
require "time"
|
|
28
|
+
require "fileutils"
|
|
29
|
+
require "pathname"
|
|
30
|
+
require "libisi/doc"
|
|
31
|
+
require "libisi/log"
|
|
32
|
+
require "libisi/uri"
|
|
33
|
+
|
|
34
|
+
Log.init(options) unless options[:no_logging]
|
|
35
|
+
initialize_ui(options) unless options[:no_ui]
|
|
36
|
+
initialize_environment(options) unless options[:no_environment]
|
|
37
|
+
initialize_mail(options) unless options[:no_mail]
|
|
38
|
+
Doc.init(options) unless options[:no_doc]
|
|
39
|
+
Uri.init(options) unless options[:no_uri]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Mail
|
|
43
|
+
def initialize_mail(options)
|
|
44
|
+
# there is no ohter implementation yet
|
|
45
|
+
raise "Mail already initialized" if $mail
|
|
46
|
+
require "libisi/mail/tmail"
|
|
47
|
+
$mail = TMailMail.new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# UI
|
|
51
|
+
def initialize_ui(options)
|
|
52
|
+
raise "UI already initialized" if $ui
|
|
53
|
+
|
|
54
|
+
if options[:ui]
|
|
55
|
+
@ui_overwritten = true
|
|
56
|
+
ui = options[:ui]
|
|
57
|
+
else
|
|
58
|
+
ui = ((rails_available? and "rails") or
|
|
59
|
+
(kde_available? and "kde") or
|
|
60
|
+
(x_available? and "x11") or
|
|
61
|
+
(terminal_available? and "console") or
|
|
62
|
+
"nobody")
|
|
63
|
+
end
|
|
64
|
+
change_ui(ui)
|
|
65
|
+
end
|
|
66
|
+
def change_ui(ui)
|
|
67
|
+
ui = ui.to_s
|
|
68
|
+
raise "Hacking attack!!" unless ui.class == String
|
|
69
|
+
raise "Unexpected UI name #{ui}." unless ui =~ /^[a-zA-Z][a-zA-Z0-9]*$/
|
|
70
|
+
require "libisi/ui/#{ui}.rb"
|
|
71
|
+
klass = eval("#{ui.capitalize}UI")
|
|
72
|
+
$ui = klass.new
|
|
73
|
+
end
|
|
74
|
+
def kde_available?
|
|
75
|
+
return false unless ENV["KDE_FULL_SESSION"] == "true"
|
|
76
|
+
unless system("ps aux | grep -v grep | grep kded > /dev/null")
|
|
77
|
+
$log.warn("kded not running but kde seems to be available. Executing kded --new-startup.")
|
|
78
|
+
return false unless system("kded --new-startup")
|
|
79
|
+
end
|
|
80
|
+
true
|
|
81
|
+
end
|
|
82
|
+
def x_available?
|
|
83
|
+
if ENV["DISPLAY"]
|
|
84
|
+
unless Pathname.new("/usr/bin/xvinfo").exist?
|
|
85
|
+
$log.debug("xvinfo not available => return x_available: false")
|
|
86
|
+
return false
|
|
87
|
+
end
|
|
88
|
+
system("xvinfo 2>/dev/null 1> /dev/null")
|
|
89
|
+
return true if $?.exitstatus != 255
|
|
90
|
+
$log.warn("DISPLAY set to #{ENV["DISPLAY"]} but cannot access X.")
|
|
91
|
+
end
|
|
92
|
+
false
|
|
93
|
+
end
|
|
94
|
+
def terminal_available?
|
|
95
|
+
ENV["TERM"]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# OUTPUT
|
|
99
|
+
def add_output(file)
|
|
100
|
+
unless Log.output(file) or
|
|
101
|
+
Doc.output(file)
|
|
102
|
+
raise "No outputter found for #{file}"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# LOG
|
|
108
|
+
def new_logger(name, filename, options = {})
|
|
109
|
+
# function now in Log class
|
|
110
|
+
Log.new_logger(name, filename, options)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# ENVIRONMENT
|
|
114
|
+
def initialize_environment(options)
|
|
115
|
+
"Could not parse caller main script: #{caller[-1]}" unless caller[-1] =~ /(.*)\:\d+/
|
|
116
|
+
ENV["main_script"] = $1
|
|
117
|
+
raise "Main script '#{ENV["main_script"]}' not found." unless main_script.exist?
|
|
118
|
+
|
|
119
|
+
ENV["PROGRAM_NAME"] = program_name
|
|
120
|
+
ENV["PROGRAM_IDENT"] = program_name
|
|
121
|
+
ENV["TODAY"] = DateTime.now.strftime("%F")
|
|
122
|
+
require 'socket'
|
|
123
|
+
ENV["HOST"] = open("|hostname") {|f| (f.readlines[0] or "").strip}
|
|
124
|
+
ENV["NET"] = open("|hostname -d") { |f| (f.readlines[0] or "").strip }
|
|
125
|
+
ENV["USER"] = open("|whoami") {|f| f.readlines[0].strip}
|
|
126
|
+
ENV["STARTDATETIME"] = DateTime.now.strftime("%F-%T")
|
|
127
|
+
# Set directory for temporary files
|
|
128
|
+
ENV["TMPDIR"] ||= "/var/tmp"
|
|
129
|
+
# output of compress and zip programs
|
|
130
|
+
# must be in english to work correctly
|
|
131
|
+
ENV["LANGUAGE"] = "en_US.UTF-8"
|
|
132
|
+
|
|
133
|
+
# set benchmarking if defined on evironment
|
|
134
|
+
if ENV["BENCHMARK"] or ENV["BENCHMARKINK"]
|
|
135
|
+
self.benchmarking = true
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
#Catch & log unhandled exceptions
|
|
139
|
+
at_exit {
|
|
140
|
+
if self.profiling
|
|
141
|
+
profiling_stop
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
begin
|
|
145
|
+
pid_file.delete if pid_file.exist?
|
|
146
|
+
rescue
|
|
147
|
+
$log.error("Could not remove pid file #{pid_file}: #{$!}") if $log
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
unless $! .class == SystemExit or $!.nil?
|
|
151
|
+
$log.fatal("#{$!.class.name}: #{$!.to_s}")
|
|
152
|
+
$@.each {|l| $log.debug{l} } if $log.debug?
|
|
153
|
+
|
|
154
|
+
# exit immediately
|
|
155
|
+
exit! 99
|
|
156
|
+
end
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# add lib directory if parent directory of
|
|
160
|
+
# source script has a lib directory
|
|
161
|
+
libdir = Pathname.new(ENV["main_script"]).dirname.parent + "lib"
|
|
162
|
+
$LOAD_PATH.insert(0, libdir.to_s) if libdir.exist?
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def program_name; main_script.basename.to_s; end
|
|
166
|
+
def program_instance; ENV["PROGRAM_INSTANCE"]; end
|
|
167
|
+
def program_instance=(inst); ENV["PROGRAM_INSTANCE"] = inst; end
|
|
168
|
+
def main_script; Pathname.new(ENV["main_script"]); end
|
|
169
|
+
def user; ENV["USER"]; end
|
|
170
|
+
def full_qualified_domainname; "#{ENV["HOST"]}.#{ENV["NET"]}"; end
|
|
171
|
+
def host_name; "#{ENV["HOST"]}"; end
|
|
172
|
+
|
|
173
|
+
def paths
|
|
174
|
+
"Could not parse caller: #{caller[-1]}" unless caller[-1] =~ /(.*)\:\d+/
|
|
175
|
+
calling_file = Pathname.new($1).cleanpath
|
|
176
|
+
all_paths = {
|
|
177
|
+
:rails => {
|
|
178
|
+
:config => Pathname.new("config"),
|
|
179
|
+
:binary => Pathname.new("script"),
|
|
180
|
+
:lib => Pathname.new("lib")
|
|
181
|
+
},
|
|
182
|
+
:debian => {
|
|
183
|
+
:data => Pathname.new("/usr/share"),
|
|
184
|
+
:config => Pathname.new("/etc"),
|
|
185
|
+
:binary => Pathname.new("/usr/bin"),
|
|
186
|
+
:lib => Pathname.new("/usr/lib/ruby/1.8"),
|
|
187
|
+
},
|
|
188
|
+
:setup => {
|
|
189
|
+
:data => Pathname.new("data"),
|
|
190
|
+
:config => Pathname.new("conf"),
|
|
191
|
+
:binary => Pathname.new("bin"),
|
|
192
|
+
:lib => Pathname.new("lib"),
|
|
193
|
+
:test => Pathname.new("test"),
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
$log.debug("Calling file: #{calling_file}")
|
|
197
|
+
file_type = all_paths.map {|env, files|
|
|
198
|
+
files.map {|type, path|
|
|
199
|
+
# eliminate overlappings
|
|
200
|
+
next if env == :setup and calling_file.to_s =~ /^\/usr\/bin/
|
|
201
|
+
next if env == :setup and calling_file.to_s =~ /rails/
|
|
202
|
+
|
|
203
|
+
next type if calling_file.to_s.starts_with?(path.to_s)
|
|
204
|
+
next type if calling_file.dirname.basename.to_s == path.to_s
|
|
205
|
+
}.compact.map {|type| [env,type]}
|
|
206
|
+
}.flatten
|
|
207
|
+
if file_type.length != 2
|
|
208
|
+
type = :rails if defined?(RAILS_ROOT)
|
|
209
|
+
else
|
|
210
|
+
type = file_type[0]
|
|
211
|
+
end
|
|
212
|
+
raise "Could not determine caller type #{file_type.inspect} from #{calling_file}" unless type
|
|
213
|
+
|
|
214
|
+
ret = all_paths[type].dup
|
|
215
|
+
ret.each {|key,val|
|
|
216
|
+
ret[key] = calling_file.dirname.parent + val
|
|
217
|
+
}
|
|
218
|
+
return ret
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def with_temp_directory(name = nil)
|
|
222
|
+
dir = Pathname.new("/var/tmp/#{program_name}.#{Process.pid}")
|
|
223
|
+
dir.mkdir
|
|
224
|
+
begin
|
|
225
|
+
FileUtils.cd(dir) {
|
|
226
|
+
begin
|
|
227
|
+
yield
|
|
228
|
+
rescue
|
|
229
|
+
if $log.debug? and $ui.respond_to?(:shell)
|
|
230
|
+
$ui.shell if
|
|
231
|
+
$ui.question("Error ocurred in temporary directory #{dir}\nError: #{$!.to_s}\nDo you want a shell, before removing directory?",:default => false)
|
|
232
|
+
end
|
|
233
|
+
raise
|
|
234
|
+
end
|
|
235
|
+
}
|
|
236
|
+
ensure
|
|
237
|
+
dir.rmtree
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def temp_file(name = nil)
|
|
242
|
+
if name.nil?
|
|
243
|
+
@temp_file_num ||= -1
|
|
244
|
+
@temp_file_num += 1
|
|
245
|
+
name = @temp_file_num += 1
|
|
246
|
+
end
|
|
247
|
+
temp_files([name]) {|tf|
|
|
248
|
+
yield tf[0]
|
|
249
|
+
}
|
|
250
|
+
end
|
|
251
|
+
def temp_files(*names)
|
|
252
|
+
files = names.map {|n| Pathname.new("/var/tmp/#{program_name}.#{Process.pid}-#{n}") }
|
|
253
|
+
begin
|
|
254
|
+
yield files
|
|
255
|
+
ensure
|
|
256
|
+
files.each {|f|
|
|
257
|
+
f.delete if f.exist?
|
|
258
|
+
}
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Profile
|
|
263
|
+
def profiling; $profiling; end
|
|
264
|
+
def profiling=(val)
|
|
265
|
+
$profiling = val
|
|
266
|
+
if self.profiling
|
|
267
|
+
$log.info("Turned on Profiling")
|
|
268
|
+
require "ruby-prof"
|
|
269
|
+
$log.debug("Starting ruby prof")
|
|
270
|
+
RubyProf.start
|
|
271
|
+
else
|
|
272
|
+
$log.info("Turned off Profiling")
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
def profiling_stop
|
|
276
|
+
$log.debug("Stopping ruby prof")
|
|
277
|
+
result = RubyProf.stop
|
|
278
|
+
|
|
279
|
+
path = Pathname.new(self.profiling)
|
|
280
|
+
raise "Profile path disappeared: #{path}" unless path.exist?
|
|
281
|
+
|
|
282
|
+
{RubyProf::FlatPrinter => ".txt",
|
|
283
|
+
RubyProf::GraphPrinter => ".txt",
|
|
284
|
+
RubyProf::GraphHtmlPrinter => ".html",
|
|
285
|
+
RubyProf::CallTreePrinter => ".txt"}.each {|printer_class, ending|
|
|
286
|
+
printer = printer_class.new(result)
|
|
287
|
+
output_path = path + "RubyProf_#{printer_class.name}#{ending}"
|
|
288
|
+
$log.debug("Writing #{output_path}")
|
|
289
|
+
output_path.open("w") {|profile_out|
|
|
290
|
+
printer.print(profile_out)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
$profiling = false
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Benchmark
|
|
297
|
+
def benchmarking; $benchmarking; end
|
|
298
|
+
def benchmarking=(val)
|
|
299
|
+
$benchmarking = val
|
|
300
|
+
$benchmarks = {}
|
|
301
|
+
if self.benchmarking
|
|
302
|
+
Log.log_level = 2 if Log.log_level > 2
|
|
303
|
+
$log.info("Turned on Benchmarking")
|
|
304
|
+
else
|
|
305
|
+
$log.info("Turned off Benchmarking")
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def benchmark(name = nil, options = {})
|
|
310
|
+
return yield unless benchmarking
|
|
311
|
+
require "benchmark"
|
|
312
|
+
ret = nil
|
|
313
|
+
bench = Benchmark.measure {
|
|
314
|
+
ret = yield
|
|
315
|
+
}
|
|
316
|
+
$log.info("Benchmark #{name}: #{bench.to_s}")
|
|
317
|
+
if $benchmarks[name]
|
|
318
|
+
$benchmarks[name] += bench
|
|
319
|
+
else
|
|
320
|
+
$benchmarks[name] = bench
|
|
321
|
+
end
|
|
322
|
+
ret
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# BASH
|
|
326
|
+
def bash_eval(expr)
|
|
327
|
+
n_expr = "echo #{expr}".inspect
|
|
328
|
+
t_expr = ""
|
|
329
|
+
in_quotes = false
|
|
330
|
+
n_expr.length.times {|i|
|
|
331
|
+
ch = n_expr[i..i]
|
|
332
|
+
case ch
|
|
333
|
+
when "'"
|
|
334
|
+
in_quotes = !in_quotes
|
|
335
|
+
when "$"
|
|
336
|
+
if in_quotes
|
|
337
|
+
t_expr += "\\"
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
t_expr += ch
|
|
341
|
+
|
|
342
|
+
}
|
|
343
|
+
n_expr = t_expr
|
|
344
|
+
cmd = "/bin/bash -c #{n_expr} "
|
|
345
|
+
# new_expr = "echo '#{expr.gsub("'","\\\\\\\\'")}'"
|
|
346
|
+
# print "-----" + expr + "\n"
|
|
347
|
+
# print "-----" + new_expr + "\n"
|
|
348
|
+
# cmd = "/bin/bash -c #{new_expr}"
|
|
349
|
+
# print "-----" + cmd + "\n\n"
|
|
350
|
+
ret = open("| #{cmd}") {|b|
|
|
351
|
+
b.readlines.join.strip
|
|
352
|
+
}
|
|
353
|
+
raise "Error during evalating #{expr.inspect}" unless $?.success?
|
|
354
|
+
$log.debug{"bash_eval: #{expr.inspect} => #{ret.inspect}"}
|
|
355
|
+
ret
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def escape_bash(command)
|
|
359
|
+
command.gsub("\\","\\\\").gsub("\"","\\\"").gsub("\$","\\\$")
|
|
360
|
+
end
|
|
361
|
+
def execute_on_remote_command(remote, command)
|
|
362
|
+
return command if remote.nil? or remote == "localhost" or remote == "127.0.0.1"
|
|
363
|
+
command = "ssh -T #{remote} \"#{escape_bash(command)}\""
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def result_of_system(command, error_ok = false)
|
|
367
|
+
$log.debug{"Execute #{command.inspect}"}
|
|
368
|
+
res = open("|#{command}") {|f| f.readlines.join}
|
|
369
|
+
raise "Error executing #{command.inspect}." if !error_ok and !$?.success?
|
|
370
|
+
$log.debug{"Result is #{res.inspect}"}
|
|
371
|
+
res
|
|
372
|
+
end
|
|
373
|
+
def source(filename)
|
|
374
|
+
$log.debug{"Sourcing file '#{filename}'"}
|
|
375
|
+
open(filename) {|f|
|
|
376
|
+
f.each {|line|
|
|
377
|
+
begin
|
|
378
|
+
case line
|
|
379
|
+
when /^\s*\#/, /^$/
|
|
380
|
+
# comment or empty
|
|
381
|
+
when /\s*(\S+)=(.*)/
|
|
382
|
+
ENV[$1] = bash_eval($2)
|
|
383
|
+
else
|
|
384
|
+
raise "Unexpected line #{line.inspect} in source file '#{filename}'."
|
|
385
|
+
end
|
|
386
|
+
rescue
|
|
387
|
+
raise "Could not parse line #{line.inspect}: #{$!}"
|
|
388
|
+
end
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
end
|
|
392
|
+
def save_env
|
|
393
|
+
old = {}
|
|
394
|
+
ENV.each {|key,val|
|
|
395
|
+
old[key] = val
|
|
396
|
+
}
|
|
397
|
+
old
|
|
398
|
+
end
|
|
399
|
+
def load_env(new_env = nil)
|
|
400
|
+
raise "Give either a block or a new environment hash, not both." if
|
|
401
|
+
!block_given? and new_env.nil?
|
|
402
|
+
|
|
403
|
+
old_env = nil
|
|
404
|
+
if block_given?
|
|
405
|
+
old_env = save_env
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
if new_env
|
|
409
|
+
new_env.each {|key,val|
|
|
410
|
+
ENV[key] = val
|
|
411
|
+
}
|
|
412
|
+
ENV.each {|key,val|
|
|
413
|
+
ENV.delete(key) unless new_env.key?(key)
|
|
414
|
+
}
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
if block_given?
|
|
418
|
+
result = yield
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
load_env(old_env) if old_env
|
|
422
|
+
result
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def command_line_parse(str)
|
|
426
|
+
return str if str.class == Array
|
|
427
|
+
quotes = ["\"","\'"]
|
|
428
|
+
regexp = "(" + (quotes.map {|q| Regexp.escape(q) }.map {|q| "\\#{q}\\#{q}|\\#{q}([^#{q}]|\\\\#{q})*[^\\\\]\\#{q}"} + ["\\S+"]).join("|") + ")"
|
|
429
|
+
regexp = Regexp.new(regexp)
|
|
430
|
+
args = str.scan(regexp).map {|arr| arr.compact[0] }
|
|
431
|
+
args.map {|a|
|
|
432
|
+
if quotes.include?(a[0..0])
|
|
433
|
+
a = a.gsub("\\#{a[0..0]}","#{a[0..0]}")
|
|
434
|
+
a[1..-2]
|
|
435
|
+
else
|
|
436
|
+
a
|
|
437
|
+
end
|
|
438
|
+
}
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# PROGRESS BAR
|
|
442
|
+
# functions now in UI
|
|
443
|
+
def enable_progress_bar(val = true)
|
|
444
|
+
$ui.enable_progress_bar(val)
|
|
445
|
+
end
|
|
446
|
+
def progress_bar_enabled?
|
|
447
|
+
$ui.progress_bar_enabled?
|
|
448
|
+
end
|
|
449
|
+
def progress_bar(title, total, &block)
|
|
450
|
+
$ui.progress_bar(title, total, &block)
|
|
451
|
+
end
|
|
452
|
+
def progress(count)
|
|
453
|
+
$ui.progress(count)
|
|
454
|
+
end
|
|
455
|
+
def pmsg(action = nil,object = nil)
|
|
456
|
+
$ui.pmsg(action, object)
|
|
457
|
+
end
|
|
458
|
+
def pinc(action = nil, object = nil)
|
|
459
|
+
$ui.pinc(action, object)
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# SYSTEM CALLS
|
|
463
|
+
def execute_command_popen3(command, input = nil, working_dir = nil, output_file = nil, error_regexps = {})
|
|
464
|
+
raise "Will not execute command, output_file already exist: #{output_file}" if output_file and Pathname.new(output_file).exist?
|
|
465
|
+
$log.debug{"Executing command with popen3: #{command.inspect}"}
|
|
466
|
+
$log.debug{"Changing to directory '#{working_dir}'"}
|
|
467
|
+
my_logs = []
|
|
468
|
+
error_ocurred = false
|
|
469
|
+
FileUtils.cd((working_dir or ".")) {
|
|
470
|
+
begin
|
|
471
|
+
popen3_process = Open3.popen3(*command) { |stdin, stdout, stderr|
|
|
472
|
+
stderrf = Thread.fork {
|
|
473
|
+
$log.debug{"Forked stderr redirect."}
|
|
474
|
+
begin
|
|
475
|
+
while (line = stderr.readline)
|
|
476
|
+
logged = error_regexps.each {|action, regexps|
|
|
477
|
+
if regexps.each {|r| break if line =~ r }.nil?
|
|
478
|
+
my_logs.push [action, regexps, line]
|
|
479
|
+
if action == :print
|
|
480
|
+
print line
|
|
481
|
+
else
|
|
482
|
+
$log.info("#{action}: #{line}")
|
|
483
|
+
end
|
|
484
|
+
break
|
|
485
|
+
end
|
|
486
|
+
}.nil?
|
|
487
|
+
unless logged
|
|
488
|
+
$log.error("Popen3 output error: #{line.strip}")
|
|
489
|
+
error_ocurred = true
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
rescue EOFError, IOError
|
|
493
|
+
# OK, this happens ;-)
|
|
494
|
+
rescue
|
|
495
|
+
$log.error{"Error in forked stderr '#{$!.class}': #{$!}"}
|
|
496
|
+
end
|
|
497
|
+
$log.debug{"End of forked stderr redirect."}
|
|
498
|
+
}
|
|
499
|
+
stdoutf = Thread.fork {
|
|
500
|
+
$log.debug{"Forked stdout redirect."}
|
|
501
|
+
if output_file
|
|
502
|
+
bsiz = 65536
|
|
503
|
+
open(output_file, "w") do |o_file|
|
|
504
|
+
begin
|
|
505
|
+
while (r = stdout.read(bsiz))
|
|
506
|
+
o_file.write(r)
|
|
507
|
+
end
|
|
508
|
+
rescue EOFError;
|
|
509
|
+
# OK, this happens ;-)
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
else
|
|
513
|
+
begin
|
|
514
|
+
while (line = stdout.readline)
|
|
515
|
+
$log.info(line.strip)
|
|
516
|
+
end
|
|
517
|
+
rescue EOFError, IOError
|
|
518
|
+
# OK, this happens ;-)
|
|
519
|
+
rescue
|
|
520
|
+
$log.error{"Error in forked stdout '#{$!.class}': #{$!}"}
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
$log.debug{"End of forked stdout redirect."}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
begin
|
|
527
|
+
if input
|
|
528
|
+
input.each {|f|
|
|
529
|
+
# DEPRECATED next if f == get_config("DIRLIST_ENTRY")
|
|
530
|
+
$log.debug{"Writing #{f.to_s} to stdin"}
|
|
531
|
+
stdin.write("#{f.to_s}\n")
|
|
532
|
+
}
|
|
533
|
+
end
|
|
534
|
+
stdin.flush
|
|
535
|
+
stdin.close
|
|
536
|
+
rescue
|
|
537
|
+
raise "Error writing to stdin: #{$!}"
|
|
538
|
+
end
|
|
539
|
+
$log.debug{Process.pid}
|
|
540
|
+
$log.debug{"Joining stderr fork."}
|
|
541
|
+
stderrf.join
|
|
542
|
+
$log.debug{"Joining stdout fork."}
|
|
543
|
+
stdoutf.join
|
|
544
|
+
$log.debug{"All foks exited."}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
raise "Popen3 command execution error." if error_ocurred
|
|
548
|
+
# These checks fail, probably we are too fast.
|
|
549
|
+
# lOutputFile = Pathname.new(lOutputFile.to_s)
|
|
550
|
+
# raise "command successful but target file does not exist!" if !lOutputFile.exist?
|
|
551
|
+
# raise "command successful but target file has size 0!" if lOutputFile.size == 0
|
|
552
|
+
rescue
|
|
553
|
+
$log.error{"Error executing #{command.inspect} in #{Dir.pwd}"}
|
|
554
|
+
raise "Error executing popen3 command: #{$!}"
|
|
555
|
+
end
|
|
556
|
+
}
|
|
557
|
+
my_logs
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
# OPTPARSE
|
|
561
|
+
def parse_arguments(description, arguments)
|
|
562
|
+
argument_names = description.split(" ")
|
|
563
|
+
params = {}
|
|
564
|
+
argument_names.each_with_index {|an,i|
|
|
565
|
+
optional = false
|
|
566
|
+
if an =~ /\[(.*)\]/
|
|
567
|
+
an = $1
|
|
568
|
+
optional = true
|
|
569
|
+
end
|
|
570
|
+
if an =~ /\{(.*)\}/
|
|
571
|
+
an = $1
|
|
572
|
+
optional = true
|
|
573
|
+
params[an.downcase.to_sym] = arguments[i..-1]
|
|
574
|
+
raise "After {..} argument no more arguments allowed!" if argument_names.length > (i+1)
|
|
575
|
+
break
|
|
576
|
+
end
|
|
577
|
+
raise "Argument #{an} (##{i}) not provided and argument is not optional" unless
|
|
578
|
+
optional or arguments[i]
|
|
579
|
+
params[an.downcase.to_sym] = arguments[i]
|
|
580
|
+
}
|
|
581
|
+
params
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# usage:
|
|
585
|
+
# args = optparse(:arguments => [["ARG1", "Description of arg1"],["ARG2","Desc arg2"]])
|
|
586
|
+
# args: ["bla","bla"...]
|
|
587
|
+
# or
|
|
588
|
+
# action, args = optparse(:actions => {"action1 ARG1 ARG2 {ARG3}"
|
|
589
|
+
# action: "action1"
|
|
590
|
+
# args: {:arg1 => "bl", :arg2 => "bla"}
|
|
591
|
+
def optparse(options = {})
|
|
592
|
+
require 'optparse'
|
|
593
|
+
pbar = false
|
|
594
|
+
|
|
595
|
+
raise "Cannot parse commandline for #{arguments} and #{actions}" if options[:arguments] and options[:actions]
|
|
596
|
+
argument_names = []
|
|
597
|
+
argument_help = nil
|
|
598
|
+
if options[:arguments]
|
|
599
|
+
argument_names = options[:arguments].map{|name,text| name}
|
|
600
|
+
argument_help = options[:arguments]
|
|
601
|
+
end
|
|
602
|
+
if options[:actions]
|
|
603
|
+
argument_names = [options[:actions].keys.map {|k| k.split(" ")[0]}.sort.join("|"), "ARGS"]
|
|
604
|
+
argument_help = options[:actions].map {|a,b| [a,b]}
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
opts = OptionParser.new do |o|
|
|
608
|
+
o.banner += "Usage: #{program_name} [options] [--] #{argument_names.join(" ")}\n"
|
|
609
|
+
if argument_help
|
|
610
|
+
o.banner += "\nArguments:\n"
|
|
611
|
+
width = argument_help.map {|arg, text| arg.length}.max
|
|
612
|
+
argument_help = argument_help.sort_by {|a| a[0]}
|
|
613
|
+
argument_help.each {|arg, text|
|
|
614
|
+
o.banner += " #{arg.ljust(width)} : #{text}\n"
|
|
615
|
+
}
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
if block_given?
|
|
619
|
+
yield o
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
o.banner += "\nOptions:\n"
|
|
623
|
+
|
|
624
|
+
o.on("-Lb","--benchmark","Print out benchmark information on info log") do
|
|
625
|
+
benchmarking = true
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
o.on("-Lp","--profile DIR","Write profiling information to this directory") do |dir|
|
|
629
|
+
self.profiling = dir
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
o.on("-q","--quiet","be quiet, print only errors") do
|
|
633
|
+
Log.log_level = Log.log_level + 1
|
|
634
|
+
end
|
|
635
|
+
o.on("-v","--verbose","be verbose") do
|
|
636
|
+
Log.log_level = Log.log_level - 1
|
|
637
|
+
end
|
|
638
|
+
unless @ui_overwritten
|
|
639
|
+
o.on("--ui <kde,console>","Force userinterface") do |ui|
|
|
640
|
+
change_ui(ui)
|
|
641
|
+
end
|
|
642
|
+
end
|
|
643
|
+
o.on("--progress","Show progress information") do
|
|
644
|
+
pbar = true
|
|
645
|
+
end
|
|
646
|
+
o.on("-O","--output FILENAME", "Output to the file. Possible endings (#{Doc.output_endings.inspect})") {|f|
|
|
647
|
+
# -O output.text -O output.txt
|
|
648
|
+
# -O output.html -O output.htm
|
|
649
|
+
# mail html output to fpellanda: -O "output.html>flavio.pellanda@logintas.ch"
|
|
650
|
+
add_output(f)
|
|
651
|
+
}
|
|
652
|
+
o.on("-h", "--help", "This help." ) do
|
|
653
|
+
puts o
|
|
654
|
+
exit
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
begin
|
|
660
|
+
$log.debug{"Parsing #{ARGV.inspect}"}
|
|
661
|
+
opts.parse!( ARGV )
|
|
662
|
+
rescue => exc
|
|
663
|
+
$log.error("E: #{exc.message}")
|
|
664
|
+
if $log.debug?
|
|
665
|
+
exc.backtrace.each {|l| $log.debug(l)}
|
|
666
|
+
end
|
|
667
|
+
STDERR.puts opts.to_s
|
|
668
|
+
exit 1
|
|
669
|
+
end
|
|
670
|
+
# must be set after change_ui
|
|
671
|
+
$ui.enable_progress_bar if pbar
|
|
672
|
+
|
|
673
|
+
if options[:arguments]
|
|
674
|
+
min_arguments = argument_names.reject{|a| a =~ /^\{|\[/}.length
|
|
675
|
+
raise "Too few arguments provided (#{ARGV.length} for at least #{min_arguments})." if argument_names and ARGV.length < min_arguments
|
|
676
|
+
return ARGV
|
|
677
|
+
end
|
|
678
|
+
if options[:actions]
|
|
679
|
+
if ARGV[0].nil?
|
|
680
|
+
puts opts
|
|
681
|
+
exit
|
|
682
|
+
end
|
|
683
|
+
action, desc, text = options[:actions].each {|a,t|
|
|
684
|
+
sp = a.split(" ")
|
|
685
|
+
break [ARGV[0],sp[1..-1].join(" "),t] if sp[0].split("|").include?(ARGV[0])
|
|
686
|
+
}
|
|
687
|
+
raise "Action '#{ARGV[0]}' not supported." unless desc
|
|
688
|
+
params = parse_arguments(desc, ARGV[1..-1])
|
|
689
|
+
return [action, params]
|
|
690
|
+
end
|
|
691
|
+
ARGV
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
## instances
|
|
695
|
+
def pid_file
|
|
696
|
+
if program_instance
|
|
697
|
+
Pathname.new("/tmp/#{program_name}-#{program_instance.gsub(/[^a-zA-Z0-9]/,"_")}-#{program_instance.hash.abs}.pid")
|
|
698
|
+
else
|
|
699
|
+
Pathname.new("/tmp/#{program_name.gsub(/[^a-zA-Z0-9]/,"_")}.pid")
|
|
700
|
+
end
|
|
701
|
+
end
|
|
702
|
+
def ensure_script_not_running_already(error_on_concurrent = true)
|
|
703
|
+
if pid_file.exist?
|
|
704
|
+
pid = pid_file.readlines.join.strip.to_i
|
|
705
|
+
$log.debug{"Pid file exist with pid #{pid}."}
|
|
706
|
+
if system("/bin/ps #{pid} > /dev/null")
|
|
707
|
+
name = program_name
|
|
708
|
+
name += " (#{program_instance})" if program_instance
|
|
709
|
+
if error_on_concurrent
|
|
710
|
+
$log.fatal("#{name} already running (pid:#{pid}).")
|
|
711
|
+
exit 1
|
|
712
|
+
else
|
|
713
|
+
$log.info("#{name} already running (pid:#{pid}). Exiting normally.\n")
|
|
714
|
+
exit 0
|
|
715
|
+
end
|
|
716
|
+
else
|
|
717
|
+
# process not running anymore
|
|
718
|
+
# TODO: this should have level warn, but the pid file is normally not remove properly in current version
|
|
719
|
+
$log.info("Removing #{pid_file} process #{pid} not runnning anymore.")
|
|
720
|
+
pid_file.delete
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
$log.debug{"Creating pid file for process #{Process.pid}"}
|
|
724
|
+
pid_file.open("w") {|f| f.write(Process.pid.to_s) }
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
## KONSOLE
|
|
728
|
+
@konsole = nil
|
|
729
|
+
@libisi_konsole_sessions = {}
|
|
730
|
+
def open_konsole_session(name)
|
|
731
|
+
@konsole = open("|dcopstart konsole-script").gets.strip unless @konsole
|
|
732
|
+
session = open("|dcop #{@konsole} konsole newSession").gets.strip
|
|
733
|
+
system("dcop #{@konsole} #{session} renameSession #{name}")
|
|
734
|
+
|
|
735
|
+
@konsole_sessions[name] = session
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
def send_command(name, command)
|
|
739
|
+
session = @konsole_sessions[name]
|
|
740
|
+
system("dcop #{@konsole} #{session} sendSession \"#{command}\"")
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
## DCOP
|
|
744
|
+
def dcop_media_list
|
|
745
|
+
media = {}
|
|
746
|
+
open("|dcop kded mediamanager fullList") {|f|
|
|
747
|
+
f.readlines.join.split("---\n").map {|e|
|
|
748
|
+
e.split("\n")
|
|
749
|
+
}
|
|
750
|
+
}.each {|entry|
|
|
751
|
+
name = entry[1]
|
|
752
|
+
media[name] = {}
|
|
753
|
+
#/org/freedesktop/Hal/devices/volume_uuid_02a67e94_d030_4211_8b21_ebf0a517aac5
|
|
754
|
+
media[name][:id] = entry[0]
|
|
755
|
+
# sdd1
|
|
756
|
+
media[name][:name] = name
|
|
757
|
+
#221M Removable Media
|
|
758
|
+
media[name][:description] = entry[2]
|
|
759
|
+
#
|
|
760
|
+
#media[name][] = entry[3]
|
|
761
|
+
#true
|
|
762
|
+
#media[name][] = entry[4]
|
|
763
|
+
#/dev/sdd1
|
|
764
|
+
media[name][:device] = entry[5]
|
|
765
|
+
#/media/user-fpellanda
|
|
766
|
+
media[name][:mount_point] = entry[6]
|
|
767
|
+
#ext3
|
|
768
|
+
media[name][:fs_type] = entry[7]
|
|
769
|
+
#true
|
|
770
|
+
#media[name][] = entry[8]
|
|
771
|
+
#
|
|
772
|
+
#media[name][] = entry[9]
|
|
773
|
+
#media/removable_mounted_decrypted
|
|
774
|
+
media[name][:mime_type] = entry[10]
|
|
775
|
+
#
|
|
776
|
+
#media[name][] = entry[11]
|
|
777
|
+
#true
|
|
778
|
+
#media[name][] = entry[12]
|
|
779
|
+
#/org/freedesktop/Hal/devices/volume_uuid_3eebb364_b2c9_4491_a4a2_04b193fc20ac
|
|
780
|
+
#media[name][] = entry[13]
|
|
781
|
+
}
|
|
782
|
+
media
|
|
783
|
+
end
|
|
784
|
+
def normalize_device_name(name)
|
|
785
|
+
name = case name
|
|
786
|
+
when /^media:\/(.*)/
|
|
787
|
+
$1
|
|
788
|
+
when /^\/dev\/(.*)/
|
|
789
|
+
$1
|
|
790
|
+
when /system:\/media\/(.*)/
|
|
791
|
+
$1
|
|
792
|
+
else
|
|
793
|
+
name
|
|
794
|
+
end
|
|
795
|
+
end
|
|
796
|
+
def dcop_find_media(name)
|
|
797
|
+
name = normalize_device_name
|
|
798
|
+
$log.debug{"Looking for media #{name}"}
|
|
799
|
+
ml = media_list
|
|
800
|
+
$log.debug{"Found medias: #{ml.keys.inspect}"}
|
|
801
|
+
media = ml[name]
|
|
802
|
+
raise "Media #{name} not found." unless media
|
|
803
|
+
media
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
# system
|
|
807
|
+
def daemonize(options = {})
|
|
808
|
+
save_pid = (pid_file.exist? and pid_file.readlines.join.strip.to_i == Process.pid)
|
|
809
|
+
|
|
810
|
+
fork and exit
|
|
811
|
+
if options[:pid_file]
|
|
812
|
+
File.open(options[:pid_file],"w") do |f|
|
|
813
|
+
f << Process.pid
|
|
814
|
+
end
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
# child becomes session leader and disassociates controlling tty.
|
|
818
|
+
# namely do Process.setpgrp + \alpha.
|
|
819
|
+
Process.setsid
|
|
820
|
+
|
|
821
|
+
# at here already the child process have become daemon. the rest
|
|
822
|
+
# is just for behaving well.
|
|
823
|
+
|
|
824
|
+
# save new pid to pid_file
|
|
825
|
+
pid_file.open("w") {|f| f.write(Process.pid.to_s) } if save_pid
|
|
826
|
+
|
|
827
|
+
# there is now no console anymore
|
|
828
|
+
if $ui.name == "ConsoleUI"
|
|
829
|
+
change_ui("nobody")
|
|
830
|
+
ENV.delete("TERM")
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
# ensure no extra I/O.
|
|
834
|
+
File.open("/dev/null", "r+") do
|
|
835
|
+
|devnull|
|
|
836
|
+
$stdin.reopen(devnull)
|
|
837
|
+
if options[:log_file]
|
|
838
|
+
$stdout.reopen("#{options[:log_file]}.log")
|
|
839
|
+
$stderr.reopen("#{options[:log_file]}.err")
|
|
840
|
+
else
|
|
841
|
+
$stdout.reopen(devnull)
|
|
842
|
+
$stderr.reopen(devnull)
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
# ensure daemon process not to prevent shutdown process.
|
|
847
|
+
Dir.chdir("/")
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
# RAILS STUFF
|
|
851
|
+
def rails_root
|
|
852
|
+
return Pathname.new(RAILS_ROOT) if defined?(RAILS_ROOT)
|
|
853
|
+
return Pathname.new(ENV["RAILS_ROOT"]) if ENV["RAILS_ROOT"]
|
|
854
|
+
return nil unless ENV["main_script"]
|
|
855
|
+
return Pathname.new(FileUtils.pwd) if main_script.basename.to_s == "rake"
|
|
856
|
+
main_script.realpath.dirname + ".."
|
|
857
|
+
end
|
|
858
|
+
def rails_available?
|
|
859
|
+
return false unless rails_root
|
|
860
|
+
(rails_root + 'config/boot.rb').exist? and
|
|
861
|
+
(rails_root + 'config/environment.rb').exist?
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
# include in boot:
|
|
865
|
+
# unless defined?(LIBISI)
|
|
866
|
+
# require 'libisi'
|
|
867
|
+
# init_libisi
|
|
868
|
+
# require "libisi/color"
|
|
869
|
+
# Doc.change("html", :doc_started => true)
|
|
870
|
+
# end
|
|
871
|
+
# or in script:
|
|
872
|
+
# initialize_rails
|
|
873
|
+
def initialize_rails
|
|
874
|
+
raise "Rails not available." unless rails_available?
|
|
875
|
+
# add this to load path to avoid real logger.rb class
|
|
876
|
+
# to be loaded
|
|
877
|
+
# $LOAD_PATH.insert(0, "/usr/lib/ruby/1.8/libisi/fake_logger/")
|
|
878
|
+
|
|
879
|
+
$log.debug{"Starting rails environment."}
|
|
880
|
+
require rails_root + 'config/boot'
|
|
881
|
+
require rails_root + 'config/environment'
|
|
882
|
+
$log.debug{"Rails environment started."}
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
# from activesupport-1.3.1/lib/active_support/core_ext/enumerable.rb
|
|
888
|
+
module Enumerable
|
|
889
|
+
def group_by
|
|
890
|
+
inject({}) do |groups, element|
|
|
891
|
+
(groups[yield(element)] ||= []) << element
|
|
892
|
+
groups
|
|
893
|
+
end
|
|
894
|
+
end
|
|
895
|
+
|
|
896
|
+
def group_bys(*args)
|
|
897
|
+
if args[-1].class == Hash
|
|
898
|
+
options = args[-1]
|
|
899
|
+
functions = args[0..-2]
|
|
900
|
+
else
|
|
901
|
+
options = {}
|
|
902
|
+
functions = args
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
of = ((options[:order_functions] and options[:order_functions][0]) or
|
|
906
|
+
lambda {|e|
|
|
907
|
+
if e.respond_to?(:"<=>") then
|
|
908
|
+
e
|
|
909
|
+
else
|
|
910
|
+
e.to_s
|
|
911
|
+
end
|
|
912
|
+
}
|
|
913
|
+
)
|
|
914
|
+
|
|
915
|
+
if (gf = functions[0])
|
|
916
|
+
unordered = self.group_by(&gf)
|
|
917
|
+
# TODO: Would be good but problems with base table
|
|
918
|
+
#res = OrderedHash.new
|
|
919
|
+
res = []
|
|
920
|
+
begin
|
|
921
|
+
ordered_keys = unordered.keys.sort_by{|k| of.call(k)}
|
|
922
|
+
rescue
|
|
923
|
+
$log.warn("Error ocurred sorting keys: #{$!}!")
|
|
924
|
+
ordered_keys = unordered.keys
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
ordered_keys.each {|key|
|
|
928
|
+
# TODO: Would be good but problems with base table
|
|
929
|
+
#res[key] = unordered[key].group_bys(*functions[1..-1])
|
|
930
|
+
res << [key, unordered[key].group_bys(*functions[1..-1])]
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
else
|
|
934
|
+
res = self
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
res
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
end
|
|
941
|
+
|
|
942
|
+
class String
|
|
943
|
+
def starts_with?(other)
|
|
944
|
+
self[0..(other.length-1)] == other
|
|
945
|
+
end
|
|
946
|
+
end
|
|
947
|
+
|
|
948
|
+
include LibIsi
|