class Solutus
TODO: Add support for tags TODO: Make stress tests TODO: Fix bug : day being off with time in file
Constants
- ARCHIVE
- BLOG_BUILD_PATH
- BLOG_DATE_DATA
- BLOG_DATE_FORMAT
- BLOG_TEMPLATE
- BUILD_PATH
- CACHE
- DAY_ENDINGS
- DEFAULT_TEMPLATE
- LOG_FILE
- PASSWORD_FILE
- POSTS_PATH
- SETTINGS_FILE
- SITE_PAGES_PATH
- SITE_PATH
- STATIC_PATH
- TEMPLATES_PATH
- VERSION
Public Class Methods
blog_urls()
click to toggle source
# File lib/solutus.rb, line 535 def self.blog_urls @@blog_urls end
build()
click to toggle source
# File lib/solutus.rb, line 613 def self.build puts "Solutus is building the static site" settings_data = load_settings if settings_data == false return end if File.directory?(BUILD_PATH) FileUtils.remove_dir(BUILD_PATH) end Dir.mkdir(BUILD_PATH) Dir.mkdir(SITE_PATH) copy_static @@templates = Hash.new Dir.entries(TEMPLATES_PATH).each do |entry| next if entry == "." || entry == ".." puts "Loading template #{entry}" path = File.join(TEMPLATES_PATH, entry) if File.file?(path) contents = "" f = File.open(path, "r") f.each_line do |line| contents += line end @@templates[entry.split(".")[0]] = contents end end yaml_data = Hash.new @@blog_urls = Hash.new Dir.entries(POSTS_PATH).each do |entry| next if entry == "." || entry == ".." path = File.join(POSTS_PATH, entry) f = File.open(path, "r") contents = "" f.each_line do |line| contents += line end f.close yaml_data[entry] = contents data = YAML.load(contents) date = data["date"] subtitle = data.fetch("subtitle", "") relative_dir = File.join(date.year.to_s, date.month.to_s, date.day.to_s, entry.split(".")[0]) year = date.year.to_s if !@@blog_urls.key?(year) @@blog_urls[year] = Array.new end @@blog_urls[year].push({ "title" => data["title"], "url" => File.join(ARCHIVE, relative_dir), "file_path" => path, "date" => date, "subtitle" => subtitle }) end recents_count = 3 recents = "" get_recents(recents_count).reverse.each do |post| url = post["url"] title = post["title"] date = prettify_date(post["date"]) subtitle = post["subtitle"] block = <<HERE <div class="solutus-recents-block"> <a class="solutus-blog-thumbnail" href="/#{url}">#{title}</a> - #{date} <div class="solutus-blog-subtitle"><i>#{subtitle}</i></div> </div> HERE recents += block end yaml_data.each do |entry, contents| path = File.join(POSTS_PATH, entry) data = YAML.load(contents) markdown_parsed = render_markdown(contents.split("---")[-1]) data["content"] = markdown_parsed data["recents"] = recents date = data["date"] puts "Rendering blog post #{entry}" html = render_page(@@templates, settings_data, data, true) relative_dir = File.join(date.year.to_s, date.month.to_s, date.day.to_s, entry.split(".")[0]) root_url = File.join(ARCHIVE, relative_dir, "index.html") year = date.year.to_s dir_path = File.join(BLOG_BUILD_PATH, relative_dir) if !File.directory?(dir_path) FileUtils.mkdir_p(dir_path) end file_path = File.join(SITE_PATH, root_url) puts "Created #{file_path}" f = File.new(file_path, "w") f.write(html) f.close() end @@page_urls = Array.new relative_path_to_all_files_in_dir(SITE_PAGES_PATH).each do |entry| next if entry == "." || entry == ".." puts "Rendering page #{entry}" path = File.join(SITE_PAGES_PATH, entry) if File.file?(path) yml_text = "" f = File.open(path, "r") f.each_line do |line| yml_text += line end data = YAML.load(yml_text) data["recents"] = recents html = render_page(@@templates, settings_data, data, false) new_dir = File.join(SITE_PATH, entry.split(".")[0]) if ["error", "index"].include? entry.split(".")[0] new_path = File.join(SITE_PATH, entry.split(".")[0] + ".html") else if !File.directory?(new_dir) FileUtils.mkdir_p(new_dir) end new_path = File.join(new_dir, "index.html") end f = File.new(new_path, "w") puts "Created #{new_path}" f.write(html) f.close @@page_urls.push({ "title" => data["title"], "file_path" => path }) end end # Create blog archive page content = "" @@blog_urls.each do |yr, arr| sorted = arr.sort_by {|k| k["date"]} .reverse content += "<h3>#{yr}</h3>\n<hr>\n" sorted.each do |hash| url = hash["url"] title = hash["title"] pretty_date = prettify_date(hash["date"]) content += "<div class=\"solutus-blog-block\">\n" content += " <div class=\"solutus-blog-title\">\n" content += " <a href=\"/#{url}\">#{title}</a>\n" content += " </div>\n" content += " <div>#{pretty_date}</div>\n" content += "</div>\n" end end if File.directory?(File.join(SITE_PATH, ARCHIVE)) path = File.join(SITE_PATH, ARCHIVE, "index.html") data = Hash.new data["title"] = "Archive" data["content"] = content data["recents"] = recents html = render_page(@@templates, settings_data, data, false) f = File.new(path, "w") f.write(html) f.close puts "Created blog archive @ #{path}" end # Mirror build if settings_data["mirror"] dir_path = settings_data["mirror"] FileUtils.rm_rf("#{dir_path}/.", secure: true) FileUtils.copy_entry(SITE_PATH, dir_path) end end
command(*args)
click to toggle source
# File lib/solutus.rb, line 547 def self.command(*args) start_time = Time.now if args.length >= 1 if ["-v", "--version"].include?(args[0]) puts VERSION return elsif args[0] == "deploy" deploy elsif args[0] == "build" build elsif args[0] == "serve" build #right now, the server won't werve unless its built. #consider serializing data in cache to save time. #TODO: Stress test the build for speed. serve return elsif args[0] == "start" build serve return elsif args[0] == "publish" build deploy else if args.length >= 2 if args[0] == "password" create_password(args[1]) elsif args[0] == "create" new_project(args[1]) else if args.length >= 3 if args[0] == "new" if args[1] == "page" new_page(args[2]) elsif args[1] == "post" return new_post(args[2]) end end else puts "Invalid arguments" return end end else puts "Unknown command." return end end end end_time = Time.now diff = end_time - start_time puts "Completed in #{diff} seconds." end
copy_static()
click to toggle source
# File lib/solutus.rb, line 875 def self.copy_static Dir.entries(STATIC_PATH).each do |entry| next if entry == "." || entry == ".." path = File.join(STATIC_PATH, entry) if File.file?(path) puts "Copying static file #{path}" FileUtils.copy(path, File.join(SITE_PATH, entry)) elsif File.directory?(path) puts "Recursively copying static dir #{path}" FileUtils.copy_entry(path, File.join(SITE_PATH, entry)) end end end
correct_time(time)
click to toggle source
# File lib/solutus.rb, line 901 def self.correct_time(time) time.utc.localtime("+05:30") end
create_password(password)
click to toggle source
# File lib/solutus.rb, line 935 def self.create_password(password) content = Digest::MD5.hexdigest password if File.file?(PASSWORD_FILE) FileUtils.rm(PASSWORD_FILE) end f = File.new(PASSWORD_FILE, "w") f.write(content) f.close puts "Wrote password to password.txt" end
deploy()
click to toggle source
# File lib/solutus.rb, line 602 def self.deploy puts "Solutus is deploying" system load_settings["deploy-command"] end
get_recents(count)
click to toggle source
# File lib/solutus.rb, line 893 def self.get_recents(count) res = Array.new @@blog_urls.each do |yr, arr| res = res + arr.sort_by {|k| k["date"]} end res.last(count) end
load_settings()
click to toggle source
# File lib/solutus.rb, line 44 def self.load_settings begin yml_text = "" f = File.open(SETTINGS_FILE, "r") f.each_line do |line| yml_text += line end f.close YAML.load(yml_text) rescue puts "Not a Solutus Project (yet) --- settings.yml not found" false end end
new_page(title)
click to toggle source
# File lib/solutus.rb, line 811 def self.new_page(title) title = title.gsub(/\s+/, "").gsub(/[^a-zA-Z0-9\-]/, "").strip if title.empty? puts "Bad name" return end if ["edit"].include?(title) puts "Can't use #{title} as a page name." return end path = File.join(SITE_PAGES_PATH, title + ".yml") if File.file?(path) puts "Page with that name already exists." return end text = <<HERE template: default title: #{title} content: | <h1>#{title}</h1> <p> Some Content </p> HERE f = File.new(path, "w") f.write(text) f.close puts "Created new site page #{title} at #{path}" end
new_post(title)
click to toggle source
# File lib/solutus.rb, line 843 def self.new_post(title) i = 1 new_title = title.gsub(/\s+/, "").gsub(/[^a-zA-Z0-9\-]/, "").strip if title.empty? puts "Empty title" return "" end while true path = File.join(POSTS_PATH, new_title + ".md") if File.file?(path) new_title = title + "#{i}" i += 1 else break end end date = Time.now.strftime(BLOG_DATE_DATA) text = <<HERE --- title: #{title} date: #{date} subtitle: Another new blog post --- *This is a temporary blog post page!* HERE f = File.new(path, "w") f.write(text) f.close puts "Created new blog post #{title} at #{path}" path end
new_project(name)
click to toggle source
# File lib/solutus.rb, line 946 def self.new_project(name) name = name.gsub(/[^a-zA-Z0-9\-]/, "").strip if name == "" puts "Invalid name" return end if File.directory?(name) puts "Invalid name, already a folder with that name" print "Overwrite? [Y/n]" if STDIN.gets.chomp == "Y" FileUtils.remove_dir(name) else return end end Dir.mkdir(name) paths = Array.new ["deploy", "static", "templates", "pages", CACHE].each do |dir| paths.push(File.join(name, dir)) end ["css", "js", "imgs"].each do |dir| paths.push(File.join(name, "static", dir)) end ["posts", "site-pages"].each do |dir| paths.push(File.join(name, "pages", dir)) end paths.each do |path| Dir.mkdir(path) end settings_file = <<HERE name: #{name} author: Your Name domain: www.yoursite.tld deploy-command: aws s3 sync --acl public-read --sse --delete deploy/site/ s3://www.yoursite.tld watermark: | <p style="text-align: center;"> <small>Powered by <a href="https://github.com/jeromew21/solutus">Solutus</a></small> </p> stylesheets: | <link rel="stylesheet" type="text/css" href="/css/styles.css" /> scripts: | <script></script> recents-count: 3 advanced: false HERE styles_file = <<HERE body { background-color: #EEEEEE; } HERE default_file = <<HERE <!DOCTYPE html> <head> <title>{{title}}</title> {{{stylesheets}}} </head> <body> <div id="solutus-everything"> {{#blog}} <h1>{{title}}</h1> {{{date}}} {{/blog}} {{{content}}} <h3>Recent Posts</h3> {{{recents}}} <small style="display: block; text-align: center;">© {{year}} {{author}}</small> {{{watermark}}} </div> {{{scripts}}} </body> </html> HERE datetime = Time.now.strftime(BLOG_DATE_DATA) test_file = <<HERE title: Example Blog Post date: #{datetime} subtitle: an example post... --- *This is an example blog post page!* HERE index_file = <<HERE template: default title: Home page type: html content: | <h1>Hello World!</h1> <p> this is a test </p> HERE files = { File.join(name, "settings.yml") => settings_file, File.join(name, ".gitignore") => PASSWORD_FILE + "\n", File.join(name, "static", "css", "styles.css") => styles_file, File.join(name, "templates", "default.html") => default_file, File.join(name, "pages", "posts", "test.md") => test_file, File.join(name, "pages", "site-pages", "index.yml") => index_file, } files.each do |filename, contents| puts "Created #{filename}" f = File.new(filename, "w") f.write(contents) f.close end puts "Created new project #{name}" end
page_urls()
click to toggle source
# File lib/solutus.rb, line 539 def self.page_urls @@page_urls end
prettify_date(date)
click to toggle source
# File lib/solutus.rb, line 889 def self.prettify_date(date) date.strftime("%b %e") + DAY_ENDINGS[date.strftime("%e").to_i] end
relative_path_to_all_files_in_dir(dir)
click to toggle source
# File lib/solutus.rb, line 920 def self.relative_path_to_all_files_in_dir(dir) result = Array.new Dir.entries(dir).each do |entry| next if entry == "." || entry == ".." path = File.join(dir, entry) if File.file?(path) result.push(entry) elsif File.directory?(path) result = result + relative_path_to_all_files_in_dir(path).collect {|x| File.join(entry, x)} end end result end
render_markdown(markdown)
click to toggle source
# File lib/solutus.rb, line 905 def self.render_markdown(markdown) Redcarpet::Markdown.new(Redcarpet::Render::HTML.new).render(markdown) end
render_page(templates, default_data, data, blog=false)
click to toggle source
# File lib/solutus.rb, line 789 def self.render_page(templates, default_data, data, blog=false) if data.key?("template") SolutusStache.template = templates[data["template"]] else SolutusStache.template = templates[DEFAULT_TEMPLATE] end result = SolutusStache.new default_data.each do |key, val| result[key.to_sym] = val || "" end data.each do |key, val| next if key == "template" if key != "title" val = wrap_element(key, val) end result[key.to_sym] = val || "" end result[:blog] = blog || false result[:year] = Time.now.year result.render end
serve()
click to toggle source
# File lib/solutus.rb, line 607 def self.serve puts "Solutus is serving" puts "View at http://localhost:4567/" Solutus_Server.run! end
templates()
click to toggle source
# File lib/solutus.rb, line 543 def self.templates @@templates end
wrap_element(key, content)
click to toggle source
# File lib/solutus.rb, line 909 def self.wrap_element(key, content) if content.is_a?(Time) content = correct_time(content).strftime(BLOG_DATE_FORMAT) end result = "" result += "<div id=\"solutus-#{key}\">\n" result += content result += "</div>" result end