diff --git a/bin/jekyll b/bin/jekyll
index 1f3a9c8d..1dacb29b 100755
--- a/bin/jekyll
+++ b/bin/jekyll
@@ -30,6 +30,15 @@ def normalize_options(options)
options
end
+command :new do |c|
+ c.syntax = 'jekyll new PATH'
+ c.description = 'Creates a new Jekyll site scaffold in PATH'
+
+ c.action do |args, options|
+ Jekyll::Commands::New.process(args)
+ end
+end
+
command :build do |c|
c.syntax = 'jekyll build [options]'
c.description = 'Build your site'
diff --git a/jekyll.gemspec b/jekyll.gemspec
index 785c185f..c93639c5 100644
--- a/jekyll.gemspec
+++ b/jekyll.gemspec
@@ -70,6 +70,8 @@ Gem::Specification.new do |s|
lib/jekyll.rb
lib/jekyll/command.rb
lib/jekyll/commands/build.rb
+ lib/jekyll/commands/migrate.rb
+ lib/jekyll/commands/new.rb
lib/jekyll/commands/serve.rb
lib/jekyll/converter.rb
lib/jekyll/converters/identity.rb
@@ -93,6 +95,15 @@ Gem::Specification.new do |s|
lib/jekyll/tags/highlight.rb
lib/jekyll/tags/include.rb
lib/jekyll/tags/post_url.rb
+ lib/site_template/_config.yml
+ lib/site_template/_layouts/default.html
+ lib/site_template/_layouts/post.html
+ lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb
+ lib/site_template/css/screen.css
+ lib/site_template/css/syntax.css
+ lib/site_template/images/.gitkeep
+ lib/site_template/images/rss.png
+ lib/site_template/index.html
script/bootstrap
site/.gitignore
site/CNAME
diff --git a/lib/jekyll/commands/new.rb b/lib/jekyll/commands/new.rb
new file mode 100644
index 00000000..e650dc52
--- /dev/null
+++ b/lib/jekyll/commands/new.rb
@@ -0,0 +1,46 @@
+require 'erb'
+
+module Jekyll
+ module Commands
+ class New < Command
+ def self.process(args)
+ raise ArgumentError.new('You must specify a path.') if args.empty?
+
+ new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
+ FileUtils.mkdir_p new_blog_path
+
+ create_sample_files new_blog_path
+
+ File.open(File.expand_path(self.initialized_post_name, new_blog_path), "w") do |f|
+ f.write(self.scaffold_post_content(site_template))
+ end
+ puts "New jekyll site installed in #{new_blog_path}."
+ end
+
+ def self.scaffold_post_content(template_site)
+ ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
+ end
+
+ # Internal: Gets the filename of the sample post to be created
+ #
+ # Returns the filename of the sample post, as a String
+ def self.initialized_post_name
+ "_posts/#{Time.now.strftime('%Y-%m-%d')}-welcome-to-jekyll.markdown"
+ end
+
+ private
+ def self.create_sample_files(path)
+ FileUtils.cp_r site_template + '/.', path
+ FileUtils.rm File.expand_path(scaffold_path, path)
+ end
+
+ def self.site_template
+ File.expand_path("../../site_template", File.dirname(__FILE__))
+ end
+
+ def self.scaffold_path
+ "_posts/0000-00-00-welcome-to-jekyll.markdown.erb"
+ end
+ end
+ end
+end
diff --git a/lib/site_template/_config.yml b/lib/site_template/_config.yml
new file mode 100644
index 00000000..6d67c09e
--- /dev/null
+++ b/lib/site_template/_config.yml
@@ -0,0 +1,2 @@
+markdown: rdiscount
+pygments: true
diff --git a/lib/site_template/_layouts/default.html b/lib/site_template/_layouts/default.html
new file mode 100644
index 00000000..9fc00095
--- /dev/null
+++ b/lib/site_template/_layouts/default.html
@@ -0,0 +1,38 @@
+
+
+
+
+ {{ page.title }}
+
+
+
+
+
+
+
+
+
+ {{ content }}
+
+
+
+
+
+
diff --git a/lib/site_template/_layouts/post.html b/lib/site_template/_layouts/post.html
new file mode 100644
index 00000000..0b28e6bd
--- /dev/null
+++ b/lib/site_template/_layouts/post.html
@@ -0,0 +1,6 @@
+---
+layout: default
+---
+
+{{ content }}
+
diff --git a/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb b/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb
new file mode 100644
index 00000000..c500b41a
--- /dev/null
+++ b/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb
@@ -0,0 +1,24 @@
+---
+layout: post
+title: "Welcome to Jekyll!"
+date: <%= Time.now.strftime('%Y-%m-%d %H:%M:%S') %>
+categories: jekyll update
+---
+
+You'll find this post in your `_posts` directory - edit this post and re-build (or run with the `-w` switch) to see your changes!
+To add new posts, simply add a file in the `_posts` directory that follows the convention: YYYY-MM-DD-name-of-post.ext.
+
+Jekyll also offers powerful support for code snippets:
+
+{% highlight ruby %}
+def print_hi(name)
+ puts "Hi, #{name}"
+end
+print_hi('Tom')
+#=> prints 'Hi, Tom' to STDOUT.
+{% endhighlight %}
+
+Check out the [Jekyll docs][jekyll] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll's GitHub repo][jekyll-gh].
+
+[jekyll-gh]: https://github.com/mojombo/jekyll
+[jekyll]: http://jekyllrb.com
diff --git a/lib/site_template/css/screen.css b/lib/site_template/css/screen.css
new file mode 100644
index 00000000..7a230ede
--- /dev/null
+++ b/lib/site_template/css/screen.css
@@ -0,0 +1,189 @@
+/*****************************************************************************/
+/*
+/* Common
+/*
+/*****************************************************************************/
+
+/* Global Reset */
+
+* {
+ margin: 0;
+ padding: 0;
+}
+
+html, body {
+ height: 100%;
+}
+
+body {
+ background-color: white;
+ font: 13.34px helvetica, arial, clean, sans-serif;
+ *font-size: small;
+ text-align: center;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-size: 100%;
+}
+
+h1 {
+ margin-bottom: 1em;
+}
+
+p {
+ margin: 1em 0;
+}
+
+a {
+ color: #00a;
+}
+
+a:hover {
+ color: black;
+}
+
+a:visited {
+ color: #a0a;
+}
+
+table {
+ font-size: inherit;
+ font: 100%;
+}
+
+/*****************************************************************************/
+/*
+/* Home
+/*
+/*****************************************************************************/
+
+ul.posts {
+ list-style-type: none;
+ margin-bottom: 2em;
+}
+
+ ul.posts li {
+ line-height: 1.75em;
+ }
+
+ ul.posts span {
+ color: #aaa;
+ font-family: Monaco, "Courier New", monospace;
+ font-size: 80%;
+ }
+
+/*****************************************************************************/
+/*
+/* Site
+/*
+/*****************************************************************************/
+
+.site {
+ font-size: 110%;
+ text-align: justify;
+ width: 42em;
+ margin: 3em auto 2em auto;
+ line-height: 1.5em;
+}
+
+.title {
+ color: #a00;
+ font-weight: bold;
+ margin-bottom: 2em;
+}
+
+ .site .title a {
+ color: #a00;
+ text-decoration: none;
+ }
+
+ .site .title a:hover {
+ color: black;
+ }
+
+ .site .title a.extra {
+ color: #aaa;
+ text-decoration: none;
+ margin-left: 1em;
+ }
+
+ .site .title a.extra:hover {
+ color: black;
+ }
+
+ .site .meta {
+ color: #aaa;
+ }
+
+ .site .footer {
+ font-size: 80%;
+ color: #666;
+ border-top: 4px solid #eee;
+ margin-top: 2em;
+ overflow: hidden;
+ }
+
+ .site .footer .contact {
+ float: left;
+ margin-right: 3em;
+ }
+
+ .site .footer .contact a {
+ color: #8085C1;
+ }
+
+ .site .footer .rss {
+ margin-top: 1.1em;
+ margin-right: -.2em;
+ float: right;
+ }
+
+ .site .footer .rss img {
+ border: 0;
+ }
+
+/*****************************************************************************/
+/*
+/* Posts
+/*
+/*****************************************************************************/
+
+#post {
+
+}
+
+ /* standard */
+
+ #post pre {
+ border: 1px solid #ddd;
+ background-color: #eef;
+ padding: 0 .4em;
+ }
+
+ #post ul,
+ #post ol {
+ margin-left: 1.35em;
+ }
+
+ #post code {
+ border: 1px solid #ddd;
+ background-color: #eef;
+ font-size: 85%;
+ padding: 0 .2em;
+ }
+
+ #post pre code {
+ border: none;
+ }
+
+ /* terminal */
+
+ #post pre.terminal {
+ border: 1px solid black;
+ background-color: #333;
+ color: white;
+ }
+
+ #post pre.terminal code {
+ background-color: #333;
+ }
diff --git a/lib/site_template/css/syntax.css b/lib/site_template/css/syntax.css
new file mode 100644
index 00000000..2774b764
--- /dev/null
+++ b/lib/site_template/css/syntax.css
@@ -0,0 +1,60 @@
+.highlight { background: #ffffff; }
+.highlight .c { color: #999988; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { font-weight: bold } /* Keyword */
+.highlight .o { font-weight: bold } /* Operator */
+.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
+.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #999999 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { font-weight: bold } /* Keyword.Constant */
+.highlight .kd { font-weight: bold } /* Keyword.Declaration */
+.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #009999 } /* Literal.Number */
+.highlight .s { color: #d14 } /* Literal.String */
+.highlight .na { color: #008080 } /* Name.Attribute */
+.highlight .nb { color: #0086B3 } /* Name.Builtin */
+.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
+.highlight .no { color: #008080 } /* Name.Constant */
+.highlight .ni { color: #800080 } /* Name.Entity */
+.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
+.highlight .nn { color: #555555 } /* Name.Namespace */
+.highlight .nt { color: #000080 } /* Name.Tag */
+.highlight .nv { color: #008080 } /* Name.Variable */
+.highlight .ow { font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #009999 } /* Literal.Number.Float */
+.highlight .mh { color: #009999 } /* Literal.Number.Hex */
+.highlight .mi { color: #009999 } /* Literal.Number.Integer */
+.highlight .mo { color: #009999 } /* Literal.Number.Oct */
+.highlight .sb { color: #d14 } /* Literal.String.Backtick */
+.highlight .sc { color: #d14 } /* Literal.String.Char */
+.highlight .sd { color: #d14 } /* Literal.String.Doc */
+.highlight .s2 { color: #d14 } /* Literal.String.Double */
+.highlight .se { color: #d14 } /* Literal.String.Escape */
+.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
+.highlight .si { color: #d14 } /* Literal.String.Interpol */
+.highlight .sx { color: #d14 } /* Literal.String.Other */
+.highlight .sr { color: #009926 } /* Literal.String.Regex */
+.highlight .s1 { color: #d14 } /* Literal.String.Single */
+.highlight .ss { color: #990073 } /* Literal.String.Symbol */
+.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #008080 } /* Name.Variable.Class */
+.highlight .vg { color: #008080 } /* Name.Variable.Global */
+.highlight .vi { color: #008080 } /* Name.Variable.Instance */
+.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
diff --git a/lib/site_template/images/.gitkeep b/lib/site_template/images/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/lib/site_template/images/rss.png b/lib/site_template/images/rss.png
new file mode 100644
index 00000000..d6ecb16f
Binary files /dev/null and b/lib/site_template/images/rss.png differ
diff --git a/lib/site_template/index.html b/lib/site_template/index.html
new file mode 100644
index 00000000..c7268192
--- /dev/null
+++ b/lib/site_template/index.html
@@ -0,0 +1,13 @@
+---
+layout: default
+title: Your New Jekyll Site
+---
+
+
+
Blog Posts
+
+ {% for post in site.posts %}
+ {{ post.date | date_to_string }} » {{ post.title }}
+ {% endfor %}
+
+
\ No newline at end of file
diff --git a/test/test_new_command.rb b/test/test_new_command.rb
new file mode 100644
index 00000000..bc9e6585
--- /dev/null
+++ b/test/test_new_command.rb
@@ -0,0 +1,104 @@
+require 'helper'
+require 'jekyll/commands/new'
+
+class TestNewCommand < Test::Unit::TestCase
+ def dir_contents(path)
+ Dir["#{path}/**/*"].each do |file|
+ file.gsub! path, ''
+ end
+ end
+
+ def site_template
+ File.expand_path("../lib/site_template", File.dirname(__FILE__))
+ end
+
+ context 'when args contains a path' do
+ setup do
+ @path = 'new-site'
+ @args = [@path]
+ @full_path = File.expand_path(@path, Dir.pwd)
+ end
+
+ teardown do
+ FileUtils.rm_r @full_path
+ end
+
+ should 'create a new directory' do
+ assert !File.exists?(@full_path)
+ capture_stdout { Jekyll::Commands::New.process(@args) }
+ assert File.exists?(@full_path)
+ end
+
+ should 'display a success message' do
+ output = capture_stdout { Jekyll::Commands::New.process(@args) }
+ success_message = "New jekyll site installed in #{@full_path}.\n"
+ assert_equal success_message, output
+ end
+
+ should 'copy the static files in site template to the new directory' do
+ static_template_files = dir_contents(site_template).reject do |f|
+ File.extname(f) == '.erb'
+ end
+
+ capture_stdout { Jekyll::Commands::New.process(@args) }
+
+ new_site_files = dir_contents(@full_path).reject do |f|
+ File.extname(f) == '.markdown'
+ end
+
+ assert_same_elements static_template_files, new_site_files
+ end
+
+ should 'process any ERB files' do
+ erb_template_files = dir_contents(site_template).select do |f|
+ File.extname(f) == '.erb'
+ end
+
+ stubbed_date = '2013-01-01'
+ stub.instance_of(Time).strftime { stubbed_date }
+
+ erb_template_files.each do |f|
+ f.chomp! '.erb'
+ f.gsub! '0000-00-00', stubbed_date
+ end
+
+ capture_stdout { Jekyll::Commands::New.process(@args) }
+
+ new_site_files = dir_contents(@full_path).select do |f|
+ erb_template_files.include? f
+ end
+
+ assert_same_elements erb_template_files, new_site_files
+ end
+ end
+
+ context 'when multiple args are given' do
+ setup do
+ @site_name_with_spaces = 'new site name'
+ @multiple_args = @site_name_with_spaces.split
+ end
+
+ teardown do
+ FileUtils.rm_r File.expand_path(@site_name_with_spaces, Dir.pwd)
+ end
+
+ should 'create a new directory' do
+ assert !File.exists?(@site_name_with_spaces)
+ capture_stdout { Jekyll::Commands::New.process(@multiple_args) }
+ assert File.exists?(@site_name_with_spaces)
+ end
+ end
+
+ context 'when no args are given' do
+ setup do
+ @empty_args = []
+ end
+
+ should 'raise an ArgumentError' do
+ exception = assert_raise ArgumentError do
+ Jekyll::Commands::New.process(@empty_args)
+ end
+ assert_equal 'You must specify a path.', exception.message
+ end
+ end
+end