serif 0.4 → 0.5

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.
Files changed (50) hide show
  1. data/Gemfile.lock +29 -14
  2. data/README.md +28 -14
  3. data/bin/serif +2 -69
  4. data/lib/serif.rb +1 -0
  5. data/lib/serif/admin_server.rb +55 -26
  6. data/lib/serif/commands.rb +150 -0
  7. data/lib/serif/content_file.rb +4 -0
  8. data/lib/serif/draft.rb +24 -2
  9. data/lib/serif/errors.rb +10 -0
  10. data/lib/serif/post.rb +4 -3
  11. data/lib/serif/site.rb +73 -4
  12. data/rakefile +10 -0
  13. data/serif.gemspec +5 -3
  14. data/statics/skeleton/_layouts/default.html +1 -1
  15. data/statics/templates/admin/bookmarks.liquid +17 -13
  16. data/statics/templates/admin/edit_draft.liquid +1 -1
  17. data/statics/templates/admin/edit_post.liquid +1 -1
  18. data/statics/templates/admin/index.liquid +2 -2
  19. data/statics/templates/admin/layout.liquid +16 -0
  20. data/test/commands_spec.rb +77 -0
  21. data/test/content_file_spec.rb +32 -1
  22. data/test/draft_spec.rb +50 -3
  23. data/test/post_spec.rb +31 -2
  24. data/test/site_dir/_layouts/default.html +2 -0
  25. data/test/site_dir/_site/archive.html +2 -0
  26. data/test/site_dir/_site/drafts/another-sample-draft/{481da12b79709bfa0547fa9b5754c9506fbed29afd0334e07a8c95e76850.html → add25848a94509103cb492c47e3a04b7b2a56299de207155fbffec42dc4b.html} +5 -2
  27. data/test/site_dir/_site/drafts/sample-draft/{a986a62ad5f6edd1fcac3d08f5b461b92bcb667a2af69505230c291d405c.html → 0b6fc164b8534d5d5a9fcfc5c709265d33f1577cd0fe2f4e23042e92f0c1.html} +5 -2
  28. data/test/site_dir/_site/index.html +2 -0
  29. data/test/site_dir/_site/page-header-but-no-layout.html +2 -0
  30. data/test/site_dir/_site/test-archive/2012/11.html +2 -0
  31. data/test/site_dir/_site/test-archive/2012/12.html +2 -0
  32. data/test/site_dir/_site/test-archive/2013/01.html +2 -0
  33. data/test/site_dir/_site/test-archive/2013/03.html +2 -0
  34. data/test/site_dir/_site/test-archive/2399/01.html +2 -0
  35. data/test/site_dir/_site/test-archive/2400/01.html +2 -0
  36. data/test/site_dir/_site/test-blog/final-post.html +4 -1
  37. data/test/site_dir/_site/test-blog/penultimate-post.html +4 -1
  38. data/test/site_dir/_site/test-blog/post-to-be-published-on-generate.html +4 -1
  39. data/test/site_dir/_site/test-blog/post-with-custom-layout.html +1 -0
  40. data/test/site_dir/_site/test-blog/sample-post.html +4 -1
  41. data/test/site_dir/_site/test-blog/second-post.html +4 -1
  42. data/test/site_dir/_site/test-smarty-filter.html +2 -0
  43. data/test/site_dir/_templates/post.html +1 -0
  44. data/test/site_dir/_trash/1364747613-autopublish-draft +5 -0
  45. data/test/site_dir/_trash/{1363633154-test-draft → 1364747613-test-draft} +1 -1
  46. data/test/site_generation_spec.rb +40 -9
  47. data/test/site_spec.rb +63 -0
  48. data/test/test_helper.rb +9 -0
  49. metadata +46 -10
  50. data/test/site_dir/_trash/1363633154-autopublish-draft +0 -5
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- serif (0.3.3)
4
+ serif (0.4)
5
5
  liquid (~> 2.4)
6
6
  nokogiri (~> 1.5)
7
7
  rack (~> 1.0)
@@ -15,37 +15,50 @@ PATH
15
15
  GEM
16
16
  remote: http://rubygems.org/
17
17
  specs:
18
- diff-lcs (1.1.3)
18
+ colorize (0.5.8)
19
+ coveralls (0.6.3)
20
+ colorize
21
+ multi_json (~> 1.3)
22
+ rest-client
23
+ simplecov (>= 0.7)
24
+ thor
25
+ diff-lcs (1.2.2)
26
+ json (1.7.7)
19
27
  liquid (2.5.0)
20
- multi_json (1.6.1)
21
- nokogiri (1.5.6)
28
+ mime-types (1.22)
29
+ multi_json (1.7.2)
30
+ nokogiri (1.5.9)
22
31
  rack (1.5.2)
23
32
  rack-protection (1.5.0)
24
33
  rack
25
34
  rake (0.9.6)
35
+ rdoc (4.0.1)
36
+ json (~> 1.4)
26
37
  redcarpet (2.2.2)
27
38
  redhead (0.0.8)
39
+ rest-client (1.6.7)
40
+ mime-types (>= 1.16)
28
41
  reverse_markdown (0.4.4)
29
42
  nokogiri
30
43
  rouge (0.3.2)
31
44
  thor
32
- rspec (2.12.0)
33
- rspec-core (~> 2.12.0)
34
- rspec-expectations (~> 2.12.0)
35
- rspec-mocks (~> 2.12.0)
36
- rspec-core (2.12.2)
37
- rspec-expectations (2.12.1)
38
- diff-lcs (~> 1.1.3)
39
- rspec-mocks (2.12.2)
45
+ rspec (2.13.0)
46
+ rspec-core (~> 2.13.0)
47
+ rspec-expectations (~> 2.13.0)
48
+ rspec-mocks (~> 2.13.0)
49
+ rspec-core (2.13.1)
50
+ rspec-expectations (2.13.0)
51
+ diff-lcs (>= 1.1.3, < 2.0)
52
+ rspec-mocks (2.13.0)
40
53
  simplecov (0.7.1)
41
54
  multi_json (~> 1.0)
42
55
  simplecov-html (~> 0.7.1)
43
56
  simplecov-html (0.7.1)
44
- sinatra (1.4.1)
57
+ sinatra (1.4.2)
45
58
  rack (~> 1.5, >= 1.5.2)
46
59
  rack-protection (~> 1.4)
47
60
  tilt (~> 1.3, >= 1.3.4)
48
- thor (0.17.0)
61
+ thor (0.18.1)
49
62
  tilt (1.3.6)
50
63
  timecop (0.6.1)
51
64
  timeout_cache (0.0.2)
@@ -54,7 +67,9 @@ PLATFORMS
54
67
  ruby
55
68
 
56
69
  DEPENDENCIES
70
+ coveralls
57
71
  rake (~> 0.9)
72
+ rdoc (~> 4.0.0)
58
73
  rspec (~> 2.5)
59
74
  serif!
60
75
  simplecov (~> 0.7)
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # Serif
2
2
 
3
- [![Build Status](https://travis-ci.org/aprescott/serif.png?branch=master)](https://travis-ci.org/aprescott/serif)
3
+ [![Build Status](https://travis-ci.org/aprescott/serif.png?branch=master)](https://travis-ci.org/aprescott/serif) [![Code Climate](https://codeclimate.com/github/aprescott/serif.png)](https://codeclimate.com/github/aprescott/serif) [![Coverage Status](https://coveralls.io/repos/aprescott/serif/badge.png?branch=master)](https://coveralls.io/r/aprescott/serif)
4
4
 
5
- Serif is a file-based blogging engine intended for simple sites. It compiles Markdown content to static files, and there is a web interface for editing and publishing ([simple video demo](https://docs.google.com/open?id=0BxPQpxGSOOyKS1J4MmlnM3JIaXM)), because managing everything with `ssh` and `git` can be a pain, compared to having a more universally accessible editing interface.
5
+ Serif is a static site generator and blogging system powered by markdown files and an optional admin interface complete with drag-and-drop image uploading. ([Check out the simple video demo](https://docs.google.com/open?id=0BxPQpxGSOOyKS1J4MmlnM3JIaXM).)
6
6
 
7
- Having problems with Serif? [Open an issue on GitHub](https://github.com/aprescott/serif/issues), or use the [Serif Google Group](https://groups.google.com/forum/#!forum/serif-rb)
7
+ Serif releases you from managing a file system so you can focus on writing content.
8
+
9
+ Having problems with Serif? [Open an issue on GitHub](https://github.com/aprescott/serif/issues), use the [Serif Google Group](https://groups.google.com/forum/#!forum/serif-rb), or [join the Freenode#serif IRC channel](irc://irc.freenode.net/serif).
8
10
 
9
11
  ## First time use
10
12
 
@@ -177,9 +179,24 @@ Something something.
177
179
  End of the post
178
180
  ```
179
181
 
182
+ ### Headers
183
+
180
184
  The headers are similar to Jekyll's YAML front matter, but here there are no formatting requirements beyond `Key: value` pairs. Header names are case-insensitive (so `title` is the same as `Title`), but values are not.
181
185
 
182
- (The headers `created` and `updated` must be a string that Ruby's standard Time library can parse, but this will mostly be handled for you.)
186
+ File headers like `Title: Some title` can contain any header, but certain headers have special meaning in Serif.
187
+
188
+ Header name | Meaning
189
+ ----------- |:-------
190
+ `Created` | For a post, timestamp for when it was first published. Must be a string that Ruby's `Time` class can parse. Means nothing for drafts.
191
+ `Updated` | For a post, timestamp for when it was last updated. Must be a string that Ruby's `Time` class can parse. Means nothing for drafts.
192
+ `Title` | Title for the draft or post.
193
+ `Update` | For a post, When given the value of `now` (i.e., `Update: now`), the `Updated` timestamp will be updated on the next site generation. Means nothing for drafts.
194
+ `Publish` | For a draft, when given the value of `now` (i.e., `Publish: now`), the draft will be published on the next site generation (and the `Created` set appropriately). Means nothing for a post.
195
+ `Permalink` | For a post, overrides the default permalink value defined in `_config.yml`. **Note that this is interpolated**, so `:title` in the permalink value will be replaced according to regular permalink rules. Means nothing for a draft.
196
+
197
+ Note that while it is possible for you to manually handle timestamp values, it is recommended that you rely on using the value of `now` for `Update` and `Publish`.
198
+
199
+ If you change the `permalink` value for a published post, you will break any inbound URLs as well as, e.g., any feeds that rely on the URL as a unique persistent ID.
183
200
 
184
201
  ## `_templates`
185
202
 
@@ -217,6 +234,8 @@ Placeholder | Value
217
234
  `:month` | Month as given in the filename, e.g., "01"
218
235
  `:day` | Day as given in the filename, e.g., "28"
219
236
 
237
+ <b>NOTE</b>: if you change the permalink value, you will break existing URLs for published posts, in addition to, e.g., any feed ID values that depend on the post URL never changing.
238
+
220
239
  ### Admin drag-and-drop upload path
221
240
 
222
241
  The `image_upload_path` configuration setting is an _absolute path_ and will be relative to the base directory of your site, used in the admin interface to control where files are sent. The default value is `/images/:timestamp_:name`. Similar to permalinks, the following placeholders are available:
@@ -283,7 +302,7 @@ On the next site generation (`serif generate`) this draft will be automatically
283
302
 
284
303
  # Updating posts
285
304
 
286
- When you update a draft, you need to remember to change the updated time. As luck would have it, Serif takes care of timestamps for you! Just use a header of `update: now` at the top of your post:
305
+ When you update a post, you need to remember to change the updated time. As luck would have it, Serif takes care of timestamps for you! Just use a header of `update: now` at the top of your published post after making your changes:
287
306
 
288
307
  ```
289
308
  title: My blog post
@@ -470,6 +489,7 @@ These should be available in any template:
470
489
  * `{{ site.latest_update_time }}` --- a [Ruby `Time`](http://ruby-doc.org/core/Time.html) instance for the latest time that any post was updated. Useful for RSS/Atom feeds.
471
490
  * `{{ site.archives }}` --- a nested hash structure that groups posts by month. See above for how to use it.
472
491
  * `{{ draft_preview }}` -- Set to true if this is part of generating a draft preview.
492
+ * `{{ post_page }}` -- Set to true if this is part of generating a regular published post.
473
493
 
474
494
  ## Post variables
475
495
 
@@ -483,6 +503,7 @@ Name | Value
483
503
  `post.created` | A [Ruby `Time`](http://ruby-doc.org/core/Time.html) instance for the time the post was first published.
484
504
  `post.updated` | A [Ruby `Time`](http://ruby-doc.org/core/Time.html) instance for the time the post was last updated.
485
505
  `post.content` | The raw post content. Example use: `{{ post.content | markdown }}`.
506
+ `post.foo` | The value of the `Foo` header, e.g., if `Foo: my special header` is in the source file, `post.foo` is `my special header`. All headers are merged into the `{{ post }}` variable for you to use in templates.
486
507
 
487
508
  ## Variables available within post templates
488
509
 
@@ -511,6 +532,7 @@ Variable | Value
511
532
  * `./bin/serif {dev,admin,generate}` to run Serif commands.
512
533
  * `rake test` to run the tests.
513
534
  * Unit tests are written in RSpec.
535
+ * `rake docs` will generate HTML documentation in `docs/`. Open `docs/index.html` in a browser to start.
514
536
 
515
537
  ## Directory structure
516
538
 
@@ -519,15 +541,7 @@ Variable | Value
519
541
 
520
542
  # Changes and what's new
521
543
 
522
- ## Latest release (v0.4)
523
-
524
- ## v0.3.3
525
-
526
- * Allow drag-and-drop to work on posts as well as drafts. (9ea3bebf)
527
- * `serif new` no longer creates a sample published post (#37) and generates immediately. (#39)
528
- * Pygments.rb is replaced with Rouge for code highlighting. (#34)
529
-
530
- See `CHANGELOG` for more.
544
+ See `CHANGELOG`.
531
545
 
532
546
  # Planned features
533
547
 
data/bin/serif CHANGED
@@ -2,73 +2,6 @@
2
2
 
3
3
  $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
4
4
 
5
- require "fileutils"
5
+ require "serif/commands"
6
6
 
7
- def initialize_admin_server(source_dir)
8
- # need to cd to the directory before requiring the admin
9
- # server, because otherwise Dir.pwd won't be right when
10
- # the admin server class is defined at require time.
11
- FileUtils.cd(source_dir)
12
- require "serif"
13
- require "serif/admin_server"
14
-
15
- server = Serif::AdminServer.new(source_dir)
16
- server.start
17
- end
18
-
19
- def initialize_dev_server(source_dir)
20
- FileUtils.cd(source_dir)
21
- require "serif"
22
- require "serif/server"
23
-
24
- server = Serif::DevelopmentServer.new(source_dir)
25
- server.start
26
- end
27
-
28
- def generate_site(source_dir)
29
- require "serif"
30
-
31
- site = Serif::Site.new(source_dir)
32
- site.generate
33
- end
34
-
35
- def verify_directory(dir)
36
- unless Dir.exist?(dir)
37
- puts "No such directory: #{dir}'"
38
- exit 1
39
- end
40
- end
41
-
42
- def produce_skeleton(dir)
43
- if !Dir[File.join(dir, "*")].empty?
44
- abort "Directory is not empty."
45
- end
46
-
47
- FileUtils.cd(File.join(File.dirname(__FILE__), "..", "statics", "skeleton"))
48
- files = Dir["*"]
49
- files.each do |f|
50
- FileUtils.cp_r(f, dir, verbose: true)
51
- end
52
-
53
- generate_site(dir)
54
-
55
- puts
56
- puts "*** NOTE ***"
57
- puts
58
- puts "You should now edit the username and password in _config.yml"
59
- puts
60
- end
61
-
62
- command = ARGV.shift
63
- args = ARGV
64
-
65
- case command
66
- when "admin"
67
- initialize_admin_server(Dir.pwd)
68
- when "generate"
69
- generate_site(Dir.pwd)
70
- when "dev"
71
- initialize_dev_server(Dir.pwd)
72
- when "new"
73
- produce_skeleton(Dir.pwd)
74
- end
7
+ Serif::Commands.new(ARGV).process
@@ -11,6 +11,7 @@ require "digest"
11
11
 
12
12
  require "securerandom"
13
13
 
14
+ require "serif/errors"
14
15
  require "serif/content_file"
15
16
  require "serif/post"
16
17
  require "serif/draft"
@@ -19,6 +19,10 @@ class AdminServer
19
19
  [username, password] == [site.config.admin_username, site.config.admin_password]
20
20
  end
21
21
 
22
+ before do
23
+ @conflicts = site.conflicts
24
+ end
25
+
22
26
  # multiple public folders??
23
27
  get "/admin/js/:file" do |file|
24
28
  assets_dir = File.join(File.dirname(__FILE__), "..", "..", "statics", "assets", "js")
@@ -34,7 +38,7 @@ class AdminServer
34
38
  posts = site.posts.sort_by { |p| p.created }.reverse
35
39
  drafts = site.drafts.sort_by { |p| File.mtime(p.path) }.reverse
36
40
 
37
- liquid :index, locals: { posts: posts, drafts: drafts }
41
+ liquid :index, locals: { conflicts: @conflicts, posts: posts, drafts: drafts }
38
42
  end
39
43
 
40
44
  get "/admin/edit/?" do
@@ -42,7 +46,7 @@ class AdminServer
42
46
  end
43
47
 
44
48
  get "/admin/bookmarks" do
45
- liquid :bookmarks, locals: { base_url: request.base_url }
49
+ liquid :bookmarks, locals: { conflicts: @conflicts }
46
50
  end
47
51
 
48
52
  get "/admin/quick-draft" do
@@ -76,21 +80,36 @@ class AdminServer
76
80
  draft = Draft.new(site)
77
81
  draft.title = title
78
82
  draft.slug = slug
79
- draft.save(markdown)
80
83
 
81
- site.generate
82
-
83
- if params[:edit] == "1"
84
- redirect to("/admin/edit/drafts/#{slug}")
84
+ # if the draft itself has no conflict, save it,
85
+ # otherwise show the new draft page with an error.
86
+ #
87
+ # if, after saving the draft because of no conflict,
88
+ # there is actually an overall site conflict, then
89
+ # keep on trucking so it doesn't interrupt the user.
90
+ if site.conflicts(draft)
91
+ liquid :new_draft, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), post: draft, error_message: "There is a conflict on this draft." }
85
92
  else
86
- redirect to(url)
93
+ draft.save(markdown)
94
+
95
+ begin
96
+ site.generate
97
+ rescue PostConflictError => e
98
+ puts "Site has conflicts, skipping generation for now."
99
+ end
100
+
101
+ if params[:edit] == "1"
102
+ redirect to("/admin/edit/drafts/#{slug}")
103
+ else
104
+ redirect to(url)
105
+ end
87
106
  end
88
107
  end
89
108
 
90
109
  get "/admin/new/draft" do
91
110
  content = Draft.new(site)
92
111
  autofocus = "slug"
93
- liquid :new_draft, locals: { images_path: site.config.image_upload_path.gsub(/"/, '\"'), post: content, autofocus: autofocus }
112
+ liquid :new_draft, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), post: content, autofocus: autofocus }
94
113
  end
95
114
 
96
115
  post "/admin/new/draft" do
@@ -109,13 +128,18 @@ class AdminServer
109
128
  autofocus = "title" unless params[:title]
110
129
  autofocus = "slug" unless params[:slug]
111
130
 
112
- liquid :new_draft, locals: { images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content, autofocus: autofocus }
131
+ liquid :new_draft, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content, autofocus: autofocus }
113
132
  else
114
133
  if Draft.exist?(site, params[:slug])
115
- liquid :new_draft, locals: { images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content, autofocus: autofocus }
134
+ error_message = "Draft already eixsts with the given slug #{params[:slug]}."
135
+ liquid :new_draft, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content, autofocus: autofocus }
116
136
  else
117
137
  content.save(params[:markdown])
118
- site.generate
138
+ begin
139
+ site.generate
140
+ rescue PostConflictError => e
141
+ puts "Cannot generate. Skipping for now."
142
+ end
119
143
  redirect to("/admin")
120
144
  end
121
145
  end
@@ -155,7 +179,10 @@ class AdminServer
155
179
  error_message = "You must pick a URL to use"
156
180
  end
157
181
 
158
- liquid :edit_draft, locals: { images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content, private_url: site.private_url(content) }
182
+ liquid :edit_draft, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content, private_url: site.private_url(content) }
183
+ elsif (conflicts = site.conflicts)
184
+ error_message = "The site has a conflict and cannot be generated."
185
+ liquid :edit_draft, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content, private_url: site.private_url(content) }
159
186
  else
160
187
  content.save(params[:markdown])
161
188
 
@@ -172,7 +199,7 @@ class AdminServer
172
199
  end
173
200
 
174
201
  post "/admin/edit/posts" do
175
- content = Post.from_slug(site, params[:original_slug])
202
+ content = Post.from_basename(site, params[:original_basename])
176
203
 
177
204
  params[:markdown] = params[:markdown].strip
178
205
  params[:title] = params[:title].strip
@@ -183,7 +210,10 @@ class AdminServer
183
210
  error_message = "Content must not be blank." if params[:markdown].empty?
184
211
  error_message = "Title must not be blank." if params[:title].empty?
185
212
 
186
- liquid :edit_post, locals: { images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content }
213
+ liquid :edit_post, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content }
214
+ elsif (conflicts = site.conflicts)
215
+ error_message = "The site has a conflict and cannot be generated."
216
+ liquid :edit_post, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), error_message: error_message, post: content }
187
217
  else
188
218
  content.save(params[:markdown])
189
219
  site.generate
@@ -192,19 +222,18 @@ class AdminServer
192
222
  end
193
223
  end
194
224
 
195
- get "/admin/edit/:type/:slug" do
225
+ get "/admin/edit/posts/:basename" do
226
+ redirect to("/admin") unless params[:basename]
227
+
228
+ content = Post.from_basename(site, params[:basename])
229
+ liquid :edit_post, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), post: content, autofocus: "markdown" }
230
+ end
231
+
232
+ get "/admin/edit/drafts/:slug" do
196
233
  redirect to("/admin") unless params[:slug]
197
234
 
198
- if params[:type] == "posts"
199
- content = site.posts.find { |p| p.slug == params[:slug] }
200
- liquid :edit_post, locals: { images_path: site.config.image_upload_path.gsub(/"/, '\"'), post: content, autofocus: "markdown" }
201
- elsif params[:type] == "drafts"
202
- content = Draft.from_slug(site, params[:slug])
203
- liquid :edit_draft, locals: { images_path: site.config.image_upload_path.gsub(/"/, '\"'), post: content, autofocus: "markdown", private_url: site.private_url(content) }
204
- else
205
- response.status = 404
206
- return "Nope"
207
- end
235
+ content = Draft.from_slug(site, params[:slug])
236
+ liquid :edit_draft, locals: { conflicts: @conflicts, images_path: site.config.image_upload_path.gsub(/"/, '\"'), post: content, autofocus: "markdown", private_url: site.private_url(content) }
208
237
  end
209
238
 
210
239
  post "/admin/delete/?" do
@@ -0,0 +1,150 @@
1
+ require "fileutils"
2
+ require "serif"
3
+ require "serif/server"
4
+
5
+ module Serif
6
+ class Commands
7
+ def initialize(argv)
8
+ @argv = argv.dup
9
+ end
10
+
11
+ def process
12
+ command = @argv.shift
13
+ case command
14
+ when "-h", "--help", nil
15
+ print_help
16
+ exit 0
17
+ when "admin"
18
+ initialize_admin_server(Dir.pwd)
19
+ when "generate"
20
+ generate_site(Dir.pwd)
21
+ when "dev"
22
+ initialize_dev_server(Dir.pwd)
23
+ when "new"
24
+ produce_skeleton(Dir.pwd)
25
+ end
26
+ end
27
+
28
+ def initialize_admin_server(source_dir)
29
+ # need to cd to the directory before requiring the admin
30
+ # server, because otherwise Dir.pwd won't be right when
31
+ # the admin server class is defined at require time.
32
+ FileUtils.cd(source_dir)
33
+ require "serif/admin_server"
34
+
35
+ server = Serif::AdminServer.new(source_dir)
36
+ server.start
37
+ end
38
+
39
+ def initialize_dev_server(source_dir)
40
+ FileUtils.cd(source_dir)
41
+
42
+ server = Serif::DevelopmentServer.new(source_dir)
43
+ server.start
44
+ end
45
+
46
+ def generate_site(source_dir)
47
+
48
+ site = Serif::Site.new(source_dir)
49
+
50
+ begin
51
+ site.generate
52
+ rescue Serif::PostConflictError => e
53
+ puts "Error! Unable to generate because there is a conflict."
54
+ puts
55
+ puts "Conflicts at:"
56
+ puts
57
+
58
+ site.conflicts.each do |url, ary|
59
+ puts url
60
+ ary.each do |e|
61
+ puts "\t#{e.path}"
62
+ end
63
+ end
64
+
65
+ exit 1
66
+ end
67
+ end
68
+
69
+ def verify_directory(dir)
70
+ unless Dir.exist?(dir)
71
+ puts "No such directory: #{dir}'"
72
+ exit 1
73
+ end
74
+ end
75
+
76
+ def produce_skeleton(dir)
77
+ if !Dir[File.join(dir, "*")].empty?
78
+ abort "Directory is not empty."
79
+ end
80
+
81
+ FileUtils.cd(File.join(File.dirname(__FILE__), "..", "..", "statics", "skeleton"))
82
+ files = Dir["*"]
83
+ files.each do |f|
84
+ FileUtils.cp_r(f, dir, verbose: true)
85
+ end
86
+
87
+ generate_site(dir)
88
+
89
+ puts
90
+ puts "*** NOTE ***"
91
+ puts
92
+ puts "You should now edit the username and password in _config.yml"
93
+ puts
94
+ end
95
+
96
+ def print_help
97
+ puts <<-END_HELP
98
+ USAGE
99
+
100
+ serif [-h | --help]
101
+ serif [COMMAND]
102
+
103
+ OPTIONS
104
+
105
+ -h, --help Display this help message and exit immediately.
106
+
107
+ COMMANDS
108
+
109
+ serif generate Generate the site in the current directory.
110
+
111
+ serif new Create a site skeleton to get started. Will
112
+ only run if the current directory is empty.
113
+
114
+ serif admin Start the admin server on localhost:4567.
115
+
116
+ serif dev Start a simple dev server on localhost:8000.
117
+ Serves up the generated static files, but loads
118
+ some files (like CSS) from source (instead of
119
+ out of the _site/ directory).
120
+
121
+ ENVIRONMENT VARIABLES
122
+
123
+ ENV Set to 'production' if the command is being run
124
+ as part of serving up a live site.
125
+
126
+ $ ENV=production serif generate
127
+
128
+ $ ENV=production serif admin
129
+
130
+ Note that this by and large doesn't change much,
131
+ but in future it may provide extra features.
132
+
133
+ The main benefit is that the `file_digest` tag
134
+ will return a hex digest of the given file's
135
+ contents only when ENV is set to production.
136
+
137
+ EXAMPLES
138
+
139
+ $ serif generate
140
+
141
+ Generate the site.
142
+
143
+ $ serif admin
144
+
145
+ Start the admin server on localhost:4567.
146
+
147
+ END_HELP
148
+ end
149
+ end
150
+ end