Pimki 1.4.092 → 1.5.092
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/README-PIMKI +20 -8
- data/app/controllers/wiki.rb +123 -24
- data/app/models/chunks/engines.rb +6 -2
- data/app/models/chunks/uri.rb +1 -1
- data/app/models/chunks/wiki.rb +15 -14
- data/app/models/page.rb +1 -1
- data/app/models/wiki_content.rb +9 -8
- data/app/models/wiki_service.rb +8 -1
- data/app/views/navigation.rhtml +1 -0
- data/app/views/wiki/adv_search.rhtml +61 -0
- data/app/views/wiki/bliki.rhtml +4 -2
- data/app/views/wiki/bliki_revision.rhtml +1 -1
- data/app/views/wiki/edit.rhtml +4 -3
- data/app/views/wiki/edit_menu.rhtml +1 -1
- data/app/views/wiki/edit_web.rhtml +27 -14
- data/app/views/wiki/page.rhtml +1 -1
- data/app/views/wiki/revision.rhtml +17 -11
- data/app/views/wiki/rollback.rhtml +3 -0
- data/app/views/wiki/search.rhtml +6 -3
- data/favicon.png +0 -0
- data/libraries/action_controller_servlet.rb +9 -4
- data/libraries/madeleine/automatic.rb +1 -1
- data/libraries/madeleine_service.rb +107 -12
- data/libraries/redcloth_2.0.11.rb +894 -0
- data/pimki.rb +85 -70
- metadata +7 -5
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<% @title = "Advanced Search Options" %>
|
|
2
|
+
<%= sub_template "top" %>
|
|
3
|
+
|
|
4
|
+
<h3>Advanced Search Options:</h3>
|
|
5
|
+
|
|
6
|
+
<form action="../search/" method="post">
|
|
7
|
+
<table>
|
|
8
|
+
<tr>
|
|
9
|
+
<td>Search string:</td>
|
|
10
|
+
<td colspan="3"><input type='text' name='query' id='query' size='60' /></td>
|
|
11
|
+
</tr>
|
|
12
|
+
<tr><td> </td></tr>
|
|
13
|
+
<tr>
|
|
14
|
+
<td colspan="3"><input type='checkbox' name='case'>Case sensitive</input></td>
|
|
15
|
+
</tr>
|
|
16
|
+
<tr>
|
|
17
|
+
<td>Search string as</td>
|
|
18
|
+
<td><input type='Radio' name='expression' value='regex' checked>Regular Expression</input></td>
|
|
19
|
+
<td><input type='Radio' name='expression' value='all'>All words</input></td>
|
|
20
|
+
<td><input type='Radio' name='expression' value='exact'>Exact phrase</input></td>
|
|
21
|
+
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<td>Search in</td>
|
|
24
|
+
<td><input type='Radio' name='where' value='all' checked>Pages & Bliki entries</input></td>
|
|
25
|
+
<td><input type='Radio' name='where' value='pages'>Pages only</input></td>
|
|
26
|
+
<td><input type='Radio' name='where' value='bliki'>Bliki entries only</input></td>
|
|
27
|
+
</tr>
|
|
28
|
+
<tr>
|
|
29
|
+
<td>Search on</td>
|
|
30
|
+
<td><input type='Radio' name='fields' value='both' checked>Pages names & contents</input></td>
|
|
31
|
+
<td><input type='Radio' name='fields' value='names'>Page names only</input></td>
|
|
32
|
+
<td><input type='Radio' name='fields' value='contents'>Page contents only</input></td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td colspan="2">Limit search to selected categories:</td>
|
|
36
|
+
<td colspan="2"><select id="category" name="category" size="3" multiple style="width:200">
|
|
37
|
+
<option value="noselect">------------
|
|
38
|
+
<% for category in web.categories %>
|
|
39
|
+
<option value="<%= category %>"><%= category %>
|
|
40
|
+
<% end %>
|
|
41
|
+
</select>
|
|
42
|
+
</td>
|
|
43
|
+
</tr>
|
|
44
|
+
<tr>
|
|
45
|
+
<td colspan="2">Limit search to selected authors:</td>
|
|
46
|
+
<td colspan="2"><select id="author" name="author" size="3" multiple style="width:200">
|
|
47
|
+
<option value="noselect">------------
|
|
48
|
+
<% for author in web.authors %>
|
|
49
|
+
<option value="<%= author %>"><%= author %>
|
|
50
|
+
<% end %>
|
|
51
|
+
</select>
|
|
52
|
+
</tr>
|
|
53
|
+
<tr>
|
|
54
|
+
<td><input type='submit' value='Search'></td>
|
|
55
|
+
</tr>
|
|
56
|
+
</table>
|
|
57
|
+
</form>
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
<%= sub_template "bottom" %>
|
|
61
|
+
|
data/app/views/wiki/bliki.rhtml
CHANGED
|
@@ -79,9 +79,9 @@ function validateSelection() {
|
|
|
79
79
|
</script>
|
|
80
80
|
|
|
81
81
|
<h2>Apply filter:</h2>
|
|
82
|
+
<form class="navigation" action="bliki" action="post" onSubmit="return validateSelection();">
|
|
82
83
|
<table><tr>
|
|
83
84
|
<td>Show only pages authored by:</td>
|
|
84
|
-
<form class="navigation" action="bliki" action="post" onSubmit="return validateSelection();">
|
|
85
85
|
<td>
|
|
86
86
|
<select id="sel_author" name="authorname" size="1">
|
|
87
87
|
<option value="noselect">------------
|
|
@@ -94,8 +94,10 @@ function validateSelection() {
|
|
|
94
94
|
<td>Regexp search on all entries:</td>
|
|
95
95
|
<td><input type="text" id="search_regex" name="regexp"></td>
|
|
96
96
|
<td><input type="submit" name="Search" value="Search"></td>
|
|
97
|
-
|
|
97
|
+
</tr><tr>
|
|
98
|
+
<td>Or go to <a href='../adv_search/'>Advanced Search</a></td>
|
|
98
99
|
</tr></table>
|
|
100
|
+
</form>
|
|
99
101
|
|
|
100
102
|
<%= sub_template "bottom" %>
|
|
101
103
|
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
|
|
64
64
|
<% if @page.revisions.length > 1 %>
|
|
65
65
|
<span id="show_changes">
|
|
66
|
-
| <a href="#" onClick="toggleChanges(); return false;">
|
|
66
|
+
| <a href="#" onClick="toggleChanges(); return false;">Show changes</a>
|
|
67
67
|
</span>
|
|
68
68
|
<span id="hide_changes" style="display: none">
|
|
69
69
|
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
|
data/app/views/wiki/edit.rhtml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<%
|
|
2
2
|
@title = "Editing #{@page.plain_name}"
|
|
3
|
-
@content_width =
|
|
3
|
+
@content_width = 810
|
|
4
4
|
@hide_navigation = true
|
|
5
|
-
@style_additions = "#
|
|
5
|
+
@style_additions = "#Content, #Container {padding-left:100px;}"
|
|
6
6
|
%>
|
|
7
7
|
<%= sub_template "top" %>
|
|
8
8
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<%= render_markup_help %>
|
|
12
12
|
|
|
13
|
+
<div id='main'>
|
|
13
14
|
<form style="float:right" id="editForm" action="../save/<%= @page.name %>" method="post" onSubmit="cleanAuthorName();">
|
|
14
15
|
<p>
|
|
15
16
|
<textarea name="content" style="width: 550px; height: 430px"><%= @page.content %></textarea>
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
| <a href="../cancel_edit/<%= @page.name %>">Cancel</a> <small>(unlocks page)</small>
|
|
32
33
|
</p>
|
|
33
34
|
</form>
|
|
34
|
-
|
|
35
|
+
</div>
|
|
35
36
|
<script language="JavaScript1.2">
|
|
36
37
|
function cleanAuthorName() {
|
|
37
38
|
if (document.getElementById('authorName').value == "") {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
</p>
|
|
25
25
|
<p>For the above options you can choose if you want to limit the number of results. Enter the number of items you wish, or 0 for all items: <input type="textfield" size="20", name="limit" value="<%= @list_limit %>" /></p>
|
|
26
26
|
<p><input type="radio" name="type" value="user" <%= 'checked' if @menu_type == 'user' %>>Or just write your own menu contents (as a regular Wiki page):
|
|
27
|
-
<textarea name="content" style="width: 400px; height: 300px"><%= @menu_content.content %></textarea>
|
|
27
|
+
<textarea name="content" style="width: 400px; height: 300px"><%= !@menu_content.nil? && Page === @menu_content ? @menu_content.content : @menu_content %></textarea>
|
|
28
28
|
</p>
|
|
29
29
|
|
|
30
30
|
<% if Page === @menu_content && @menu_content.revisions.length > 1
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<% @title = "Edit Web" %>
|
|
2
2
|
<%= sub_template "top" %>
|
|
3
3
|
|
|
4
|
+
<%= "<p style='font-size: 15px; font-variant: italic; color: red;'>#{@message}</span>" if @message %>
|
|
5
|
+
|
|
4
6
|
<form action="../update_web" id="setup" method="post" onSubmit="cleanAddress(); return validateSetup()">
|
|
5
7
|
<h2 style="margin-bottom: 3px">Name and address</h2>
|
|
6
8
|
<div class="help">
|
|
@@ -54,6 +56,15 @@
|
|
|
54
56
|
<textarea id="additionalStyle" style="display: none; margin-top: 10px; margin-bottom: 5px; width: 560px; height: 200px" name="additional_style"><%= @web.additional_style %></textarea>
|
|
55
57
|
</div>
|
|
56
58
|
|
|
59
|
+
<h2 style="margin-bottom: 3px">Persistence Options (all webs)</h2>
|
|
60
|
+
<div class="help">
|
|
61
|
+
You can set how often to take snapshots of the web data. (All incremental changes are saved as command_logs; snapshots supercede those with the full data). Recommended values are 1-2 hours if you turn the web on and off often, or 24-48 hours if this is a long running service.<br />
|
|
62
|
+
Snapshots will not be taken if there are no incremental changes (in the form of command_logs). You can always force a snapshot in the administrative tasks below.
|
|
63
|
+
</div>
|
|
64
|
+
<div class="inputBox">
|
|
65
|
+
<input align='right' type="text" name="snapshots_interval" value='<%= @snapshot_interval %>' /> hour(s).
|
|
66
|
+
</div>
|
|
67
|
+
|
|
57
68
|
<h2 style="margin-bottom: 3px">Password protection for this web (<%= @web.name %>)</h2>
|
|
58
69
|
<div class="help">
|
|
59
70
|
This is the password that visitors need to login to view and edit this web. Setting the password to nothing will remove the password protection.
|
|
@@ -148,27 +159,29 @@
|
|
|
148
159
|
<input type="password" id="system_password" name="system_password">
|
|
149
160
|
and
|
|
150
161
|
<input type="submit" value="Update Web">
|
|
151
|
-
<br/><br/>
|
|
152
|
-
...or forget changes and <a href="/new_web/">create a new web</a>
|
|
153
162
|
</small>
|
|
154
163
|
</p>
|
|
155
|
-
|
|
156
164
|
</form>
|
|
157
165
|
|
|
158
166
|
<br/>
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
<
|
|
167
|
+
<h2>Other administrative tasks</h2>
|
|
168
|
+
<form action="../administrate" id="administrate" method="post">
|
|
169
|
+
<p style="font-size: 10px;">
|
|
170
|
+
Clean up by entering system password
|
|
171
|
+
<input type="password" id="system_password" name="system_password">
|
|
172
|
+
and...
|
|
173
|
+
</p>
|
|
174
|
+
<p align='right'>
|
|
175
|
+
<input type="submit" name='action' value="Delete Orphan Pages"><br/>
|
|
176
|
+
<input type="submit" name='action' value="Clear Render Cache"><br/>
|
|
177
|
+
<input type="submit" name='action' value="Force Data Snapshot"><br/>
|
|
178
|
+
<input type="submit" name='action' value="Clean Storage"><br/>
|
|
179
|
+
</p>
|
|
180
|
+
</form>
|
|
162
181
|
|
|
163
|
-
<p
|
|
164
|
-
<small>
|
|
165
|
-
Clean up by entering system password
|
|
166
|
-
<input type="password" id="system_password" name="system_password">
|
|
167
|
-
and
|
|
168
|
-
<input type="submit" value="Delete Orphan Pages">
|
|
169
|
-
</small>
|
|
170
|
-
</p>
|
|
182
|
+
<p style='font-size: 10px;'>...or forget all your changes and <a href="/new_web/">create a new web</a>.</p>
|
|
171
183
|
|
|
184
|
+
|
|
172
185
|
<script>
|
|
173
186
|
function proposeAddress() {
|
|
174
187
|
document.getElementById('address').value =
|
data/app/views/wiki/page.rhtml
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
<% if @page.revisions.length > 1 %>
|
|
38
38
|
<span id="show_changes">
|
|
39
|
-
| <a href="#" onClick="toggleChanges(); return false;">
|
|
39
|
+
| <a href="#" onClick="toggleChanges(); return false;">Show changes</a>
|
|
40
40
|
</span>
|
|
41
41
|
<span id="hide_changes" style="display: none">
|
|
42
42
|
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
|
|
@@ -23,6 +23,15 @@
|
|
|
23
23
|
|
|
24
24
|
<div class="navigation">
|
|
25
25
|
|
|
26
|
+
<% if @revision.previous_revision %>
|
|
27
|
+
<a href="../revision/<%= @page.name %>?rev=<%= @revision.previous_revision.number %>" class="navlink">Back in time</a>
|
|
28
|
+
(<%= @revision.previous_revision.number + 1 %> more)
|
|
29
|
+
<% end %>
|
|
30
|
+
|
|
31
|
+
<% if @revision.next_revision && @revision.previous_revision %>
|
|
32
|
+
|
|
|
33
|
+
<% end %>
|
|
34
|
+
|
|
26
35
|
<% if @revision.next_revision %>
|
|
27
36
|
<% if @revision.next_revision.number < (@page.revisions.length - 1) %>
|
|
28
37
|
<a href="../revision/<%= @page.name %>?rev=<%= @revision.next_revision.number %>" class="navlink">
|
|
@@ -33,20 +42,11 @@
|
|
|
33
42
|
(<%= @revision.page.revisions.length - @revision.next_revision.number %> more)
|
|
34
43
|
<% end %>
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
|
38
|
-
<% end %>
|
|
39
|
-
|
|
40
|
-
<% if @revision.previous_revision %>
|
|
41
|
-
<a href="../revision/<%= @page.name %>?rev=<%= @revision.previous_revision.number %>" class="navlink">Back in time</a>
|
|
42
|
-
(<%= @revision.previous_revision.number + 1 %> more)
|
|
43
|
-
<% end %>
|
|
44
|
-
|
|
45
|
-
| <a href="../show/<%= @page.name %>" class="navlink">See current</a>
|
|
45
|
+
| <a href="../show/<%= @page.name %>" class="navlink">Show current</a>
|
|
46
46
|
|
|
47
47
|
<% if @revision.previous_revision %>
|
|
48
48
|
<span id="show_changes">
|
|
49
|
-
| <a href="#" onClick="toggleChanges(); return false;">
|
|
49
|
+
| <a href="#" onClick="toggleChanges(); return false;">Show changes</a>
|
|
50
50
|
</span>
|
|
51
51
|
<span id="hide_changes" style="display: none">
|
|
52
52
|
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
|
|
@@ -60,6 +60,12 @@
|
|
|
60
60
|
| Linked from: <%= @page.references.collect { |ref| "<a href='#{ref.name}'>#{ref.name}</a>" }.join(", ") %>
|
|
61
61
|
</small>
|
|
62
62
|
<% end %>
|
|
63
|
+
|
|
64
|
+
<% if @page.bliki_references.length > 0 %>
|
|
65
|
+
<small>
|
|
66
|
+
<br />| Bliki Linked from: <%= @page.bliki_references.collect { |ref| link_to_bliki(ref) }.join(", ") %>
|
|
67
|
+
</small>
|
|
68
|
+
<% end %>
|
|
63
69
|
</div>
|
|
64
70
|
|
|
65
71
|
<script language="Javascript">
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
<textarea name="content" style="font-size: 12px; width: 450px; height: 500px"><%= @revision.content %></textarea>
|
|
12
12
|
</p>
|
|
13
13
|
<p>
|
|
14
|
+
<% if @web.check_pass_on_edit %>
|
|
15
|
+
<p>Please enter edit password: <input type="password" name="password" id="password"></p>
|
|
16
|
+
<% end %>
|
|
14
17
|
<input type="submit" value="Update"> as
|
|
15
18
|
<input type="text" name="author" id="authorName" value="<%= @author %>"
|
|
16
19
|
onClick="this.value == 'AnonymousCoward' ? this.value = '' : true">
|
data/app/views/wiki/search.rhtml
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
<%
|
|
1
|
+
<% num_results = @results.length + @bliki_results.length
|
|
2
|
+
@title = num_results > 0 ? "#{num_results} page#{ 's' unless num_results == 1} contain#{ 's' if num_results == 1} \"#{@params["query"]}\"" : "No pages contains \"#{@query}\""
|
|
3
|
+
%>
|
|
4
|
+
<%= sub_template "top" %>
|
|
2
5
|
|
|
3
6
|
<% if @results.length > 0 %>
|
|
4
|
-
<h3
|
|
7
|
+
<h3><%= @results.length %> Matching Page<%= 's' unless @results.length == 1 %>:</h3>
|
|
5
8
|
<ul>
|
|
6
9
|
<% for page in @results %>
|
|
7
10
|
<li><a href="../show/<%= page.name %>"><%= page.plain_name %></a><br />
|
|
@@ -20,7 +23,7 @@
|
|
|
20
23
|
</ul>
|
|
21
24
|
<% end %>
|
|
22
25
|
<% if @bliki_results.length > 0 %>
|
|
23
|
-
<h3
|
|
26
|
+
<h3><%= @bliki_results.length %> Matching Bliki Entr<%= @bliki_results.length == 1 ? 'y' : 'ies' %>:</h3>
|
|
24
27
|
<ul>
|
|
25
28
|
<% for entry in @bliki_results %>
|
|
26
29
|
<li><a href="../bliki_revision/<%= entry.name %>?rev=<%= entry.revisions.size-1 %>"><%= entry.name %></a><br />
|
data/favicon.png
CHANGED
|
Binary file
|
|
@@ -6,11 +6,11 @@ include WEBrick
|
|
|
6
6
|
require 'view_helper'
|
|
7
7
|
|
|
8
8
|
class FavIconHandler < HTTPServlet::AbstractServlet
|
|
9
|
+
LOCAL_PATH = File.join(File.dirname(__FILE__), '../favicon.png')
|
|
10
|
+
ICO_FILE = File.open(LOCAL_PATH, "rb") { |f| f.read }
|
|
9
11
|
def do_GET(req, res)
|
|
10
|
-
ico = File.read(File.join(Dir.pwd, 'favicon.png'))
|
|
11
12
|
res['content-type'] = 'image/png'
|
|
12
|
-
res
|
|
13
|
-
res.body = ico
|
|
13
|
+
res.body = ICO_FILE
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -171,8 +171,13 @@ class ActionControllerServlet < HTTPServlet::AbstractServlet
|
|
|
171
171
|
begin
|
|
172
172
|
ERB.new(IO.readlines(template_path).join).result(binding)
|
|
173
173
|
rescue Exception => detail
|
|
174
|
-
@logger.error "
|
|
174
|
+
@logger.error "Error processing #{template_path}"
|
|
175
|
+
line = /:(\d+):/.match(detail.backtrace[0]).captures[0].to_i - 172
|
|
176
|
+
@logger.error "On Line: #{line}"
|
|
175
177
|
@logger.error detail
|
|
178
|
+
src = ERB.new(IO.readlines(template_path).join).src
|
|
179
|
+
lines = src.split("\n")[(line-1)..(line+1)]
|
|
180
|
+
@logger.error "\n\n" + lines.join("\n\n") + "\n\n"
|
|
176
181
|
raise
|
|
177
182
|
end
|
|
178
183
|
end
|
|
@@ -8,6 +8,8 @@ class MadeleineService
|
|
|
8
8
|
include Madeleine::Automatic::Interceptor
|
|
9
9
|
|
|
10
10
|
@@storage_path = self.name.downcase + "_storage"
|
|
11
|
+
automatic_read_only :snapshot_interval_hours, :take_snapshot, :clean_old_snapshots,
|
|
12
|
+
:restart, :request_stop
|
|
11
13
|
|
|
12
14
|
class << self
|
|
13
15
|
def storage_path
|
|
@@ -19,25 +21,56 @@ class MadeleineService
|
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def instance
|
|
22
|
-
|
|
24
|
+
if @system.nil?
|
|
25
|
+
@madeleine_server = MadeleineServer.new(self)
|
|
26
|
+
@system = @madeleine_server.system
|
|
27
|
+
end
|
|
23
28
|
@system
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
def restart
|
|
27
|
-
MadeleineServer.
|
|
28
|
-
@system =
|
|
32
|
+
MadeleineServer.delete_storage(self)
|
|
33
|
+
@system = nil
|
|
34
|
+
instance
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def clean_old_snapshots
|
|
38
|
+
instance
|
|
39
|
+
@madeleine_server.clean_storage(self)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def take_snapshot
|
|
43
|
+
instance
|
|
44
|
+
@madeleine_server.force_snapshot
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def snapshot_interval_hours
|
|
48
|
+
instance
|
|
49
|
+
@madeleine_server.snapshot_interval.div MadeleineServer::ONE_HOUR rescue 1
|
|
29
50
|
end
|
|
51
|
+
|
|
52
|
+
def snapshot_interval_hours= hours
|
|
53
|
+
instance
|
|
54
|
+
@madeleine_server.snapshot_interval = hours.to_i * MadeleineServer::ONE_HOUR rescue MadeleineServer::ONE_HOUR
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def request_stop
|
|
58
|
+
instance
|
|
59
|
+
@madeleine_server.request_stop
|
|
60
|
+
end
|
|
61
|
+
|
|
30
62
|
end
|
|
31
63
|
end
|
|
32
64
|
|
|
65
|
+
require 'fileutils'
|
|
33
66
|
class MadeleineServer
|
|
34
|
-
|
|
35
|
-
|
|
67
|
+
|
|
68
|
+
attr_reader :storage_path
|
|
69
|
+
attr_accessor :snapshot_interval
|
|
36
70
|
|
|
37
71
|
# Clears all the command_log and snapshot files located in the storage directory, so the
|
|
38
72
|
# database is essentially dropped and recreated as blank. Used in tests.
|
|
39
|
-
def self.
|
|
40
|
-
require 'fileutils'
|
|
73
|
+
def self.delete_storage(service)
|
|
41
74
|
if (File.directory?(service.storage_path))
|
|
42
75
|
FileUtils.rm_rf(Dir[service.storage_path + '/*.command_log'])
|
|
43
76
|
FileUtils.rm_rf(Dir[service.storage_path + '/*.snapshot'])
|
|
@@ -45,24 +78,86 @@ class MadeleineServer
|
|
|
45
78
|
FileUtils.mkdir_p(service.storage_path)
|
|
46
79
|
end
|
|
47
80
|
end
|
|
81
|
+
|
|
82
|
+
def clean_storage(service)
|
|
83
|
+
force_snapshot
|
|
84
|
+
command_logs = Dir[service.storage_path + '/*.command_log']
|
|
85
|
+
raise 'Error: existing command_logs after snapshot' unless command_logs.empty?
|
|
86
|
+
|
|
87
|
+
snapshots = Dir[service.storage_path + '/*.snapshot']
|
|
88
|
+
FileUtils.rm_rf(snapshots.sort[0..-2])
|
|
89
|
+
end
|
|
90
|
+
|
|
48
91
|
|
|
49
92
|
def initialize(service)
|
|
93
|
+
@storage_path = service.storage_path
|
|
94
|
+
@snapshot_interval = ONE_HOUR
|
|
50
95
|
marshaller = Madeleine::ZMarshal.new()
|
|
51
96
|
@server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
|
|
52
97
|
marshaller) { service.new }
|
|
53
|
-
start_snapshot_thread
|
|
98
|
+
start_snapshot_thread
|
|
54
99
|
end
|
|
55
100
|
|
|
56
101
|
def system
|
|
57
102
|
@server.system
|
|
58
103
|
end
|
|
59
104
|
|
|
105
|
+
def command_log_present?
|
|
106
|
+
not Dir[storage_path + '/*.command_log'].empty?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def force_snapshot
|
|
110
|
+
begin
|
|
111
|
+
hours_since_last_snapshot = 0
|
|
112
|
+
@server.take_snapshot
|
|
113
|
+
rescue => e
|
|
114
|
+
sleep(ONE_MINUTE)
|
|
115
|
+
retry
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
ONE_MINUTE = 60
|
|
121
|
+
ONE_HOUR = ONE_MINUTE * 60
|
|
122
|
+
MAX_INTERVAL_HOURS = 24 * 2
|
|
123
|
+
|
|
60
124
|
def start_snapshot_thread
|
|
61
|
-
Thread.new(@server) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
125
|
+
@snapshot_thread = Thread.new(@server) {
|
|
126
|
+
hours_since_last_snapshot = 0
|
|
127
|
+
while not @request_stop
|
|
128
|
+
sleep(snapshot_interval)
|
|
129
|
+
hours_since_last_snapshot += snapshot_interval.div ONE_HOUR
|
|
130
|
+
begin
|
|
131
|
+
# Take a snapshot if there is a command log
|
|
132
|
+
if command_log_present? or hours_since_last_snapshot > MAX_INTERVAL_HOURS
|
|
133
|
+
# 'Taking a Madeleine snapshot'
|
|
134
|
+
@server.take_snapshot
|
|
135
|
+
hours_since_last_snapshot = 0
|
|
136
|
+
puts "[#{DateTime.now.strftime '%F %T'}] INFO Taking snapshot"
|
|
137
|
+
else
|
|
138
|
+
puts "[#{DateTime.now.strftime '%F %T'}] INFO Skipping snapshot (no command logs)"
|
|
139
|
+
end
|
|
140
|
+
rescue => e
|
|
141
|
+
# wait for a minute (not to spoof the log with the same error)
|
|
142
|
+
# and go back into the loop, to keep trying
|
|
143
|
+
sleep(ONE_MINUTE)
|
|
144
|
+
retry
|
|
145
|
+
end
|
|
65
146
|
end
|
|
66
147
|
}
|
|
67
148
|
end
|
|
149
|
+
|
|
150
|
+
def request_stop
|
|
151
|
+
begin
|
|
152
|
+
@request_stop = true
|
|
153
|
+
if @snapshot_thread and @snapshot_thread.alive?
|
|
154
|
+
@snapshot_thread.wakeup
|
|
155
|
+
@snapshot_thread.join
|
|
156
|
+
end
|
|
157
|
+
@server.take_snapshot if command_log_present?
|
|
158
|
+
rescue => detail
|
|
159
|
+
puts detail
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
68
163
|
end
|