trac-export-wiki 1.0.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 ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Loren Segal
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,36 @@
1
+ # Trac Wiki Exporter
2
+
3
+ ## Synopsis
4
+
5
+ Exports wiki pages in Trac as HTML pages organized in categories for easy
6
+ local viewing.
7
+
8
+ ## Installing
9
+
10
+ $ [sudo] gem install trac-export-wiki
11
+
12
+ ## Using
13
+
14
+ To use this script, you need to create a `config.yaml` file that tells the
15
+ exporter which pages you want to export under which categories. You can
16
+ see a sample config.yaml file in the "examples" directory. Once you've
17
+ created your configuration file, you can call the script with:
18
+
19
+ $ trac-export-wiki config.yaml
20
+
21
+ This will download the wiki pages from your site into your current directory.
22
+ If you want to put your files in a `docs` directory, make sure to cd there
23
+ first:
24
+
25
+ $ mkdir docs
26
+ $ cd docs
27
+ $ trac-export-wiki ../config.yaml
28
+
29
+ You can specify some parameters on the command-line, see `trac-export-wiki --help`
30
+ for a list of options. Specifically, you may want to only regenerate the index
31
+ page, or not generate the index page. This is done with `-i` or `-n` respectively.
32
+
33
+ ## License & Author
34
+
35
+ This library is written by Loren Segal and released under the MIT license.
36
+ See the `LICENSE` file attached with this archive.
@@ -0,0 +1,33 @@
1
+ require 'rbconfig'
2
+
3
+ WINDOWS = (Config::CONFIG['host_os'] =~ /mingw|win32|cygwin/ ? true : false) rescue false
4
+ SUDO = WINDOWS ? '' : 'sudo'
5
+
6
+ task :default => :specs
7
+
8
+ desc "Builds the gem"
9
+ task :gem do
10
+ load 'trac-export-wiki.gemspec'
11
+ Gem::Builder.new(SPEC).build
12
+ end
13
+
14
+ desc "Installs the gem"
15
+ task :install => :gem do
16
+ sh "#{SUDO} gem install trac-export-wiki-1.0.0.gem --no-rdoc --no-ri"
17
+ end
18
+
19
+ begin
20
+ require 'spec'
21
+ require 'spec/rake/spectask'
22
+
23
+ desc "Run all specs"
24
+ Spec::Rake::SpecTask.new("specs") do |t|
25
+ $DEBUG = true if ENV['DEBUG']
26
+ t.spec_opts = ["--format", "specdoc", "--colour"]
27
+ t.spec_opts += ["--require", File.join(File.dirname(__FILE__), 'spec', 'spec_helper')]
28
+ t.spec_files = Dir["spec/**/*_spec.rb"].sort
29
+ end
30
+ task :spec => :specs
31
+ rescue LoadError
32
+ warn "warn: RSpec tests not available. `gem install rspec` to enable them."
33
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path(File.dirname(__FILE__)) + "/../lib/trac-export-wiki"
3
+ TracWiki::CLI.new.run(*ARGV)
@@ -0,0 +1,42 @@
1
+ #username: username_here
2
+ #password: password_here
3
+ base_url: http://example.com/trac/soen490
4
+ pages:
5
+ mgmt:
6
+ - BiWeeklyStatusReport
7
+ - Proposal
8
+ - ActivityPlan
9
+ - RiskManagement
10
+ - ProcessDocumentation
11
+ - ImpactAnalysis
12
+ research:
13
+ - CachingStrategies
14
+ - CachingEvaluation
15
+ - LoadBalancing
16
+ - PlanForDistributedReq
17
+ - ProversBenchmark
18
+ - ProfilingResults
19
+ reqs:
20
+ - VisionDocument
21
+ - SupplementarySpecification
22
+ - InstallationAndCommissioning
23
+ - Glossary
24
+ design:
25
+ - Jml4-LogicalView
26
+ - FirstPrototype
27
+ - Jml4Disco-LogicalView
28
+ - Jml4Disco-PhysicalView
29
+ - Jml4Disco-UseCaseView
30
+ - DevelopmentView
31
+ test:
32
+ - TestPlan
33
+ - BoogieTraceability
34
+ - PerformanceReport
35
+ categories:
36
+ mgmt: 'Management, Planning & Risk Analysis Docs'
37
+ research: 'Research & Potential Strategies Docs'
38
+ reqs: 'Requirements Docs'
39
+ design: 'Design & Architecture'
40
+ test: 'Testing & Implementation'
41
+ wiki_title: JML4 Disco Documentation
42
+ wiki_title_prefix: Disco
@@ -0,0 +1,58 @@
1
+ # The base URL to the trac page (excluding /wiki)
2
+ base_url: http://example.com/trac/myproject
3
+
4
+ # Optional authentication information, uncomment below.
5
+ # You can also specify this information via the command-line (-u/-p).
6
+ #username: username_here
7
+ #password: password_here
8
+
9
+ # The list of pages within separated categories
10
+ # The category should be listed first, followed by a list of pages
11
+ pages:
12
+ # Make sure to include the category short-name first
13
+ mgmt:
14
+ - BiWeeklyStatusReport
15
+ - Proposal
16
+ - ActivityPlan
17
+ - RiskManagement
18
+ - ProcessDocumentation
19
+ - ImpactAnalysis
20
+ research:
21
+ - CachingStrategies
22
+ - CachingEvaluation
23
+ - LoadBalancing
24
+ - PlanForDistributedReq
25
+ - ProversBenchmark
26
+ - ProfilingResults
27
+ reqs:
28
+ - VisionDocument
29
+ - SupplementarySpecification
30
+ - InstallationAndCommissioning
31
+ - Glossary
32
+ design:
33
+ - Jml4-LogicalView
34
+ - FirstPrototype
35
+ - Jml4Disco-LogicalView
36
+ - Jml4Disco-PhysicalView
37
+ - Jml4Disco-UseCaseView
38
+ - DevelopmentView
39
+ test:
40
+ - TestPlan
41
+ - BoogieTraceability
42
+ - PerformanceReport
43
+
44
+ # The full titles and order of the category short-names. These titles will be
45
+ # listed in the order they are given on the index.html page.
46
+ categories:
47
+ mgmt: 'Management, Planning & Risk Analysis Docs'
48
+ research: 'Research & Potential Strategies Docs'
49
+ reqs: 'Requirements Docs'
50
+ design: 'Design & Architecture'
51
+ test: 'Testing & Implementation'
52
+
53
+ # The wiki title listed on the index.html page
54
+ wiki_title: JML4 Disco Documentation
55
+
56
+ # The wiki short title used in the <title> of individual wiki pages
57
+ # in the form: "SHORT_TITLE - WIKI_PAGE_TITLE"
58
+ wiki_title_prefix: Disco
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/ruby
2
+ require 'net/https'
3
+ require 'open-uri'
4
+ require 'hpricot'
5
+ require 'fileutils'
6
+ require 'optparse'
7
+
8
+ module TracWiki
9
+ class HashStruct < Hash
10
+ def self.[](*hash)
11
+ case hash.first
12
+ when Hash
13
+ super(*hash.first.map {|k, v| [k.to_sym, v] }.flatten(1))
14
+ else
15
+ i = 0
16
+ super(*hash.map {|e| e = i % 2 == 0 ? e.to_sym : e; i += 1; e })
17
+ end
18
+ end
19
+
20
+ def []=(key, value)
21
+ super(key.to_sym, value)
22
+ end
23
+
24
+ def method_missing(sym, *args, &block)
25
+ if has_key?(sym.to_sym)
26
+ self[sym.to_sym]
27
+ else
28
+ super
29
+ end
30
+ end
31
+ end
32
+
33
+ DefaultConfiguration = HashStruct[
34
+ :username => nil,
35
+ :password => nil,
36
+ :base_url => nil,
37
+ :destination_path => '.',
38
+ :pages => {},
39
+ :categories => [],
40
+ :wiki_title => "Trac Wiki Pages",
41
+ :wiki_title_prefix => "Wiki",
42
+ :no_index => false,
43
+ :only_index => false,
44
+ ].freeze
45
+
46
+ class CLI
47
+ attr_accessor :config
48
+
49
+ def initialize
50
+ self.config = DefaultConfiguration.dup
51
+ end
52
+
53
+ def run(*args)
54
+ args = args.dup
55
+ opts = OptionParser.new
56
+ opts.banner = "Usage: trac-export-wiki [options] config.yaml"
57
+ opts.on('-u', '--username USERNAME') {|username| config[:username] = username }
58
+ opts.on('-p', '--password PASSWORD') {|password| config[:password] = password }
59
+ opts.on('-b', '--base-url URL') {|url| config[:base_url] = url }
60
+ opts.on('-t', '--wiki-title TITLE') {|title| config[:wiki_title] = title }
61
+ opts.on('-T', '--wiki-title-prefix TITLE') {|title| config[:wiki_title_prefix] = title }
62
+ opts.on('-i', '--only-index') { config[:only_index] = true }
63
+ opts.on('-n', '--no-index') { config[:no_index] = true }
64
+ opts.parse!(args)
65
+ parse_from_yaml(args.first) if args.size > 0
66
+ Exporter.new(config).export
67
+ end
68
+
69
+ private
70
+
71
+ def parse_from_yaml(file)
72
+ require 'yaml'
73
+ config.update HashStruct[YAML.load_file(file)]
74
+ end
75
+ end
76
+
77
+ class Exporter
78
+ # common HTML elements to remove (expressed with css selectors)
79
+ ELEMENTS_TO_REMOVE = ["html > head > link",
80
+ "html > head > style",
81
+ "html > head > script",
82
+ "html > body > script",
83
+ "div#banner",
84
+ "div#header",
85
+ "div#search",
86
+ "div#ctxtnav",
87
+ "div#metanav",
88
+ "div#mainnav",
89
+ "div.buttons",
90
+ "div#altlinks",
91
+ "div#footer",
92
+ "h3#tkt-changes-hdr",
93
+ "ul.tkt-chg-list"]
94
+
95
+ attr_accessor :config
96
+
97
+ def initialize(config = DefaultConfiguration)
98
+ self.config = config
99
+ end
100
+
101
+ def export
102
+ write_pages unless config.only_index
103
+ generate_index unless config.no_index
104
+ end
105
+
106
+ private
107
+
108
+ def write_pages
109
+ config.pages.each do |category, page_names|
110
+ page_names.each do |page|
111
+ print "Exporting \"" + page + "\"... "
112
+ Page.new(page, category).export(config)
113
+ puts "done."
114
+ end
115
+ end
116
+ end
117
+
118
+ def generate_index
119
+ print "Exporting index..."
120
+ index = <<-eof
121
+ <html>
122
+ <head>
123
+ <title>#{config.wiki_title}</title>
124
+ </head>
125
+ <body>
126
+ <h1>#{config.wiki_title}</h1>
127
+ eof
128
+ config.categories.each do |line|
129
+ cat, name = *line
130
+ index += "<h2>#{name}</h2>\n"
131
+ index += "<ul>\n"
132
+ config.pages.select {|k,v| k == cat }.each do |cat, docs|
133
+ docs.each do |doc|
134
+ fname = Page.new(doc, cat).filename
135
+ index += "<li><a href='#{fname}'>#{doc}</a>\n"
136
+ end
137
+ end
138
+ index += "</ul>\n"
139
+ end
140
+ index += <<-eof
141
+ </body>
142
+ </html>
143
+ eof
144
+ File.open('index.html', "w") { |f| f.write(index) }
145
+
146
+ puts "done."
147
+ end
148
+ end
149
+
150
+ class Page
151
+ attr_accessor :page_title, :category, :filename, :config
152
+
153
+ def initialize(page_title, category = nil)
154
+ self.page_title = page_title
155
+ self.category = category
156
+ self.filename = File.join(*[category, page_title.gsub(/([a-z])([A-Z])/,'\1-\2').split(/\?/).first.downcase + '.html'].compact)
157
+ end
158
+
159
+ def export(config)
160
+ self.config = config
161
+
162
+ # load the wiki page
163
+ doc = Hpricot(read_asset(page_title))
164
+
165
+ # search for each element and remove it from the doc
166
+ Exporter::ELEMENTS_TO_REMOVE.each { |e| doc.search(e).remove }
167
+
168
+ # set title
169
+ doc.search("html > head").at("title").inner_html = "#{config.wiki_title_prefix} - " + page_title.gsub(/([a-z])([A-Z])/,'\1 \2')
170
+
171
+ # add link to css
172
+ updir = "../" * category.split(/\//).size
173
+ css = %Q(<link rel="stylesheet" type="text/css" href="#{updir}style.css" />)
174
+ charset = %Q(<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />)
175
+ doc.search("html > head").append(css + charset)
176
+
177
+ # give toc's parent ol a class
178
+ ol = doc.search("html > body > div.wiki-toc > ol").first
179
+ ol.raw_attributes = ol.attributes.to_hash.merge('class' => 'top-most') unless ol.nil?
180
+
181
+ # change the toc's li's class names
182
+ doc.search("html > body > div.wiki-toc > ol").search("li.active").set(:class => 'toc') rescue nil
183
+
184
+ # create category directory if it does not exist
185
+ FileUtils.mkdir_p(File.dirname(filename)) rescue nil
186
+
187
+ # find all images
188
+ doc.search("//img").each do |img|
189
+ imgfile = img.attributes['src']
190
+ short_imgfile = File.basename(imgfile).split(/\?/).first
191
+
192
+ # change image attribute in source
193
+ img.raw_attributes = img.attributes.to_hash.merge("src" => File.join('images', short_imgfile))
194
+
195
+ # make image directory
196
+ outdir = File.join(File.dirname(filename), 'images')
197
+ FileUtils.mkdir_p(outdir)
198
+
199
+ # write image to file
200
+ begin
201
+ uri = URI.parse(config.base_url)
202
+ contents = read_asset(imgfile, "#{uri.scheme}://#{uri.host}")
203
+ File.open(File.join(outdir, short_imgfile), "wb") do |f|
204
+ f.write(contents)
205
+ end
206
+ rescue OpenURI::HTTPError
207
+ end
208
+ end
209
+
210
+ # write HTML to file
211
+ File.open(filename, "w") { |f| f.write(doc.to_html) }
212
+ print "wrote #{filename}... "
213
+ rescue StandardError => bang
214
+ print "(Oops! " + bang.message + ") "
215
+ end
216
+
217
+ private
218
+
219
+ def read_asset(asset, base = nil)
220
+ base ||= File.join(config.base_url, "wiki")
221
+ open(File.join(base, asset), open_options).read
222
+ end
223
+
224
+ def open_options
225
+ @open_options ||= config.username ?
226
+ {:http_basic_authentication => [config.username, config.password]} : {}
227
+ end
228
+ end
229
+ end
230
+
231
+ class Net::HTTP
232
+ alias :old_verify_mode :verify_mode=
233
+ def verify_mode=(x) old_verify_mode(OpenSSL::SSL::VERIFY_NONE) end
234
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trac-export-wiki
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Loren Segal
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-11 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: hpricot
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description: Exports Trac wiki pages as local HTML files
34
+ email: lsegal@soen.ca
35
+ executables:
36
+ - trac-export-wiki
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - bin/trac-export-wiki
43
+ - lib/trac-export-wiki.rb
44
+ - examples/config.yaml
45
+ - examples/config.yaml.sample
46
+ - LICENSE
47
+ - README.md
48
+ - Rakefile
49
+ has_rdoc: yard
50
+ homepage: http://github.com/lsegal/trac-export-wiki
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project: trac-export-wiki
77
+ rubygems_version: 1.3.7
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Exports Trac wiki pages as local HTML files.
81
+ test_files: []
82
+