diff --git a/bin/sitegen b/bin/sitegen index c9f99bc..1db89b8 100755 --- a/bin/sitegen +++ b/bin/sitegen @@ -1,217 +1,18 @@ #!/usr/bin/env moon -moonscript = require "moonscript" -moon = require "moon" -cosmo = require "cosmo" - -import run_with_scope, extend, dump from require "moon" -import SiteFile from require "sitegen.site_file" -import catch_error, throw_error, split, slugify, Path from require "sitegen.common" - action = ... or "build" args = {...} -default = { - sitefile: "site.moon" - files: - page: [==[{ - date: "$eval{"require('date')()"}" - $if{"title"}[[title: "$title"]] -} - -Hello world! - -]==] - sitefile: [==[ -sitegen = require "sitegen" -sitegen.create => - @title = $title -]==] -} - -log = (...) -> - print "->", ... - -scope = (t={}) -> - extend t, { - eval: (arg) -> - code = "return -> " .. arg[1] - moonscript.loadstring(code)!! - if: (arg) -> - var_name = arg[1] - cosmo.yield t if t[var_name] - nil - } - -get_site = -> SiteFile!\get_site! - -annotate = (obj, verbs) -> - setmetatable {}, { - __newindex: (name, value) => - obj[name] = value - __index: (name) => - fn = obj[name] - return fn if not type(fn) == "function" - if verbs[name] - (...) -> - fn ... - first = ... - log verbs[name], first - else - fn - } - -Path = annotate Path, { - mkdir: "made directory" - write_file: "wrote" -} - --- wrap test based on tokens -wrap_text = (text, indent=0, max_width=80) -> - width = max_width - indent - words = split text, " " - pos = 1 - lines = {} - while pos <= #words - line_len = 0 - line = {} - while true - word = words[pos] - break if word == nil - error "can't wrap text, words too long" if #word > width - break if line_len + #word > width - - pos += 1 - table.insert line, word - line_len += #word + 1 -- +1 for the space - - table.insert lines, table.concat line, " " - - table.concat lines, "\n" .. (" ")\rep indent - -columnize = (rows, indent=2, padding=4) -> - max = 0 - max = math.max max, #row[1] for row in *rows - - left_width = indent + padding + max - - formatted = for row in *rows - padd = (max - #row[1]) + padding - table.concat { - (" ")\rep indent - row[1] - (" ")\rep padd - wrap_text row[2], left_width - } - - table.concat formatted, "\n" - -tasks = { - dump: -> print dump get_site! - - new: (title) -> - if Path.exists default.sitefile - throw_error "sitefile already exists: " .. default.sitefile - - title = ("%q")\format title or "Hello World" - - Path.mkdir"www" - Path.mkdir"templates" - - site_moon = cosmo.f(default.files.sitefile) scope{:title} - Path.write_file default.sitefile, site_moon - - page: (path, title)-> - get_site! - - if not title - title = path - path_part, title_part = title\match"^(.-)([^/]+)$" - if path_part - title = title_part - path = path_part - else - path = '.' - - Path.mkdir path if Path.normalize(path) != "" - - -- iterater for all potential file names - names = (fname, ext=".md") -> - i = 0 - coroutine.wrap -> - while true - coroutine.yield if i == 0 - fname .. ext - else - table.concat {fname, "_", i, ext } - i += 1 - - full_path = nil - for name in names slugify title - full_path = Path.join path, name - if not Path.exists full_path - break - - Path.write_file full_path, cosmo.f(default.files.page) scope{:title} - - -- TODO: this should be implemented in the plugin, not here - deploy: (host, path) -> - site = get_site! - deploy = site\get_plugin "sitegen.plugins.deploy" - throw_error "deploy plugin not initialized" unless deploy - - {:host, :path} = deploy - - throw_error "need host" unless host - throw_error "need path" unless path - - log "uploading to:", host, path - - deploy\sync! - - build: (...) -> - files = {...} - site = get_site! - - local filter - if next files - filter = {} - for i, fname in ipairs files - filter[site.sitefile\relativeize fname] = true - - site\write filter - - watch: -> - site = get_site! - w = require "sitegen.watch" - - with w.Watcher site - \loop! - - help: -> - print "Sitegen" - print "usage: sitegen [args]" - print! - print "Available actions:" - - print! - print columnize { - {"new", "Create a new site in the current directory"} - {"build [input-files]", "Build (or rebuild) all pages, or only files"} - {"page [title]", "Create a new markdown page at path"} - {"deploy [host] [path]", "Deploy site to host over ssh (rsync)"} - {"watch", "Compile pages automatically when inputs change (needs inotify)"} - } - print! -} +import actions from require "sitegen.cmd.actions" +import catch_error from require "sitegen.common" -- potential commands: -- plugins: sitegen blog:post "Hello World" -- did I already do this? catch_error -> - if not tasks[action] + if not actions[action] throw_error "unknown task: " .. action - tasks[action] unpack args, 2 + actions[action] unpack args, 2 -- vim: set filetype=moon: diff --git a/sitegen-dev-1.rockspec b/sitegen-dev-1.rockspec index 84cf50c..f105b8e 100644 --- a/sitegen-dev-1.rockspec +++ b/sitegen-dev-1.rockspec @@ -29,6 +29,8 @@ build = { modules = { ["sitegen"] = "sitegen/init.lua", ["sitegen.cache"] = "sitegen/cache.lua", + ["sitegen.cmd.actions"] = "sitegen/cmd/actions.lua", + ["sitegen.cmd.util"] = "sitegen/cmd/util.lua", ["sitegen.common"] = "sitegen/common.lua", ["sitegen.default.templates"] = "sitegen/default/templates.lua", ["sitegen.formatters.default"] = "sitegen/formatters/default.lua", diff --git a/sitegen/cmd/actions.lua b/sitegen/cmd/actions.lua new file mode 100644 index 0000000..d0a2456 --- /dev/null +++ b/sitegen/cmd/actions.lua @@ -0,0 +1,192 @@ +local moonscript = require("moonscript") +local cosmo = require("cosmo") +local throw_error, slugify +do + local _obj_0 = require("sitegen.common") + throw_error, slugify = _obj_0.throw_error, _obj_0.slugify +end +local log, get_site, columnize, Path +do + local _obj_0 = require("sitegen.cmd.util") + log, get_site, get_site, columnize, Path = _obj_0.log, _obj_0.get_site, _obj_0.get_site, _obj_0.columnize, _obj_0.Path +end +local extend, dump +do + local _obj_0 = require("moon") + extend, dump = _obj_0.extend, _obj_0.dump +end +local default = { + sitefile = "site.moon", + files = { + page = [==[{ + date: "$eval{"require('date')()"}" + $if{"title"}[[title: "$title"]] +} + +Hello world! + +]==], + sitefile = [==[sitegen = require "sitegen" +sitegen.create => + @title = $title +]==] + } +} +local scope +scope = function(t) + if t == nil then + t = { } + end + return extend(t, { + eval = function(arg) + local code = "return -> " .. arg[1] + return moonscript.loadstring(code)()() + end, + ["if"] = function(arg) + local var_name = arg[1] + if t[var_name] then + cosmo.yield(t) + end + return nil + end + }) +end +local actions = { + dump = function() + return print(dump(get_site())) + end, + new = function(title) + if Path.exists(default.sitefile) then + throw_error("sitefile already exists: " .. default.sitefile) + end + title = ("%q"):format(title or "Hello World") + Path.mkdir("www") + Path.mkdir("templates") + local site_moon = cosmo.f(default.files.sitefile)(scope({ + title = title + })) + return Path.write_file(default.sitefile, site_moon) + end, + page = function(path, title) + get_site() + if not title then + title = path + local path_part, title_part = title:match("^(.-)([^/]+)$") + if path_part then + title = title_part + path = path_part + else + path = '.' + end + end + if Path.normalize(path) ~= "" then + Path.mkdir(path) + end + local names + names = function(fname, ext) + if ext == nil then + ext = ".md" + end + local i = 0 + return coroutine.wrap(function() + while true do + coroutine.yield((function() + if i == 0 then + return fname .. ext + else + return table.concat({ + fname, + "_", + i, + ext + }) + end + end)()) + i = i + 1 + end + end) + end + local full_path = nil + for name in names(slugify(title)) do + full_path = Path.join(path, name) + if not Path.exists(full_path) then + break + end + end + return Path.write_file(full_path, cosmo.f(default.files.page)(scope({ + title = title + }))) + end, + deploy = function(host, path) + local site = get_site() + local deploy = site:get_plugin("sitegen.plugins.deploy") + if not (deploy) then + throw_error("deploy plugin not initialized") + end + host, path = deploy.host, deploy.path + if not (host) then + throw_error("need host") + end + if not (path) then + throw_error("need path") + end + log("uploading to:", host, path) + return deploy:sync() + end, + build = function(...) + local files = { + ... + } + local site = get_site() + local filter + if next(files) then + filter = { } + for i, fname in ipairs(files) do + filter[site.sitefile:relativeize(fname)] = true + end + end + return site:write(filter) + end, + watch = function() + local site = get_site() + local w = require("sitegen.watch") + do + local _with_0 = w.Watcher(site) + _with_0:loop() + return _with_0 + end + end, + help = function() + print("Sitegen") + print("usage: sitegen [args]") + print() + print("Available actions:") + print() + print(columnize({ + { + "new", + "Create a new site in the current directory" + }, + { + "build [input-files]", + "Build (or rebuild) all pages, or only files" + }, + { + "page [title]", + "Create a new markdown page at path" + }, + { + "deploy [host] [path]", + "Deploy site to host over ssh (rsync)" + }, + { + "watch", + "Compile pages automatically when inputs change (needs inotify)" + } + })) + return print() + end +} +return { + actions = actions +} diff --git a/sitegen/cmd/actions.moon b/sitegen/cmd/actions.moon new file mode 100644 index 0000000..7693860 --- /dev/null +++ b/sitegen/cmd/actions.moon @@ -0,0 +1,140 @@ +moonscript = require "moonscript" +cosmo = require "cosmo" + +import throw_error, slugify from require "sitegen.common" +import log, get_site, get_site, columnize, Path from require "sitegen.cmd.util" + +import extend, dump from require "moon" + +default = { + sitefile: "site.moon" + files: + page: [==[{ + date: "$eval{"require('date')()"}" + $if{"title"}[[title: "$title"]] +} + +Hello world! + +]==] + sitefile: [==[ +sitegen = require "sitegen" +sitegen.create => + @title = $title +]==] +} + + +scope = (t={}) -> + extend t, { + eval: (arg) -> + code = "return -> " .. arg[1] + moonscript.loadstring(code)!! + if: (arg) -> + var_name = arg[1] + cosmo.yield t if t[var_name] + nil + } + +actions = { + dump: -> print dump get_site! + + new: (title) -> + if Path.exists default.sitefile + throw_error "sitefile already exists: " .. default.sitefile + + title = ("%q")\format title or "Hello World" + + Path.mkdir"www" + Path.mkdir"templates" + + site_moon = cosmo.f(default.files.sitefile) scope{:title} + Path.write_file default.sitefile, site_moon + + page: (path, title)-> + get_site! + + if not title + title = path + path_part, title_part = title\match"^(.-)([^/]+)$" + if path_part + title = title_part + path = path_part + else + path = '.' + + Path.mkdir path if Path.normalize(path) != "" + + -- iterater for all potential file names + names = (fname, ext=".md") -> + i = 0 + coroutine.wrap -> + while true + coroutine.yield if i == 0 + fname .. ext + else + table.concat {fname, "_", i, ext } + i += 1 + + full_path = nil + for name in names slugify title + full_path = Path.join path, name + if not Path.exists full_path + break + + Path.write_file full_path, cosmo.f(default.files.page) scope{:title} + + -- TODO: this should be implemented in the plugin, not here + deploy: (host, path) -> + site = get_site! + deploy = site\get_plugin "sitegen.plugins.deploy" + throw_error "deploy plugin not initialized" unless deploy + + {:host, :path} = deploy + + throw_error "need host" unless host + throw_error "need path" unless path + + log "uploading to:", host, path + + deploy\sync! + + build: (...) -> + files = {...} + site = get_site! + + local filter + if next files + filter = {} + for i, fname in ipairs files + filter[site.sitefile\relativeize fname] = true + + site\write filter + + watch: -> + site = get_site! + w = require "sitegen.watch" + + with w.Watcher site + \loop! + + help: -> + print "Sitegen" + print "usage: sitegen [args]" + print! + print "Available actions:" + + print! + print columnize { + {"new", "Create a new site in the current directory"} + {"build [input-files]", "Build (or rebuild) all pages, or only files"} + {"page [title]", "Create a new markdown page at path"} + {"deploy [host] [path]", "Deploy site to host over ssh (rsync)"} + {"watch", "Compile pages automatically when inputs change (needs inotify)"} + } + print! +} + +{:actions} + + diff --git a/sitegen/cmd/util.lua b/sitegen/cmd/util.lua new file mode 100644 index 0000000..2b01149 --- /dev/null +++ b/sitegen/cmd/util.lua @@ -0,0 +1,117 @@ +local split, Path +do + local _obj_0 = require("sitegen.common") + split, Path = _obj_0.split, _obj_0.Path +end +local SiteFile +SiteFile = require("sitegen.site_file").SiteFile +local log +log = function(...) + return print("->", ...) +end +local get_site +get_site = function() + return SiteFile():get_site() +end +local annotate +annotate = function(obj, verbs) + return setmetatable({ }, { + __newindex = function(self, name, value) + obj[name] = value + end, + __index = function(self, name) + local fn = obj[name] + if not type(fn) == "function" then + return fn + end + if verbs[name] then + return function(...) + fn(...) + local first = ... + return log(verbs[name], first) + end + else + return fn + end + end + }) +end +Path = annotate(Path, { + mkdir = "made directory", + write_file = "wrote" +}) +local wrap_text +wrap_text = function(text, indent, max_width) + if indent == nil then + indent = 0 + end + if max_width == nil then + max_width = 80 + end + local width = max_width - indent + local words = split(text, " ") + local pos = 1 + local lines = { } + while pos <= #words do + local line_len = 0 + local line = { } + while true do + local word = words[pos] + if word == nil then + break + end + if #word > width then + error("can't wrap text, words too long") + end + if line_len + #word > width then + break + end + pos = pos + 1 + table.insert(line, word) + line_len = line_len + #word + 1 + end + table.insert(lines, table.concat(line, " ")) + end + return table.concat(lines, "\n" .. (" "):rep(indent)) +end +local columnize +columnize = function(rows, indent, padding) + if indent == nil then + indent = 2 + end + if padding == nil then + padding = 4 + end + local max = 0 + for _index_0 = 1, #rows do + local row = rows[_index_0] + max = math.max(max, #row[1]) + end + local left_width = indent + padding + max + local formatted + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #rows do + local row = rows[_index_0] + local padd = (max - #row[1]) + padding + local _value_0 = table.concat({ + (" "):rep(indent), + row[1], + (" "):rep(padd), + wrap_text(row[2], left_width) + }) + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end + formatted = _accum_0 + end + return table.concat(formatted, "\n") +end +return { + log = log, + Path = Path, + annotate = annotate, + get_site = get_site, + columnize = columnize +} diff --git a/sitegen/cmd/util.moon b/sitegen/cmd/util.moon new file mode 100644 index 0000000..88b0ee4 --- /dev/null +++ b/sitegen/cmd/util.moon @@ -0,0 +1,71 @@ +import split, Path from require "sitegen.common" +import SiteFile from require "sitegen.site_file" + +log = (...) -> + print "->", ... + +get_site = -> SiteFile!\get_site! + +annotate = (obj, verbs) -> + setmetatable {}, { + __newindex: (name, value) => + obj[name] = value + __index: (name) => + fn = obj[name] + return fn if not type(fn) == "function" + if verbs[name] + (...) -> + fn ... + first = ... + log verbs[name], first + else + fn + } + +Path = annotate Path, { + mkdir: "made directory" + write_file: "wrote" +} + +-- wrap test based on tokens +wrap_text = (text, indent=0, max_width=80) -> + width = max_width - indent + words = split text, " " + pos = 1 + lines = {} + while pos <= #words + line_len = 0 + line = {} + while true + word = words[pos] + break if word == nil + error "can't wrap text, words too long" if #word > width + break if line_len + #word > width + + pos += 1 + table.insert line, word + line_len += #word + 1 -- +1 for the space + + table.insert lines, table.concat line, " " + + table.concat lines, "\n" .. (" ")\rep indent + +columnize = (rows, indent=2, padding=4) -> + max = 0 + max = math.max max, #row[1] for row in *rows + + left_width = indent + padding + max + + formatted = for row in *rows + padd = (max - #row[1]) + padding + table.concat { + (" ")\rep indent + row[1] + (" ")\rep padd + wrap_text row[2], left_width + } + + table.concat formatted, "\n" + + +{ :log, :Path, :annotate, :get_site, :columnize }