Module: WikiFlatFileStore

Included in:
Wiki
Defined in:
lib/soks-storage.rb

Constant Summary collapse

CONTENT_EXTENSION =
'.textile'
REVISIONS_EXTENSION =
'.yaml'
DEFAULT_AUTHOR =
'the import script'

Instance Method Summary collapse

Instance Method Details

#check_disk_for_updated_page(pagename, force = false) ⇒ Object



77
78
79
80
81
82
83
84
# File 'lib/soks-storage.rb', line 77

def check_disk_for_updated_page( pagename, force = false )
	return unless force || self.check_files_every # We don't care about file changes 
	filename = filename_for_content( pagename )
	return :file_does_not_exist unless File.exists?( filename ) # File doesn't exist on disk
	return load_page( filename ) unless page_named( pagename )# File is new on the disk, but not yet in memory 
	return load_page( filename ) if content_newer_than_revisions?( page_named(pagename) ) # File is newer on disk
	return nil
end

#content_newer_than_revisions?(page) ⇒ Boolean

Returns:

  • (Boolean)


132
133
134
135
# File 'lib/soks-storage.rb', line 132

def content_newer_than_revisions?( page )
	return true if page.empty?
	File.ctime(filename_for_content( page.name )) > File.ctime(filename_for_revisions(page.name))
end

#delete_files_for_page(page_name) ⇒ Object



68
69
70
# File 'lib/soks-storage.rb', line 68

def delete_files_for_page( page_name )
	File.delete( filename_for_content( page_name ), filename_for_revisions( page_name ) )
end

#filename_for_content(pagename) ⇒ Object



179
180
181
# File 'lib/soks-storage.rb', line 179

def filename_for_content( pagename )
	File.join( @folder, "#{pagename.url_encode}#{CONTENT_EXTENSION}" )
end

#filename_for_revisions(pagename) ⇒ Object



183
184
185
# File 'lib/soks-storage.rb', line 183

def filename_for_revisions( pagename )
	File.join( @folder, "#{pagename.url_encode}#{REVISIONS_EXTENSION}" )
end

#load_all_pagesObject



52
53
54
55
56
57
58
59
60
61
# File 'lib/soks-storage.rb', line 52

def load_all_pages
	move_files_if_names_are_not_url_encoded
	pages_on_disk = Dir[ File.join( @folder, "*#{CONTENT_EXTENSION}" ) ].map { |filename| page_name_for( filename )}
	pages_in_memory = @pages.values.map { |page| page && page.name }
	( pages_in_memory.compact | pages_on_disk ).each do |pagename| 
		if check_disk_for_updated_page( pagename, true ) == :file_does_not_exist
			revise( pagename, $MESSAGES[:page_deleted], DEFAULT_AUTHOR )
		end
	 end
end

#load_content(page) ⇒ Object



110
111
112
# File 'lib/soks-storage.rb', line 110

def load_content( page )
	IO.readlines( filename_for_content( page.name ) ).join
end

#load_page(filename) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/soks-storage.rb', line 86

def load_page( filename )
	mutate( page_name_for( filename ) ) do |page|
		disk_content = load_content( page )
		return nil if disk_content == page.content # No change, disk is the same as memory

		# We now know that the content on disk is different from that in memory
		
		page.revisions = load_revisions( page ) if page.revisions.empty? # Load revisions from disk if none known 
		# assumes disk revisions are ALWAYS up to date with memory?
		
		# We now know what the page content and the page revisions should be. But not if the revisions are up to date	
		if content_newer_than_revisions?( page ) # The textile file has been modified, but the array file has not been updated to match
			page.content = reconstruct_content_from_revisions( page.revisions )
			page.revise( disk_content, DEFAULT_AUTHOR )
			save_last_revision( page )
		else # The textile file and the array file are in sync.
			page.content = disk_content
		end
	
		add_page_to_index( page )
		[ page.revisions.last, :dont_save ]
	end
end

#load_revisions(page) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/soks-storage.rb', line 114

def load_revisions( page )
	return [] unless File.exists?( filename_for_revisions( page.name ) )
	revisions = []
	begin
		File.open( filename_for_revisions( page.name ) ) { |file| 
			YAML.each_document( file ) { |array|
				next unless array.is_a? Array 
				next unless array.size == 4
				next unless array[0].is_a? Integer 
				revisions[ array[0] ] = Revision.new( page, *array ) } 
		}
	rescue
		$LOG.error "Error loading revisions with #{$!.to_s} in file #{page.name}"
	end
	revisions.each_with_index { |r,i| $LOG.error "#{page.name} missing revision #{i}" unless r }
	revisions
end

#move_files_for_page(old_page_name, new_page_name) ⇒ Object



72
73
74
75
# File 'lib/soks-storage.rb', line 72

def move_files_for_page( old_page_name, new_page_name )
	File.rename( filename_for_content( old_page_name ), filename_for_content( new_page_name ) )
	File.rename( filename_for_revisions( old_page_name ), filename_for_revisions( new_page_name ) )
end

#move_files_if_names_are_not_url_encodedObject



143
144
145
146
147
148
149
150
# File 'lib/soks-storage.rb', line 143

def move_files_if_names_are_not_url_encoded
	Dir[ File.join( @folder, "*#{CONTENT_EXTENSION}" ) ].each do |filename|
		basename = File.basename( filename, '.*')
		next if basename.url_decode.url_encode == basename # All ok, so no worry
		new_name = File.join( File.dirname(filename), File.unique_filename( File.dirname(filename), basename.url_decode.url_encode +  File.extname( filename) ) )
		File.rename(filename, new_name )
	end
end

#page_name_for(filename) ⇒ Object



175
176
177
# File 'lib/soks-storage.rb', line 175

def page_name_for( filename )
	File.basename( filename, '.*').url_decode	
end

#reconstruct_content_from_revisions(revisions) ⇒ Object



137
138
139
140
141
# File 'lib/soks-storage.rb', line 137

def reconstruct_content_from_revisions( revisions )
	content = []
	revisions.each { |revision| content = Diff::LCS.patch( content, revision.changes, :patch ) }
	content.join("\n")
end

#save(page) ⇒ Object



63
64
65
66
# File 'lib/soks-storage.rb', line 63

def save( page )
	save_content( page )
	save_last_revision( page )
end

#save_all_revisions(page) ⇒ Object



165
166
167
168
169
170
171
172
173
# File 'lib/soks-storage.rb', line 165

def save_all_revisions( page )
	$LOG.warn "Saving all revisions for #{page.name}"
	File.open(filename_for_revisions( page.name ), 'w' ) do |file|
		page.revisions.each do |revision| 
			YAML.dump( revision.to_a, file )
			file.puts # Needed to ensure that documents are separated
		end
	end
end

#save_content(page) ⇒ Object



152
153
154
# File 'lib/soks-storage.rb', line 152

def save_content( page )
	File.open(filename_for_content( page.name ), 'w' ) { |file| file.puts page.content }
end

#save_last_revision(page) ⇒ Object

Appends the last revision onto the yaml file



157
158
159
160
161
162
163
# File 'lib/soks-storage.rb', line 157

def save_last_revision( page )
	$LOG.info "Saving revisions for #{page.name}"
	File.open(filename_for_revisions( page.name ), 'a' ) do |file| 
		YAML.dump( page.revisions.last.to_a, file )
		file.puts # Needed to ensure that documents are separated
	end
end