serif 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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