git-scribe 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.asc +67 -0
- data/bin/git-scribe +6 -0
- data/lib/git-scribe.rb +294 -0
- metadata +70 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2007-2009 Scott Chacon
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.asc
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
Git Scribe
|
2
|
+
==========
|
3
|
+
|
4
|
+
The git-scribe tool is a simple command line toolset to help you use Git, GitHub and Asciidoc
|
5
|
+
to write e-books. This provides tools for setting up the structure, collaborating with co-authors, doing technical and copy-editing, handling translations, taking errata, as well as publishing online, pdf, mobi (Kindle) and epub (iBooks, Nook) versions.
|
6
|
+
|
7
|
+
The project is targeted for writing books of any length, but should also be usable for articles and stuff too, though for a while you'll have to just do it as a really short book.
|
8
|
+
|
9
|
+
Features
|
10
|
+
========
|
11
|
+
|
12
|
+
Eventually, these are the feature goals for the project:
|
13
|
+
|
14
|
+
* Easy: Syntax-Highlighted Code, Formula, Diagrams
|
15
|
+
* Site Generation: Comment, Search, Permalinks
|
16
|
+
* Pegging versions of the book to versions of the tool it documents
|
17
|
+
* Technical and Copy editing workflow tools
|
18
|
+
* Translation workflow tools
|
19
|
+
* Selling (possibly): Kindle, iBooks, Lulu, Pledgie(?)
|
20
|
+
|
21
|
+
The idea is that you use the tool to generate a known structure, write in asciidoc and let the tool handle everything else for you. I want authors to be able to focus on writing and not have to worry about anything else.
|
22
|
+
|
23
|
+
A good AsciiDoc cheat sheet: http://powerman.name/doc/asciidoc#_text
|
24
|
+
|
25
|
+
Disclaimer
|
26
|
+
==========
|
27
|
+
|
28
|
+
This tool is a work in progress. At the 1.0 release, this file will be totally up to date, but for now I may have documented some stuff that doesn't yet work. Contact me personally if you are interested in working on it.
|
29
|
+
|
30
|
+
Installing
|
31
|
+
==========
|
32
|
+
|
33
|
+
You can install git-scribe via RubyGems.
|
34
|
+
|
35
|
+
$ gem install git-scribe
|
36
|
+
|
37
|
+
For local generation (evenutally pushing to GitHub will handle gen for you), it depends on a couple things like:
|
38
|
+
|
39
|
+
* Ruby
|
40
|
+
* asciidoc, a2x
|
41
|
+
* xslt stuff
|
42
|
+
* FOP for PDF gen
|
43
|
+
|
44
|
+
Usage
|
45
|
+
=====
|
46
|
+
|
47
|
+
Initialize a new book with `init` (not yet completed).
|
48
|
+
|
49
|
+
$ git scribe init
|
50
|
+
|
51
|
+
This will set up the outline for your book. All the book content goes into the 'book' subdirectory with 'book.asc' as the starting point. If you want to split the writing up into multiple files you can simply include them in the book.asc file.
|
52
|
+
|
53
|
+
$ git scribe gen [site|html|pdf|epub|mobi|all]
|
54
|
+
|
55
|
+
Roadmap
|
56
|
+
=======
|
57
|
+
|
58
|
+
See the_dream.asc for what this file should look like eventually.
|
59
|
+
|
60
|
+
Contributing
|
61
|
+
============
|
62
|
+
|
63
|
+
If you want to hack on this, fork it, improve it and send me a pull request.
|
64
|
+
|
65
|
+
To get started using it, just clone it and call the ./bin/git-scribe script directly from either the `example` subdir or your own book directory. If you add a feature, make sure it's included in the example subdirectory so I can test it out.
|
66
|
+
|
67
|
+
|
data/bin/git-scribe
ADDED
data/lib/git-scribe.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'liquid'
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
class GitScribe
|
9
|
+
|
10
|
+
SCRIBE_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
11
|
+
|
12
|
+
def initialize(args)
|
13
|
+
@command = args.shift
|
14
|
+
@args = args
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.start(args)
|
18
|
+
GitScribe.new(args).run
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
if @command && self.respond_to?(@command)
|
23
|
+
self.send @command
|
24
|
+
else
|
25
|
+
help
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
## COMMANDS ##
|
30
|
+
|
31
|
+
def help
|
32
|
+
puts "No command: #{@command}"
|
33
|
+
puts "TODO: tons of help"
|
34
|
+
end
|
35
|
+
|
36
|
+
# start a new scribe directory with skeleton structure
|
37
|
+
def init
|
38
|
+
end
|
39
|
+
|
40
|
+
# check that we have everything needed
|
41
|
+
def check
|
42
|
+
# look for a2x (asciidoc, latex, xsltproc)
|
43
|
+
end
|
44
|
+
|
45
|
+
BOOK_FILE = 'book.asc'
|
46
|
+
|
47
|
+
OUTPUT_TYPES = ['pdf', 'epub', 'mobi', 'html', 'site']
|
48
|
+
|
49
|
+
# generate the new media
|
50
|
+
def gen
|
51
|
+
type = @args.shift || 'all'
|
52
|
+
prepare_output_dir
|
53
|
+
|
54
|
+
gather_and_process
|
55
|
+
|
56
|
+
types = type == 'all' ? OUTPUT_TYPES : [type]
|
57
|
+
|
58
|
+
output = []
|
59
|
+
Dir.chdir("output") do
|
60
|
+
types.each do |out_type|
|
61
|
+
call = 'do_' + out_type
|
62
|
+
if self.respond_to? call
|
63
|
+
self.send call
|
64
|
+
else
|
65
|
+
puts "NOT A THING: #{call}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
# clean up
|
69
|
+
# `rm #{BOOK_FILE}`
|
70
|
+
# TODO: open media (?)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def prepare_output_dir
|
75
|
+
Dir.mkdir('output') rescue nil
|
76
|
+
Dir.chdir('output') do
|
77
|
+
Dir.mkdir('stylesheets') rescue nil
|
78
|
+
puts SCRIBE_ROOT
|
79
|
+
from_stdir = File.join(SCRIBE_ROOT, 'stylesheets')
|
80
|
+
pp from_stdir
|
81
|
+
FileUtils.cp_r from_stdir, '.'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def a2x(type)
|
86
|
+
"a2x -f #{type} -d book "
|
87
|
+
end
|
88
|
+
|
89
|
+
def a2x_wss(type)
|
90
|
+
a2x(type) + " --stylesheet=stylesheets/handbookish.css"
|
91
|
+
end
|
92
|
+
|
93
|
+
def do_pdf
|
94
|
+
puts "GENERATING PDF"
|
95
|
+
# TODO: syntax highlighting (fop?)
|
96
|
+
puts `asciidoc -b docbook #{BOOK_FILE}`
|
97
|
+
strparams = {'callout.graphics' => 0,
|
98
|
+
'navig.graphics' => 0,
|
99
|
+
'admon.textlabel' => 1,
|
100
|
+
'admon.graphics' => 0}
|
101
|
+
param = strparams.map { |k, v| "--stringparam #{k} #{v}" }.join(' ')
|
102
|
+
puts cmd = "xsltproc --nonet #{param} --output #{local('book.fo')} #{base('docbook-xsl/fo.xsl')} #{local('book.xml')}"
|
103
|
+
puts `#{cmd}`
|
104
|
+
cmd = "fop -fo #{local('book.fo')} -pdf #{local('book.pdf')}"
|
105
|
+
puts `#{cmd}`
|
106
|
+
#puts `#{a2x('pdf')} -v --fop #{BOOK_FILE}`
|
107
|
+
if $?.exitstatus == 0
|
108
|
+
'book.pdf'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def local(file)
|
113
|
+
File.expand_path(File.join(Dir.pwd, file))
|
114
|
+
end
|
115
|
+
|
116
|
+
def base(file)
|
117
|
+
File.join(SCRIBE_ROOT, file)
|
118
|
+
end
|
119
|
+
|
120
|
+
def do_epub
|
121
|
+
puts "GENERATING EPUB"
|
122
|
+
# TODO: look for custom stylesheets
|
123
|
+
`#{a2x_wss('epub')} -v #{BOOK_FILE}`
|
124
|
+
puts 'exit status', $?.exitstatus
|
125
|
+
'book.epub'
|
126
|
+
end
|
127
|
+
|
128
|
+
def do_html
|
129
|
+
puts "GENERATING HTML"
|
130
|
+
# TODO: look for custom stylesheets
|
131
|
+
#puts `#{a2x_wss('xhtml')} -v #{BOOK_FILE}`
|
132
|
+
styledir = local('stylesheets')
|
133
|
+
puts cmd = "asciidoc -a stylesdir=#{styledir} -a theme=handbookish #{BOOK_FILE}"
|
134
|
+
`#{cmd}`
|
135
|
+
puts 'exit status', $?.exitstatus
|
136
|
+
'book.html'
|
137
|
+
end
|
138
|
+
|
139
|
+
def do_site
|
140
|
+
puts "GENERATING SITE"
|
141
|
+
# TODO: check if html was already done
|
142
|
+
puts `asciidoc -b docbook #{BOOK_FILE}`
|
143
|
+
xsldir = base('docbook-xsl/xhtml')
|
144
|
+
`xsltproc --stringparam html.stylesheet stylesheets/handbookish.css --nonet #{xsldir}/chunk.xsl book.xml`
|
145
|
+
|
146
|
+
source = File.read('index.html')
|
147
|
+
html = Nokogiri::HTML.parse(source, nil, 'utf-8')
|
148
|
+
|
149
|
+
sections = []
|
150
|
+
c = -1
|
151
|
+
|
152
|
+
# each chapter
|
153
|
+
html.css('.toc > dl').each do |section|
|
154
|
+
section.children.each do |item|
|
155
|
+
if item.name == 'dt' # section
|
156
|
+
c += 1
|
157
|
+
sections[c] ||= {'number' => c}
|
158
|
+
link = item.css('a').first
|
159
|
+
sections[c]['title'] = title = link.text
|
160
|
+
sections[c]['href'] = href = link['href']
|
161
|
+
clean_title = title.downcase.gsub(/[^a-z0-9\-_]+/, '_') + '.html'
|
162
|
+
sections[c]['link'] = clean_title
|
163
|
+
if href[0, 10] == 'index.html'
|
164
|
+
sections[c]['link'] = 'title.html'
|
165
|
+
end
|
166
|
+
sections[c]['sub'] = []
|
167
|
+
end
|
168
|
+
if item.name == 'dd' # subsection
|
169
|
+
item.css('dt').each do |sub|
|
170
|
+
link = sub.css('a').first
|
171
|
+
data = {}
|
172
|
+
data['title'] = title = link.text
|
173
|
+
data['href'] = href = link['href']
|
174
|
+
data['link'] = sections[c]['link'] + '#' + href.split('#').last
|
175
|
+
sections[c]['sub'] << data
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
puts
|
180
|
+
end
|
181
|
+
|
182
|
+
pp sections
|
183
|
+
|
184
|
+
book_title = html.css('head > title').text
|
185
|
+
content = html.css('body > div')[1]
|
186
|
+
content.css('.toc').first.remove
|
187
|
+
content = content.inner_html
|
188
|
+
|
189
|
+
puts content
|
190
|
+
sections.each do |s|
|
191
|
+
content.gsub!(s['href'], s['link'])
|
192
|
+
end
|
193
|
+
|
194
|
+
template_dir = File.join(SCRIBE_ROOT, 'site', 'default')
|
195
|
+
|
196
|
+
# copy the template files in
|
197
|
+
files = Dir.glob(template_dir + '/*')
|
198
|
+
FileUtils.cp_r files, '.'
|
199
|
+
|
200
|
+
Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_dir)
|
201
|
+
index_template = Liquid::Template.parse(File.read(File.join(template_dir, 'index.html')))
|
202
|
+
page_template = Liquid::Template.parse(File.read(File.join(template_dir, 'page.html')))
|
203
|
+
|
204
|
+
# write the index page
|
205
|
+
main_data = {
|
206
|
+
'book_title' => book_title,
|
207
|
+
'sections' => sections
|
208
|
+
}
|
209
|
+
File.open('index.html', 'w+') do |f|
|
210
|
+
f.puts index_template.render( main_data )
|
211
|
+
end
|
212
|
+
|
213
|
+
# write the title page
|
214
|
+
File.open('title.html', 'w+') do |f|
|
215
|
+
data = {
|
216
|
+
'title' => sections.first['title'],
|
217
|
+
'sub' => sections.first['sub'],
|
218
|
+
'prev' => {'link' => 'index.html', 'title' => "Main"},
|
219
|
+
'home' => {'link' => 'index.html', 'title' => "Home"},
|
220
|
+
'next' => sections[1],
|
221
|
+
'content' => content
|
222
|
+
}
|
223
|
+
data.merge!(main_data)
|
224
|
+
f.puts page_template.render( data )
|
225
|
+
end
|
226
|
+
|
227
|
+
# write the other pages
|
228
|
+
sections.each_with_index do |section, i|
|
229
|
+
|
230
|
+
if i > 0 # skip title page
|
231
|
+
source = File.read(section['href'])
|
232
|
+
html = Nokogiri::HTML.parse(source, nil, 'utf-8')
|
233
|
+
|
234
|
+
content = html.css('body > div')[1].to_html
|
235
|
+
sections.each do |s|
|
236
|
+
content.gsub!(s['href'], s['link'])
|
237
|
+
end
|
238
|
+
|
239
|
+
File.open(section['link'], 'w+') do |f|
|
240
|
+
next_section = nil
|
241
|
+
if i <= sections.size
|
242
|
+
next_section = sections[i+1]
|
243
|
+
end
|
244
|
+
data = {
|
245
|
+
'title' => section['title'],
|
246
|
+
'sub' => section['sub'],
|
247
|
+
'prev' => sections[i-1],
|
248
|
+
'home' => {'link' => 'index.html', 'title' => "Home"},
|
249
|
+
'next' => next_section,
|
250
|
+
'content' => content
|
251
|
+
}
|
252
|
+
data.merge!(main_data)
|
253
|
+
f.puts page_template.render( data )
|
254
|
+
end
|
255
|
+
#File.unlink(section['href'])
|
256
|
+
|
257
|
+
puts i
|
258
|
+
puts section['title']
|
259
|
+
puts section['href']
|
260
|
+
puts section['link']
|
261
|
+
puts
|
262
|
+
end
|
263
|
+
|
264
|
+
#File.unlink
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
# create a new file by concatenating all the ones we find
|
270
|
+
def gather_and_process
|
271
|
+
files = Dir.glob("book/*")
|
272
|
+
FileUtils.cp_r files, 'output'
|
273
|
+
end
|
274
|
+
|
275
|
+
# DISPLAY HELPER FUNCTIONS #
|
276
|
+
|
277
|
+
def l(info, size)
|
278
|
+
clean(info)[0, size].ljust(size)
|
279
|
+
end
|
280
|
+
|
281
|
+
def r(info, size)
|
282
|
+
clean(info)[0, size].rjust(size)
|
283
|
+
end
|
284
|
+
|
285
|
+
def clean(info)
|
286
|
+
info.to_s.gsub("\n", ' ')
|
287
|
+
end
|
288
|
+
|
289
|
+
# API/DATA HELPER FUNCTIONS #
|
290
|
+
|
291
|
+
def git(command)
|
292
|
+
`git #{command}`.chomp
|
293
|
+
end
|
294
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git-scribe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Scott Chacon
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-15 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: " git-scribe is a workflow tool for starting, writing, reviewing and publishing\n multiple forms of a book. it allows you to use asciidoc plain text markup to\n write, review and translate a work and provides a simple toolkit for generating\n common digital outputs for publishing - epub, mobi, pdf and html. it is also\n integrated into github functionality, letting you automate the publishing and\n collaboration process.\n"
|
23
|
+
email: schacon@gmail.com
|
24
|
+
executables:
|
25
|
+
- git-scribe
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- LICENSE
|
32
|
+
- README.asc
|
33
|
+
- lib/git-scribe.rb
|
34
|
+
- bin/git-scribe
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/schacon/git-scribe
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
hash: 3
|
50
|
+
segments:
|
51
|
+
- 0
|
52
|
+
version: "0"
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.7
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: git-scribe is an authors toolkit for writing and publishing books
|
69
|
+
test_files: []
|
70
|
+
|