#!/usr/bin/env lua -- porteail.lua --[[ Requirements ]]-- require 'lfs' --[[ Variables ]]-- -- Mandatories files local configFile = './' .. 'configrc' -- Default directories values local currentpath = os.getenv('CURDIR') or '.' local default_dir_category = 'categ' local default_dir_component = 'composants' local default_dir_destination = 'porteail' local default_dir_img_destination = 'image' local default_dir_img_source = 'img' local default_dir_css_source = 'style' local default_dir_lang = 'lang' -- Default files values local default_img_filename = 'generique.png' local default_index_filename = 'index.html' local default_template_index_filename = 'index.html' local default_template_categ_filename = 'categories.html' local default_template_element_filename = 'element.html' local default_css_filename = 'black.css' local default_css_menu_without = 'without_menu.css' local default_css_menu_with = 'with_menu.css' -- Other defaults values local version = os.getenv('VERSION') or '(Unknown version)' local default_categ_extension = 'txt' local DIR_SEP = '/' local default_css_name = 'Default' local default_title = 'My portal' local default_homepage_title = ' - Homepage' local default_language = 'en' --[[ Functions ]]-- function readFile(path, mode) result = '' if not mode then mode = 'r' end if mode ~= 'r' and mode ~= 'rb' then print('Unknown read mode!') os.exit(1) end attr = lfs.attributes(path) if attr and attr.mode == 'file' then f = assert(io.open(path, mode)) result = assert(f:read('*a')) assert(f:close()) end return result end function getConfig(file) result = {} f = assert(io.open(file, 'r')) while true do line = f.read(f) if not line then break end local key = line:match('([^#].-)[ ]+=') local val = line:match('=[ ]+(.*)') local comment = string.find(line, '^#+(.*)') if comment then -- do nothing with comment elseif key then result[key] = val end end assert(f:close()) return result end function replace(string, table) return string:gsub("$(%b{})", function(string) return table[string:sub(2,-2)] end) end function listing (path, extension) files = {} if lfs.attributes(path) then for file in lfs.dir(path) do if file ~= "." and file ~= ".." then local f = path..'/'..file local attr = lfs.attributes (f) filext = (string.match(file, "[^\\/]-%.?([^%.\\/]*)$")) if attr.mode == 'file' and filext == extension then table.insert(files, f) end end end else files = nil end return files end function basename (string, suffix) string = string or '' local basename = string.gsub (string, '[^'.. DIR_SEP ..']*'.. DIR_SEP ..'', '') if suffix then basename = string.gsub (basename, suffix, '') end return basename end function processImage(image, source, img_destination, destination, default_img) -- if no image given, use default one if not image or image == nil or image == '' then image = default_img end -- create image weblink result = img_destination .. '/' .. basename(image) -- check if this image exists attr = lfs.attributes(destination .. '/' .. result) if not attr then img_path = source .. '/' .. image f = assert(io.open(img_path, 'rb')) img_src = assert(f:read('*a')) assert(f:close()) img_dest = assert(io.open(destination .. '/' .. result, 'wb')) assert(img_dest:write(img_src)) assert(img_dest:close()) end return result end function process(filepath, template_categ, template_element, img_destination, destination, img_source, default_img) -- parse given file local elements = {} local categ_title = '' local categ_description = '' local categ_count = 0 -- parse category file for line in io.lines(filepath) do local element = '' -- check if this line is: -- a comment ("# my comment"), -- a category ("[[My category]]Its description") -- or an element ("Title##Description##URL##Image") is_comment = string.find(line, '^#+.*') is_title = string.find(line, '%[%[(.*)%]%](.*)') is_element = string.find(line, '(.*)##(.*)##(.*)##(.*)') -- processing lines to fetch data if is_comment then -- do nothing because it's a comment elseif is_title then for t in string.gmatch(line, '%[%[(.*)%]%].*') do categ_title = categ_title .. t end for d in string.gmatch(line, '%[%[.*%]%](.*)') do categ_description = categ_description .. d end categ_count = categ_count + 1 elseif is_element then title = '' description = '' url = '' img = '' for t in string.gmatch(line, '(.*)##.*##.*##.*') do title = title .. t end for d in string.gmatch(line, '.*##.*##(.*)##.*') do description = description .. d end for u in string.gmatch(line, '.*##(.*)##.*##.*') do url = url .. u end for i in string.gmatch(line, '.*##.*##.*##(.*)') do img = img .. i end img_description = " " -- copy image and fetch result img_url = processImage(img, img_source, img_destination, destination, default_img) -- replace some chars in URL to avoid HTML5 problems url = url:gsub('%&', '%&') -- create element's result element = replace(template_element, {ELEMENT_URL=url, ELEMENT_DESC=description, ELEMENT_TITLE=title, IMG_URL=img_url, IMG_DESC=img_description}) -- add it to elements table table.insert(elements, element) end end -- check if category is ok error_msg = ' ' .. filepath .. ' not imported: ' if categ_count > 1 then print (error_msg .. 'too many categories.') return '' elseif categ_count == 0 then print (error_msg .. 'no category found.') return '' end -- check elements if table.getn(elements) < 1 then print (error_msg .. 'no elements found.') return '' end -- parse elements to add them to result local text_elements = '' for k, v in pairs(elements) do text_elements = text_elements .. v end -- do substitutions on result local result = replace(template_categ, {CATEG_TITLE=categ_title, CATEG_DESC=categ_description, ELEMENTS=text_elements}) return result end --[[ Principal ]]-- -- fetch user defined values config = getConfig(configFile) -- create values for directories categ = config['CATEGORIES'] or default_dir_category component = config['COMPONENTS'] or default_dir_component destination = config['DESTINATION'] or default_dir_destination img_destination = config['IMAGE_DESTINATION'] or default_dir_img_destination img_source = config['IMAGES'] or default_dir_img_source css_source = config['CSS'] or default_dir_css_source -- create values for files index_filename = config['INDEX'] or default_index_filename main_template = config['TEMPLATE_INDEX'] or default_template_index_filename template_categ_filename = config['TEMPLATE_CATEG'] or default_template_categ_filename template_element_filename = config['TEMPLATE_ELEMENT'] or default_template_element_filename default_img = config['DEFAULT_IMG'] or default_img_filename css_filename = config['STYLE'] or default_css_filename css_menu = default_css_menu_without local menu = config['MENU'] or '' if config['MENU'] then css_menu = default_css_menu_with end local introduction = config['INTRO'] or '' -- other default values categ_extension = config['CATEGORIES_EXT'] or default_categ_extension css_name = config['CSS_NAME'] or default_css_name -- get pages index = readFile(currentpath .. '/' .. component .. '/' .. index_filename, 'r') template_categ = readFile(currentpath .. '/' .. component .. '/' .. template_categ_filename, 'r') template_element = readFile(currentpath .. '/' .. component .. '/' .. template_element_filename, 'r') -- open menu file if menu have been activated local menu_content = '' if menu ~= '' then menu_content = readFile(component .. '/' .. menu, 'r') end -- open introduction file if intro have been activated local introduction_content = '' if introduction ~= '' then introduction_content = readFile(component .. '/' .. introduction, 'r') end -- Check if public and image directory exists for i, dir in pairs({destination, destination .. '/' .. img_destination}) do if lfs.attributes(dir) == nil then assert(lfs.mkdir(dir)) end end -- Browse categ directory local categories_files = listing (currentpath .. '/' .. categ, categ_extension) -- sort table in order to show categories in the alphabetical order table.sort(categories_files) local content = '' if categories_files then for k,v in pairs(categories_files) do -- read category content attr = lfs.attributes(v) if attr and attr.mode == 'file' then content = content .. process(v, template_categ, template_element, img_destination, destination, img_source, default_img) end end else print ("-- No category file found!") end -- Create index file in destination directory index_result = assert(io.open(destination .. '/' .. main_template, 'wb')) -- create substitution table substitutions = { TITLE=config['HOMEPAGE'] or (config['TITLE'] and config['TITLE'] .. default_homepage_title) or (default_title .. default_homepage_title), PORTEAIL_TITLE=config['TITLE'] or default_title, CONTENT=content, INTRODUCTION=introduction_content, MENU=menu_content, CSS_COLOR=css_filename, CSS_NAME=css_name, DEFAULT_CSS=css_menu, VERSION=version, } -- Get language configuration language = config['LANG'] or default_language languagerc = getConfig(default_dir_lang .. '/' .. language) -- Add language translation to replacements table for k, v in pairs(languagerc) do substitutions[k] = v end -- replace variables in result homepage = replace(index, substitutions) assert(index_result:write(homepage)) -- close file assert(index_result:close()) -- Copy miscellaneous files to destination to_be_copied = { component .. '/' .. 'html5.js', css_source .. '/' .. css_filename, css_source .. '/' .. css_menu, } for i, filepath in pairs(to_be_copied) do fileattr = lfs.attributes(filepath) if not fileattr or fileattr.mode ~= 'file' then print (filepath .. " doesn't exist or is not a file!") os.exit(1) end dest = destination .. '/' .. basename(filepath) filecontent = readFile(filepath, 'r') destfile = assert(io.open(dest, 'wb')) assert(destfile:write(filecontent)) assert(destfile:close()) end --[[ END ]]--