Merge branch 'master' of git://github.com/plusjade/jekyll-bootstrap
[GalaxyBlog.git] / Rakefile
blobf3911bfbf4474cf4c3df5d9034b22059e477dd89
1 require "rubygems"
2 require 'rake'
3 require 'yaml'
4 require 'time'
6 SOURCE = "."
7 CONFIG = {
8   'version' => "0.3.1",
9   'themes' => File.join(SOURCE, "_includes", "themes"),
10   'layouts' => File.join(SOURCE, "_layouts"),
11   'posts' => File.join(SOURCE, "_posts"),
12   'post_ext' => "md",
13   'theme_package_version' => "0.1.0"
16 # Path configuration helper
17 module JB
18   class Path
19     SOURCE = "."
20     Paths = {
21       :layouts => "_layouts",
22       :themes => "_includes/themes",
23       :theme_assets => "assets/themes",
24       :theme_packages => "_theme_packages",
25       :posts => "_posts"
26     }
27     
28     def self.base
29       SOURCE
30     end
32     # build a path relative to configured path settings.
33     def self.build(path, opts = {})
34       opts[:root] ||= SOURCE
35       path = "#{opts[:root]}/#{Paths[path.to_sym]}/#{opts[:node]}".split("/")
36       path.compact!
37       File.__send__ :join, path
38     end
39   
40   end #Path
41 end #JB
43 # Usage: rake post title="A Title" [date="2012-02-09"] [tags=[tag1,tag2]] [category="category"]
44 desc "Begin a new post in #{CONFIG['posts']}"
45 task :post do
46   abort("rake aborted: '#{CONFIG['posts']}' directory not found.") unless FileTest.directory?(CONFIG['posts'])
47   title = ENV["title"] || "new-post"
48   tags = ENV["tags"] || "[]"
49   category = ENV["category"] || ""
50   category = "\"#{category.gsub(/-/,' ')}\"" if !category.empty?
51   slug = title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
52   begin
53     date = (ENV['date'] ? Time.parse(ENV['date']) : Time.now).strftime('%Y-%m-%d')
54   rescue => e
55     puts "Error - date format must be YYYY-MM-DD, please check you typed it correctly!"
56     exit -1
57   end
58   filename = File.join(CONFIG['posts'], "#{date}-#{slug}.#{CONFIG['post_ext']}")
59   if File.exist?(filename)
60     abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
61   end
62   
63   puts "Creating new post: #{filename}"
64   open(filename, 'w') do |post|
65     post.puts "---"
66     post.puts "layout: post"
67     post.puts "date: \'#{Time.now.strftime('%a %Y-%m-%d %H:%M:%S %z')}\'"
68     post.puts "slug: \"#{slug}\""
69     post.puts "title: \"#{title.gsub(/-/,' ')}\""
70     post.puts 'description: ""'
71     post.puts "category: #{category}"
72     post.puts "tags: #{tags}"
73     post.puts "---"
74     post.puts "{% include JB/setup %}"
75   end
76 end # task :post
78 # Usage: rake page name="about.html"
79 # You can also specify a sub-directory path.
80 # If you don't specify a file extention we create an index.html at the path specified
81 desc "Create a new page."
82 task :page do
83   name = ENV["name"] || "pages/new-page.md"
84   filename = File.join(SOURCE, "#{name}")
85   filename = File.join(filename, "index.html") if File.extname(filename) == ""
86   title = File.basename(filename, File.extname(filename)).gsub(/[\W\_]/, " ").gsub(/\b\w/){$&.upcase}
87   if File.exist?(filename)
88     abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
89   end
90   
91   mkdir_p File.dirname(filename)
92   puts "Creating new page: #{filename}"
93   open(filename, 'w') do |post|
94     post.puts "---"
95     post.puts "layout: page"
96     post.puts "date: \'#{Time.now.strftime('%a %Y-%m-%d %H:%M:%S %z')}\'"
97     post.puts "slug: \'#{title.gsub(/ /,'-')}\'"
98     post.puts "title: \"#{title}\""
99     post.puts 'description: ""'
100     post.puts "---"
101     post.puts "{% include JB/setup %}"
102   end
103 end # task :page
105 desc "Launch preview environment"
106 task :preview do
107   system "jekyll serve -w"
108 end # task :preview
110 # Public: Alias - Maintains backwards compatability for theme switching.
111 task :switch_theme => "theme:switch"
113 namespace :theme do
114   
115   # Public: Switch from one theme to another for your blog.
116   #
117   # name - String, Required. name of the theme you want to switch to.
118   #        The theme must be installed into your JB framework.
119   #
120   # Examples
121   #
122   #   rake theme:switch name="the-program"
123   #
124   # Returns Success/failure messages.
125   desc "Switch between Jekyll-bootstrap themes."
126   task :switch do
127     theme_name = ENV["name"].to_s
128     theme_path = File.join(CONFIG['themes'], theme_name)
129     settings_file = File.join(theme_path, "settings.yml")
130     non_layout_files = ["settings.yml"]
132     abort("rake aborted: name cannot be blank") if theme_name.empty?
133     abort("rake aborted: '#{theme_path}' directory not found.") unless FileTest.directory?(theme_path)
134     abort("rake aborted: '#{CONFIG['layouts']}' directory not found.") unless FileTest.directory?(CONFIG['layouts'])
136     Dir.glob("#{theme_path}/*") do |filename|
137       next if non_layout_files.include?(File.basename(filename).downcase)
138       puts "Generating '#{theme_name}' layout: #{File.basename(filename)}"
140       open(File.join(CONFIG['layouts'], File.basename(filename)), 'w') do |page|
141         page.puts "---"
142         page.puts File.read(settings_file) if File.exist?(settings_file)
143         page.puts "layout: default" unless File.basename(filename, ".html").downcase == "default"
144         page.puts "---"
145         page.puts "{% include JB/setup %}"
146         page.puts "{% include themes/#{theme_name}/#{File.basename(filename)} %}" 
147       end
148     end
149     
150     puts "=> Theme successfully switched!"
151     puts "=> Reload your web-page to check it out =)"
152   end # task :switch
153   
154   # Public: Install a theme using the theme packager.
155   # Version 0.1.0 simple 1:1 file matching.
156   #
157   # git  - String, Optional path to the git repository of the theme to be installed.
158   # name - String, Optional name of the theme you want to install.
159   #        Passing name requires that the theme package already exist.
160   #
161   # Examples
162   #
163   #   rake theme:install git="https://github.com/jekyllbootstrap/theme-twitter.git"
164   #   rake theme:install name="cool-theme"
165   #
166   # Returns Success/failure messages.
167   desc "Install theme"
168   task :install do
169     if ENV["git"]
170       manifest = theme_from_git_url(ENV["git"])
171       name = manifest["name"]
172     else
173       name = ENV["name"].to_s.downcase
174     end
176     packaged_theme_path = JB::Path.build(:theme_packages, :node => name)
177     
178     abort("rake aborted!
179       => ERROR: 'name' cannot be blank") if name.empty?
180     abort("rake aborted! 
181       => ERROR: '#{packaged_theme_path}' directory not found.
182       => Installable themes can be added via git. You can find some here: http://github.com/jekyllbootstrap
183       => To download+install run: `rake theme:install git='[PUBLIC-CLONE-URL]'`
184       => example : rake theme:install git='git@github.com:jekyllbootstrap/theme-the-program.git'
185     ") unless FileTest.directory?(packaged_theme_path)
186     
187     manifest = verify_manifest(packaged_theme_path)
188     
189     # Get relative paths to packaged theme files
190     # Exclude directories as they'll be recursively created. Exclude meta-data files.
191     packaged_theme_files = []
192     FileUtils.cd(packaged_theme_path) {
193       Dir.glob("**/*.*") { |f| 
194         next if ( FileTest.directory?(f) || f =~ /^(manifest|readme|packager)/i )
195         packaged_theme_files << f 
196       }
197     }
198     
199     # Mirror each file into the framework making sure to prompt if already exists.
200     packaged_theme_files.each do |filename|
201       file_install_path = File.join(JB::Path.base, filename)
202       if File.exist? file_install_path and ask("#{file_install_path} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
203         next
204       else
205         mkdir_p File.dirname(file_install_path)
206         cp_r File.join(packaged_theme_path, filename), file_install_path
207       end
208     end
209     
210     puts "=> #{name} theme has been installed!"
211     puts "=> ---"
212     if ask("=> Want to switch themes now?", ['y', 'n']) == 'y'
213       system("rake switch_theme name='#{name}'")
214     end
215   end
217   # Public: Package a theme using the theme packager.
218   # The theme must be structured using valid JB API.
219   # In other words packaging is essentially the reverse of installing.
220   #
221   # name - String, Required name of the theme you want to package.
222   #        
223   # Examples
224   #
225   #   rake theme:package name="twitter"
226   #
227   # Returns Success/failure messages.
228   desc "Package theme"
229   task :package do
230     name = ENV["name"].to_s.downcase
231     theme_path = JB::Path.build(:themes, :node => name)
232     asset_path = JB::Path.build(:theme_assets, :node => name)
234     abort("rake aborted: name cannot be blank") if name.empty?
235     abort("rake aborted: '#{theme_path}' directory not found.") unless FileTest.directory?(theme_path)
236     abort("rake aborted: '#{asset_path}' directory not found.") unless FileTest.directory?(asset_path)
237     
238     ## Mirror theme's template directory (_includes)
239     packaged_theme_path = JB::Path.build(:themes, :root => JB::Path.build(:theme_packages, :node => name))
240     mkdir_p packaged_theme_path
241     cp_r theme_path, packaged_theme_path
242     
243     ## Mirror theme's asset directory
244     packaged_theme_assets_path = JB::Path.build(:theme_assets, :root => JB::Path.build(:theme_packages, :node => name))
245     mkdir_p packaged_theme_assets_path
246     cp_r asset_path, packaged_theme_assets_path
248     ## Log packager version
249     packager = {"packager" => {"version" => CONFIG["theme_package_version"].to_s } }
250     open(JB::Path.build(:theme_packages, :node => "#{name}/packager.yml"), "w") do |page|
251       page.puts packager.to_yaml
252     end
253     
254     puts "=> '#{name}' theme is packaged and available at: #{JB::Path.build(:theme_packages, :node => name)}"
255   end
256   
257 end # end namespace :theme
259 # Internal: Download and process a theme from a git url.
260 # Notice we don't know the name of the theme until we look it up in the manifest.
261 # So we'll have to change the folder name once we get the name.
263 # url - String, Required url to git repository.
264 #        
265 # Returns theme manifest hash
266 def theme_from_git_url(url)
267   tmp_path = JB::Path.build(:theme_packages, :node => "_tmp")
268   abort("rake aborted: system call to git clone failed") if !system("git clone #{url} #{tmp_path}")
269   manifest = verify_manifest(tmp_path)
270   new_path = JB::Path.build(:theme_packages, :node => manifest["name"])
271   if File.exist?(new_path) && ask("=> #{new_path} theme package already exists. Override?", ['y', 'n']) == 'n'
272     remove_dir(tmp_path)
273     abort("rake aborted: '#{manifest["name"]}' already exists as theme package.")
274   end
276   remove_dir(new_path) if File.exist?(new_path)
277   mv(tmp_path, new_path)
278   manifest
281 # Internal: Process theme package manifest file.
283 # theme_path - String, Required. File path to theme package.
284 #        
285 # Returns theme manifest hash
286 def verify_manifest(theme_path)
287   manifest_path = File.join(theme_path, "manifest.yml")
288   manifest_file = File.open( manifest_path )
289   abort("rake aborted: repo must contain valid manifest.yml") unless File.exist? manifest_file
290   manifest = YAML.load( manifest_file )
291   manifest_file.close
292   manifest
295 def ask(message, valid_options)
296   if valid_options
297     answer = get_stdin("#{message} #{valid_options.to_s.gsub(/"/, '').gsub(/, /,'/')} ") while !valid_options.include?(answer)
298   else
299     answer = get_stdin(message)
300   end
301   answer
304 def get_stdin(message)
305   print message
306   STDIN.gets.chomp
309 #Load custom rake scripts
310 Dir['_rake/*.rake'].each { |r| load r }