Class: Hugo
Instance Method Summary collapse
- #delete_note(note, fname) ⇒ Object
-
#initialize(opts = {}) ⇒ Hugo
constructor
A new instance of Hugo.
- #output_note(note) ⇒ Object
- #set_static_dirs(note) ⇒ Object
Constructor Details
#initialize(opts = {}) ⇒ Hugo
Returns a new instance of Hugo.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/output/hugo.rb', line 16 def initialize(opts = {}) @opts = opts @base_dir = opts['base_dir'] unless @base_dir error "The 'base_dir' option of the Hugo plugin must be set!" end @use_filters = opts['use_filters'] || true @rebuild_all = opts['rebuild_all'] || false # Persistent store for this base_dir datadir = "#{@base_dir}/data" FileUtils.mkdir_p datadir @config_store = YAML::Store.new("#{datadir}/enwrite_data.yaml") # Initialize GUID-to-filename map if needed @config_store.transaction { @config_store[:note_files] = {} unless @config_store[:note_files] } # These are [ realpath, urlpath ] @static_dir = [ "#{@base_dir}/#{opts['static_subdir'] || 'static' }", opts['static_url'] || "" ] @static_subdirs = { 'image' => opts['image_subdir'] || 'img', 'audio' => opts['audio_subdir'] || 'audio', 'video' => opts['video_subdir'] || 'video', 'files' => opts['files_subdir'] || 'files', } # Tag-to-type map @tag_to_type = opts['tag_to_type'] || { "default" => "post/", "post" => "post/", "page" => "" } @tag_to_type_order = opts['tag_to_type_order'] || [ "post", "page", "default" ] @tag_to_type_order.each { |type| @tag_to_type[type] = "" unless @tag_to_type.include?(type) @tag_to_type[type] = "" if @tag_to_type[type].nil? } # Markdown tag @markdown_tag = opts['markdown_tag'] || "markdown" # Command to run hugo @hugo_cmd = opts['hugo_cmd'] || "hugo" end |
Instance Method Details
#delete_note(note, fname) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/output/hugo.rb', line 69 def delete_note(note, fname) set_static_dirs(note) if File.exist?(fname) msg " This note has been deleted from Evernote, deleting its file #{fname}" File.delete(fname) end if Dir.exist?(@static_dirs['note'][0]) msg " Deleting static files for deleted note #{@static_dirs['note'][0]}" FileUtils.rmtree(@static_dirs['note'][0]) end end |
#output_note(note) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/output/hugo.rb', line 82 def output_note(note) set_static_dirs(note) msg "Found note '#{note.title}'" verbose "Created: #{Time.at(note.created/1000)}" if note.created verbose "Deleted: #{Time.at(note.deleted/1000)}" if note.deleted verbose "Content length: #{note.contentLength}" if note.contentLength verbose "Clipped from: #{note.attributes.sourceURL}" if note.attributes.sourceURL markdown = note.tagNames.include?(@markdown_tag) if markdown msg " It has the '#{ @markdown_tag }' tag, so I will interpret it as markdown" note.tagNames -= [ @markdown_tag ] end type = nil # Detect the type of post according to its tags @tag_to_type_order.each do |tag| if note.tagNames.include?(tag) or tag == "default" type = @tag_to_type[tag] break end end if type.nil? error " ### I couldn't determine the type for this post - skipping it" return end # Determine if we should add custom frontmatter custom_fm = {} note.tagNames.grep(/^_(\S+)=(.*)/) do |tag| custom_fm[$1] = $2 note.tagNames -= [ tag ] verbose " Will use custom frontmatter entry for this post: #{$1} = #{custom_fm[$1]}" end # Get our note GUID-to-filename map note_files = config(:note_files, {}, @config_store) # Determine the name I would assign to this note when published to Hugo date = Time.at(note.created/1000).strftime('%F') post_filename = "#{type}#{date}-#{note.title}.#{markdown ? 'md' : 'html'}" # Do we already have a post for this note (by GUID)? If so, we remove the # old file since it will be regenerated anyway, which also takes care of the # case when the note was renamed and the filename will change, to avoid # post duplication. If the note has been deleted, we just delete the # old filename and stop here. oldfile = note_files[note.guid] if oldfile verbose " I already had a file for note #{note.guid}, removing #{oldfile}" File.delete(oldfile) if File.exist?(oldfile) note_files.delete(note.guid) setconfig(:note_files, note_files, @config_store) if note.deleted delete_note(note, oldfile) return end end # Run hugo to create the file, then read it back it to update the front matter # with our tags. # We run "hugo new" also for deleted notes so that hugo gives us the filename # to delete. fname = nil frontmatter = nil Dir.chdir(@base_dir) do # Force -f yaml because it's so much easier to process while true post_filename.gsub!(/"/, '\"') cmd = %Q(#{@hugo_cmd} new "#{post_filename}" 2>&1) debug "Executing: #{cmd}" output = %x(#{cmd}) if output =~ /^(.+) created$/ # Get the full filename as reported by Hugo fname = $1 if note.deleted delete_note(note, fname) return end # Load the frontmatter frontmatter = YAML.load_file(fname) # Update title because Hugo gets it wrong sometimes depending on the characters in the title, and to get rid of the date we put in the filename frontmatter['title'] = note.title # Fix the date to the date when the note was created frontmatter['date'] = date # Update tags, for now set categories to the same frontmatter['tags'] = note.tagNames frontmatter['categories'] = note.tagNames # Set custom frontmatter custom_fm.each do |k,v| frontmatter[k] = v end # Set slug to work around https://github.com/spf13/hugo/issues/1017 frontmatter['slug'] = custom_fm['slug'] ? custom_fm['slug'] : note.title.downcase.gsub(/\W+/, "-").gsub(/^-+/, "").gsub(/-+$/, "") break elsif output =~ /ERROR: \S+ (.+) already exists/ # Get the full filename as reported by Hugo fname = $1 # If the file existed already, remove it and regenerate it File.delete(fname) if note.deleted delete_note(note, fname) return end # This shouldn't happen due to the index check above unless @rebuild_all error " I found a file that should not be there (#{fname}). This might indicate" error " an inconsistency in my internal note-to-file map. Please re-run with" error " --rebuild-all to regenerate it. I am deleting the file and continuing" error " for now, but please review the results carefully." end redo else error " Hugo returned unknown output when trying to create this post - skipping it: #{output}" return end end end debug "Updated frontmatter: #{frontmatter.to_s}" File.open(fname, "w") do |f| f.write(frontmatter.to_yaml) f.puts("---") f.puts enml = ENML_utils.new(note.content, note.resources, @static_dirs, note.guid) output = markdown ? enml.to_text : enml.to_html if @use_filters verbose "Running filters on text" output = run_filters(output) end if note.attributes.sourceURL f.puts(%(<p class="clip-attribute">via <a href="#{note.attributes.sourceURL}">#{note.attributes.sourceURL}</a></p>)) end f.puts(output) enml.resource_files.each do |resfile| FileUtils.mkdir_p File.dirname(resfile[:fname]) File.open(resfile[:fname], "w") do |r| r.write(resfile[:data]) end verbose "Wrote file #{resfile[:fname]}" end end verbose "Wrote file #{fname}" note_files[note.guid] = fname setconfig(:note_files, note_files, @config_store) end |
#set_static_dirs(note) ⇒ Object
59 60 61 62 63 64 65 66 67 |
# File 'lib/output/hugo.rb', line 59 def set_static_dirs(note) @static_dirs = {} @static_dirs['note'] = [ "#{@static_dir[0]}/note/#{note.guid}", "#{@static_dir[1]}/note/#{note.guid}" ] ['image', 'audio', 'video', 'files']. each do |type| @static_dirs[type] = [ "#{@static_dirs['note'][0]}/#{@static_subdirs[type]}", # full path "#{@static_dirs['note'][1]}/#{@static_subdirs[type]}" ]; # url path end end |