diff --git a/.gitignore b/.gitignore index 1bc95092..d1f1f8c5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ bbin/ gh-pages/ site/_site/ coverage +.ruby-version diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 74f5f164..00000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -1.9.3-p362 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3135baf4..5245c868 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,7 @@ following in mind: * If your contribution changes any Jekyll behavior, make sure to update the documentation. It lives in site/_posts. If the docs are missing information, please feel free to add it in. Great docs make a great project! +* Please follow the [Github Ruby Styleguide](https://github.com/styleguide/ruby) when modifying Ruby code. Test Dependencies ----------------- diff --git a/Gemfile b/Gemfile index e45e65f8..851fabc2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,2 +1,2 @@ -source :rubygems +source 'https://rubygems.org' gemspec diff --git a/History.txt b/History.txt index 3d1f567e..18c26a0a 100644 --- a/History.txt +++ b/History.txt @@ -1,7 +1,22 @@ == HEAD * Major Enhancements * Refactored jekyll commands into subcommands: build, serve, and migrate. (#690) + * Removed importers/migrators from main project, migrated to jekyll-import sub-gem (#793) + * Added ability to render drafts in _drafts folder via command line (#833) * Minor Enhancements + * Accept custom configuration file via CLI (#863) + * Load in Apache MIME Types on `jekyll serve` (#847) + * Improve debugability of error message for a malformed highlight tag (#785) + * Allow symlinked files in unsafe mode (#824) + * Add 'gist' liquid tag to core (#822) + * New format of Jekyll output (#795) + * Reinstate --limit_posts and --future switches (#788) + * Remove ambiguity from command descriptions (#815) + * Fix SafeYAML Warnings (#807) + * Relaxed Kramdown version to 0.14 (#808) + * Aliased `jekyll server` to `jekyll serve`. (#792) + * Updated gem versions for Kramdown, Rake, Shoulda, Cucumber, and RedCarpet. (#744) + * Refactored jekyll subcommands into Jekyll::Commands submodule, which now contains them (#768) * Rescue from import errors in Wordpress.com migrator (#671) * Massively accelerate LSI performance (#664) * Truncate post slugs when importing from Tumblr (#496) @@ -12,16 +27,26 @@ * Add source and destination directory protection (#535) * Better YAML error message (#718) * Bug Fixes + * Patch for multibyte URI problem with jekyll serve (#723) + * Order plugin execution by priority (#864) + * Fixed Page#dir and Page#url for edge cases (#536) + * Fix broken post_url with posts with a time in their YAML Front-Matter (#831) + * Look for plugins under the source directory (#654) * Tumblr Migrator: finds _posts dir correctly, fixes truncation of long post names (#775) * Force Categories to be Strings (#767) * Safe YAML plugin to prevent vulnerability (#777) * Add SVG support to Jekyll/WEBrick. (#407, #406) - * Prevent custom destination from causing continuous regen (#528) + * Prevent custom destination from causing continuous regen on watch (#528, #820) * Site Enhancements * Bring site into master branch with better preview/deploy (#709) * Redesigned site (#583) * Development fixes + * Added "features:html" rake task for debugging purposes, cleaned up + cucumber profiles (#832) + * Explicitly require HTTPS rubygems source in Gemfile (#826) + * Changed Ruby version for development to 1.9.3-p374 from p362 (#801) + * Including a link to the GitHub Ruby style guide in CONTRIBUTING.md (#806) * Added script/bootstrap (#776) * Running Simplecov under 2 conditions: ENV(COVERAGE)=true and with Ruby version of greater than 1.9 (#771) diff --git a/README.textile b/README.textile index 80ca6220..6ce392a8 100644 --- a/README.textile +++ b/README.textile @@ -21,6 +21,7 @@ h2. Diving In * Put information on your site with "Template Data":http://wiki.github.com/mojombo/jekyll/template-data * Customize the "Permalinks":http://wiki.github.com/mojombo/jekyll/permalinks your posts are generated with * Use the built-in "Liquid Extensions":http://wiki.github.com/mojombo/jekyll/liquid-extensions to make your life easier +* Use custom "Plugins":http://wiki.github.com/mojombo/jekyll/Plugins to generate content specific to your site h2. Runtime Dependencies diff --git a/Rakefile b/Rakefile index 9504dc1d..3b41504f 100644 --- a/Rakefile +++ b/Rakefile @@ -63,36 +63,13 @@ Rake::RDocTask.new do |rdoc| rdoc.rdoc_files.include('lib/**/*.rb') end -desc "Open an irb session preloaded with this library" -task :console do - sh "irb -rubygems -r ./lib/#{name}.rb" -end - -############################################################################# -# -# Custom tasks (add your own tasks here) -# -############################################################################# - -namespace :migrate do - desc "Migrate from mephisto in the current directory" - task :mephisto do - sh %q(ruby -r './lib/jekyll/migrators/mephisto' -e 'Jekyll::Mephisto.postgres(:database => "#{ENV["DB"]}")') - end - desc "Migrate from Movable Type in the current directory" - task :mt do - sh %q(ruby -r './lib/jekyll/migrators/mt' -e 'Jekyll::MT.process("#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")') - end - desc "Migrate from Typo in the current directory" - task :typo do - sh %q(ruby -r './lib/jekyll/migrators/typo' -e 'Jekyll::Typo.process("#{ENV["DB"]}", "#{ENV["USER"]}", "#{ENV["PASS"]}")') - end -end - begin require 'cucumber/rake/task' Cucumber::Rake::Task.new(:features) do |t| - t.cucumber_opts = "--format progress" + t.profile = "travis" + end + Cucumber::Rake::Task.new(:"features:html", "Run Cucumber features and produce HTML output") do |t| + t.profile = "html_report" end rescue LoadError desc 'Cucumber rake task not available' @@ -101,6 +78,11 @@ rescue LoadError end end +desc "Open an irb session preloaded with this library" +task :console do + sh "irb -rubygems -r ./lib/#{name}.rb" +end + ############################################################################# # # Site tasks - http://jekyllrb.com diff --git a/bin/jekyll b/bin/jekyll index 6c3577c5..02c364cf 100755 --- a/bin/jekyll +++ b/bin/jekyll @@ -16,6 +16,19 @@ global_option '-d', '--destination [DIR]', 'Destination directory (defaults to . global_option '--safe', 'Safe mode (defaults to false)' global_option '--plugins', 'Plugins directory (defaults to ./_plugins)' global_option '--layouts', 'Layouts directory (defaults to ./_layouts)' + +# Option names don't always directly match the configuration value we'd like. +# This method will rename options to match what Jekyll configuration expects. +# +# options - The Hash of options from Commander. +# +# Returns the normalized Hash. +def normalize_options(options) + if drafts_state = options.delete(:drafts) + options[:show_drafts] = drafts_state + end + options +end command :new do |c| c.syntax = 'jekyll new PATH' @@ -28,24 +41,33 @@ end command :build do |c| c.syntax = 'jekyll build [options]' - c.description = 'Build your site with the option of auto-renegeration' + c.description = 'Build your site' + c.option '--config [CONFIG_FILE]', 'Custom configuration file' + c.option '--future', 'Publishes posts with a future date' + c.option '--limit_posts MAX_POSTS', 'Limits the number of posts to parse and publish' c.option '-w', '--watch', 'Watch for changes and rebuild' c.option '--lsi', 'Use LSI for improved related posts' + c.option '--drafts', 'Render posts in the _drafts folder' c.action do |args, options| options.defaults :serving => false - options = Jekyll.configuration(options.__hash__) + options = normalize_options(options.__hash__) + options = Jekyll.configuration(options) Jekyll::Commands::Build.process(options) end end command :serve do |c| c.syntax = 'jekyll serve [options]' - c.description = 'Serve your site locally with the option of auto-regeneration' + c.description = 'Serve your site locally' + c.option '--config [CONFIG_FILE]', 'Custom configuration file' + c.option '--future', 'Publishes posts with a future date' + c.option '--limit_posts MAX_POSTS', 'Limits the number of posts to parse and publish' c.option '-w', '--watch', 'Watch for changes and rebuild' c.option '--lsi', 'Use LSI for improved related posts' + c.option '--drafts', 'Render posts in the _drafts folder' c.option '-p', '--port [PORT]', 'Port to listen on' c.option '-h', '--host [HOST]', 'Host to bind to' @@ -57,16 +79,19 @@ command :serve do |c| :baseurl => '/', :serving => true - options = Jekyll.configuration(options.__hash__) + options = normalize_options(options.__hash__) + options = Jekyll.configuration(options) Jekyll::Commands::Build.process(options) Jekyll::Commands::Serve.process(options) end end +alias_command :server, :serve command :import do |c| c.syntax = 'jekyll import [options]' c.description = 'Import your old blog to Jekyll' + c.option '--source', 'Source file or URL to migrate from' c.option '--file', 'File to migrate from' c.option '--dbname', 'Database name to migrate from' c.option '--user', 'Username to use when migrating' @@ -74,6 +99,14 @@ command :import do |c| c.option '--host', 'Host address to use when migrating' c.action do |args, options| - Jekyll::Commands::Migrate.process(args.first, options) + begin + require 'jekyll-import' + rescue LoadError + msg = "You must install the 'jekyll-import' gem before continuing.\n" + msg += "* Do this by running `gem install jekyll-import`.\n" + msg += "* Or if you need root privileges, run `sudo gem install jekyll-import`." + abort msg + end + Jekyll::Commands::Import.process(args.first, options) end end diff --git a/cucumber.yml b/cucumber.yml index ff1d0580..78342a17 100644 --- a/cucumber.yml +++ b/cucumber.yml @@ -1,2 +1,3 @@ -default: --format progress +default: --format pretty +travis: --format progress html_report: --format progress --format html --out=features_report.html diff --git a/features/create_sites.feature b/features/create_sites.feature index 438ee358..cbdfb64b 100644 --- a/features/create_sites.feature +++ b/features/create_sites.feature @@ -89,7 +89,7 @@ Feature: Create sites And I have an "_includes/about.textile" file that contains "Generated by {% include jekyll.textile %}" And I have an "_includes/jekyll.textile" file that contains "Jekyll" And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}" - When I debug jekyll + When I run jekyll Then the _site directory should exist And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/index.html" diff --git a/features/drafts.feature b/features/drafts.feature new file mode 100644 index 00000000..27832fc4 --- /dev/null +++ b/features/drafts.feature @@ -0,0 +1,25 @@ +Feature: Draft Posts + As a hacker who likes to blog + I want to be able to preview drafts locally + In order to see if they look alright before publishing + + Scenario: Preview a draft + Given I have a configuration file with "permalink" set to "none" + And I have a _drafts directory + And I have the following draft: + | title | date | layout | content | + | Recipe | 3/27/2009 | default | Not baked yet. | + When I run jekyll with drafts + Then the _site directory should exist + And I should see "Not baked yet." in "_site/recipe.html" + + Scenario: Don't preview a draft + Given I have a configuration file with "permalink" set to "none" + And I have an "index.html" page that contains "Totally index" + And I have a _drafts directory + And I have the following draft: + | title | date | layout | content | + | Recipe | 3/27/2009 | default | Not baked yet. | + When I run jekyll + Then the _site directory should exist + And the "_site/recipe.html" file should not exist diff --git a/features/site_configuration.feature b/features/site_configuration.feature index b9a082fa..c07a3c73 100644 --- a/features/site_configuration.feature +++ b/features/site_configuration.feature @@ -3,7 +3,7 @@ Feature: Site configuration I want to be able to configure jekyll In order to make setting up a site easier - Scenario: Change destination directory + Scenario: Change source directory Given I have a blank site in "_sourcedir" And I have an "_sourcedir/index.html" file that contains "Changing source directory" And I have a configuration file with "source" set to "_sourcedir" diff --git a/features/step_definitions/jekyll_steps.rb b/features/step_definitions/jekyll_steps.rb index 20128964..1b0eb519 100644 --- a/features/step_definitions/jekyll_steps.rb +++ b/features/step_definitions/jekyll_steps.rb @@ -50,9 +50,8 @@ Given /^I have an? (.*) directory$/ do |dir| FileUtils.mkdir_p(dir) end -Given /^I have the following posts?(?: (.*) "(.*)")?:$/ do |direction, folder, table| +Given /^I have the following (draft|post)s?(?: (.*) "(.*)")?:$/ do |status, direction, folder, table| table.hashes.each do |post| - date = Date.strptime(post['date'], '%m/%d/%Y').strftime('%Y-%m-%d') title = post['title'].downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-') if direction && direction == "in" @@ -61,7 +60,14 @@ Given /^I have the following posts?(?: (.*) "(.*)")?:$/ do |direction, folder, t after = folder || '.' end - path = File.join(before || '.', '_posts', after || '.', "#{date}-#{title}.#{post['type'] || 'textile'}") + ext = post['type'] || 'textile' + + if "draft" == status + path = File.join(before || '.', '_drafts', after || '.', "#{title}.#{ext}") + else + date = Date.strptime(post['date'], '%m/%d/%Y').strftime('%Y-%m-%d') + path = File.join(before || '.', '_posts', after || '.', "#{date}-#{title}.#{ext}") + end matter_hash = {} %w(title layout tag tags category categories published author).each do |key| @@ -117,6 +123,10 @@ When /^I run jekyll$/ do run_jekyll end +When /^I run jekyll with drafts$/ do + run_jekyll(:drafts => true) +end + When /^I debug jekyll$/ do run_jekyll(:debug => true) end diff --git a/features/support/env.rb b/features/support/env.rb index 1ed330a1..7e550c6c 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -10,8 +10,9 @@ TEST_DIR = File.join('/', 'tmp', 'jekyll') JEKYLL_PATH = File.join(ENV['PWD'], 'bin', 'jekyll') def run_jekyll(opts = {}) - command = JEKYLL_PATH + command = JEKYLL_PATH.clone command << " build" + command << " --drafts" if opts[:drafts] command << " >> /dev/null 2>&1" if opts[:debug].nil? system command end diff --git a/jekyll.gemspec b/jekyll.gemspec index a6efcd62..b3250899 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -4,9 +4,9 @@ Gem::Specification.new do |s| s.rubygems_version = '1.3.5' s.name = 'jekyll' - s.version = '0.12.0' + s.version = '1.0.0.beta1' s.license = 'MIT' - s.date = '2012-12-22' + s.date = '2013-03-14' s.rubyforge_project = 'jekyll' s.summary = "A simple, blog aware, static site generator." @@ -27,31 +27,26 @@ Gem::Specification.new do |s| s.add_runtime_dependency('classifier', "~> 1.3") s.add_runtime_dependency('directory_watcher', "~> 1.1") s.add_runtime_dependency('maruku', "~> 0.5") - s.add_runtime_dependency('kramdown', "~> 0.13.4") + s.add_runtime_dependency('kramdown', "~> 0.14") s.add_runtime_dependency('pygments.rb', "~> 0.3.2") s.add_runtime_dependency('commander', "~> 4.1.3") s.add_runtime_dependency('safe_yaml', "~> 0.7.0") - s.add_development_dependency('rake', "~> 0.9") + s.add_development_dependency('rake', "~> 10.0.3") s.add_development_dependency('rdoc', "~> 3.11") s.add_development_dependency('redgreen', "~> 1.2") - s.add_development_dependency('shoulda', "~> 2.11") + s.add_development_dependency('shoulda', "~> 3.3.2") s.add_development_dependency('rr', "~> 1.0") - s.add_development_dependency('cucumber', "1.1") + s.add_development_dependency('cucumber', "~> 1.2.1") s.add_development_dependency('RedCloth', "~> 4.2") s.add_development_dependency('rdiscount', "~> 1.6") - s.add_development_dependency('redcarpet', "~> 2.1.1") + s.add_development_dependency('redcarpet', "~> 2.2.2") s.add_development_dependency('launchy', "~> 2.1.2") s.add_development_dependency('simplecov', "~> 0.7") s.add_development_dependency('simplecov-gem-adapter', "~> 1.0.1") - # migrator dependencies: - s.add_development_dependency('sequel', "~> 3.42") - s.add_development_dependency('htmlentities', "~> 4.3") - s.add_development_dependency('hpricot', "~> 0.8") # = MANIFEST = s.files = %w[ - .travis.yml CONTRIBUTING.md Gemfile History.txt @@ -61,6 +56,7 @@ Gem::Specification.new do |s| bin/jekyll cucumber.yml features/create_sites.feature + features/drafts.feature features/embed_filters.feature features/markdown.feature features/pagination.feature @@ -74,8 +70,11 @@ Gem::Specification.new do |s| lib/jekyll.rb lib/jekyll/command.rb lib/jekyll/commands/build.rb +<<<<<<< HEAD lib/jekyll/commands/migrate.rb lib/jekyll/commands/new.rb +======= +>>>>>>> master lib/jekyll/commands/serve.rb lib/jekyll/converter.rb lib/jekyll/converters/identity.rb @@ -83,33 +82,23 @@ Gem::Specification.new do |s| lib/jekyll/converters/textile.rb lib/jekyll/convertible.rb lib/jekyll/core_ext.rb + lib/jekyll/draft.rb lib/jekyll/errors.rb lib/jekyll/filters.rb lib/jekyll/generator.rb lib/jekyll/generators/pagination.rb lib/jekyll/layout.rb - lib/jekyll/migrators/csv.rb - lib/jekyll/migrators/drupal.rb - lib/jekyll/migrators/enki.rb - lib/jekyll/migrators/joomla.rb - lib/jekyll/migrators/marley.rb - lib/jekyll/migrators/mephisto.rb - lib/jekyll/migrators/mt.rb - lib/jekyll/migrators/posterous.rb - lib/jekyll/migrators/rss.rb - lib/jekyll/migrators/textpattern.rb - lib/jekyll/migrators/tumblr.rb - lib/jekyll/migrators/typo.rb - lib/jekyll/migrators/wordpress.rb - lib/jekyll/migrators/wordpressdotcom.rb + lib/jekyll/mime.types lib/jekyll/page.rb lib/jekyll/plugin.rb lib/jekyll/post.rb lib/jekyll/site.rb lib/jekyll/static_file.rb + lib/jekyll/tags/gist.rb lib/jekyll/tags/highlight.rb lib/jekyll/tags/include.rb lib/jekyll/tags/post_url.rb +<<<<<<< HEAD lib/site_template/_config.yml lib/site_template/_layouts/default.html lib/site_template/_layouts/post.html @@ -119,9 +108,62 @@ Gem::Specification.new do |s| lib/site_template/images/.gitkeep lib/site_template/images/rss.png lib/site_template/index.html +======= + script/bootstrap + site/.gitignore + site/CNAME + site/README + site/_config.yml + site/_includes/analytics.html + site/_includes/docs_contents.html + site/_includes/footer.html + site/_includes/header.html + site/_includes/section_nav.html + site/_includes/top.html + site/_layouts/default.html + site/_layouts/docs.html + site/_posts/2012-07-01-configuration.md + site/_posts/2012-07-01-contributing.md + site/_posts/2012-07-01-deployment-methods.md + site/_posts/2012-07-01-extras.md + site/_posts/2012-07-01-frontmatter.md + site/_posts/2012-07-01-github-pages.md + site/_posts/2012-07-01-heroku.md + site/_posts/2012-07-01-home.md + site/_posts/2012-07-01-installation.md + site/_posts/2012-07-01-migrations.md + site/_posts/2012-07-01-pages.md + site/_posts/2012-07-01-pagination.md + site/_posts/2012-07-01-permalinks.md + site/_posts/2012-07-01-plugins.md + site/_posts/2012-07-01-posts.md + site/_posts/2012-07-01-resources.md + site/_posts/2012-07-01-sites.md + site/_posts/2012-07-01-structure.md + site/_posts/2012-07-01-templates.md + site/_posts/2012-07-01-troubleshooting.md + site/_posts/2012-07-01-usage.md + site/_posts/2012-07-01-variables.md + site/css/grid.css + site/css/normalize.css + site/css/pygments.css + site/css/style.css + site/docs/index.html + site/favicon.png + site/img/article-footer.png + site/img/footer-arrow.png + site/img/footer-logo.png + site/img/logo-2x.png + site/img/octojekyll.png + site/img/tube.png + site/img/tube1x.png + site/index.html + site/js/modernizr-2.5.3.min.js +>>>>>>> master test/fixtures/broken_front_matter1.erb test/fixtures/broken_front_matter2.erb test/fixtures/broken_front_matter3.erb + test/fixtures/exploit_front_matter.erb test/fixtures/front_matter.erb test/helper.rb test/source/.htaccess @@ -153,9 +195,13 @@ Gem::Specification.new do |s| test/source/_posts/2010-01-16-override-data.textile test/source/_posts/2011-04-12-md-extension.md test/source/_posts/2011-04-12-text-extension.text + test/source/_posts/2013-01-12-nil-layout.textile + test/source/_posts/2013-01-12-no-layout.textile test/source/about.html test/source/category/_posts/2008-9-23-categories.textile test/source/contacts.html + test/source/contacts/bar.html + test/source/contacts/index.html test/source/css/screen.css test/source/deal.with.dots.html test/source/foo/_posts/bar/2008-12-12-topical-post.textile diff --git a/lib/jekyll.rb b/lib/jekyll.rb index 2c1ab0e6..6e489264 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -33,6 +33,7 @@ require 'jekyll/convertible' require 'jekyll/layout' require 'jekyll/page' require 'jekyll/post' +require 'jekyll/draft' require 'jekyll/filters' require 'jekyll/static_file' require 'jekyll/errors' @@ -48,16 +49,17 @@ require_all 'jekyll/converters' require_all 'jekyll/generators' require_all 'jekyll/tags' +SafeYAML::OPTIONS[:suppress_warnings] = true + module Jekyll - VERSION = '0.12.0' + VERSION = '1.0.0.beta1' # Default options. Overriden by values in _config.yml. # Strings rather than symbols are used for compatability with YAML. DEFAULTS = { 'source' => Dir.pwd, 'destination' => File.join(Dir.pwd, '_site'), - - 'plugins' => File.join(Dir.pwd, '_plugins'), + 'plugins' => '_plugins', 'layouts' => '_layouts', 'keep_files' => ['.git','.svn'], @@ -127,16 +129,23 @@ module Jekyll # then, we need to know where to look for _config.yml source = override['source'] || Jekyll::DEFAULTS['source'] - # Get configuration from /_config.yml - config_file = File.join(source, '_config.yml') + # Get configuration from /_config.yml or / + config_file = override.delete('config') + config_file = File.join(source, "_config.yml") if config_file.to_s.empty? + begin - config = YAML.load_file(config_file) - raise "Invalid configuration - #{config_file}" if !config.is_a?(Hash) - $stdout.puts "Configuration from #{config_file}" + config = YAML.safe_load_file(config_file) + raise "Configuration file: (INVALID) #{config_file}" if !config.is_a?(Hash) + $stdout.puts "Configuration file: #{config_file}" + rescue SystemCallError + # Errno:ENOENT = file not found + $stderr.puts "Configuration file: none" + config = {} rescue => err - $stderr.puts "WARNING: Could not read configuration. " + + $stderr.puts " " + + "WARNING: Error reading configuration. " + "Using defaults (and options)." - $stderr.puts "\t" + err.to_s + $stderr.puts "#{err}" config = {} end diff --git a/lib/jekyll/command.rb b/lib/jekyll/command.rb index f7f0fa6b..bbc9e8a6 100644 --- a/lib/jekyll/command.rb +++ b/lib/jekyll/command.rb @@ -1,9 +1,9 @@ module Jekyll class Command - def self.globs(source) + def self.globs(source, destination) Dir.chdir(source) do dirs = Dir['*'].select { |x| File.directory?(x) } - dirs -= ['_site'] + dirs -= [destination] dirs = dirs.map { |x| "#{x}/**/*" } dirs += ['*'] end diff --git a/lib/jekyll/commands/build.rb b/lib/jekyll/commands/build.rb index 0bb3c4f1..181316d2 100644 --- a/lib/jekyll/commands/build.rb +++ b/lib/jekyll/commands/build.rb @@ -23,7 +23,9 @@ module Jekyll def self.build(site, options) source = options['source'] destination = options['destination'] - puts "Building site: #{source} -> #{destination}" + puts " Source: #{source}" + puts " Destination: #{destination}" + print " Generating... " begin site.process rescue Jekyll::FatalException => e @@ -33,7 +35,7 @@ module Jekyll puts e.message exit(1) end - puts "Successfully generated site: #{source} -> #{destination}" + puts "done." end # Private: Watch for file changes and rebuild the site. @@ -48,23 +50,26 @@ module Jekyll source = options['source'] destination = options['destination'] - puts "Auto-Regenerating enabled: #{source} -> #{destination}" + puts " Source: #{source}" + puts " Destination: #{destination}" + puts " Auto-regeneration: enabled" dw = DirectoryWatcher.new(source) dw.interval = 1 - dw.glob = self.globs(source) + dw.glob = self.globs(source, destination) dw.add_observer do |*args| t = Time.now.strftime("%Y-%m-%d %H:%M:%S") - puts "[#{t}] regeneration: #{args.size} files changed" + print " Regenerating: #{args.size} files at #{t} " site.process + puts "...done." end dw.start unless options['serving'] trap("INT") do - puts "Stopping auto-regeneration..." + puts " Halting auto-regeneration." exit 0 end diff --git a/lib/jekyll/commands/migrate.rb b/lib/jekyll/commands/migrate.rb deleted file mode 100644 index 21c49037..00000000 --- a/lib/jekyll/commands/migrate.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Jekyll - module Commands - class Migrate < Command - MIGRATORS = { - :csv => 'CSV', - :drupal => 'Drupal', - :enki => 'Enki', - :mephisto => 'Mephisto', - :mt => 'MT', - :posterous => 'Posterous', - :textpattern => 'TextPattern', - :tumblr => 'Tumblr', - :typo => 'Typo', - :wordpressdotcom => 'WordpressDotCom', - :wordpress => 'WordPress' - } - - def self.process(migrator, options) - abort 'missing argument. Please specify a migrator' if migrator.nil? - migrator = migrator.downcase - - cmd_options = [] - [ :file, :dbname, :user, :pass, :host, :site ].each do |p| - cmd_options << "\"#{options[p]}\"" unless options[p].nil? - end - - - if MIGRATORS.keys.include?(migrator) - app_root = File.expand_path( - File.join(File.dirname(__FILE__), '..', '..', '..') - ) - - require "#{app_root}/lib/jekyll/migrators/#{migrator}" - - if Jekyll.const_defiend?(MIGRATORS[migrator.to_sym]) - puts 'Importing...' - migrator_class = Jekyll.const_get(MIGRATORS[migrator.to_sym]) - migrator_class.process(*cmd_options) - exit 0 - end - end - - abort 'invalid migrator. Please specify a valid migrator' - end - end - end -end diff --git a/lib/jekyll/commands/serve.rb b/lib/jekyll/commands/serve.rb index 4ced4fce..ae28665b 100644 --- a/lib/jekyll/commands/serve.rb +++ b/lib/jekyll/commands/serve.rb @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- module Jekyll module Commands class Serve < Command @@ -9,9 +10,12 @@ module Jekyll FileUtils.mkdir_p(destination) - mime_types = WEBrick::HTTPUtils::DefaultMimeTypes - mime_types.store 'js', 'application/javascript' - mime_types.store 'svg', 'image/svg+xml' + mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__)) + mime_types = WEBrick::HTTPUtils::load_mime_types(mime_types_file) + + # recreate NondisclosureName under utf-8 circumstance + fh_option = WEBrick::Config::FileHandler + fh_option[:NondisclosureName] = ['.ht*','~*'] s = HTTPServer.new( :Port => options['port'], @@ -19,7 +23,7 @@ module Jekyll :MimeTypes => mime_types ) - s.mount(options['baseurl'], HTTPServlet::FileHandler, destination) + s.mount(options['baseurl'], HTTPServlet::FileHandler, destination, fh_option) t = Thread.new { s.start } trap("INT") { s.shutdown } t.join() diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb index e71fe1bf..952fd670 100644 --- a/lib/jekyll/convertible.rb +++ b/lib/jekyll/convertible.rb @@ -30,7 +30,7 @@ module Jekyll if self.content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m self.content = $POSTMATCH - self.data = YAML.load($1) + self.data = YAML.safe_load($1) end rescue => e puts "Error reading file #{File.join(base, name)}: #{e.message}" diff --git a/lib/jekyll/core_ext.rb b/lib/jekyll/core_ext.rb index dfc5bbf7..1d6b83a1 100644 --- a/lib/jekyll/core_ext.rb +++ b/lib/jekyll/core_ext.rb @@ -24,7 +24,7 @@ class Hash # and then the plural key, and handling any nil entries. # +hash+ the hash to read from # +singular_key+ the singular key - # +plural_key+ the singular key + # +plural_key+ the plural key # # Returns an array def pluralized_array(singular_key, plural_key) diff --git a/lib/jekyll/draft.rb b/lib/jekyll/draft.rb new file mode 100644 index 00000000..321a6e58 --- /dev/null +++ b/lib/jekyll/draft.rb @@ -0,0 +1,35 @@ +module Jekyll + + class Draft < Post + + # Valid post name regex (no date) + MATCHER = /^(.*)(\.[^.]+)$/ + + # Draft name validator. Draft filenames must be like: + # my-awesome-post.textile + # + # Returns true if valid, false if not. + def self.valid?(name) + name =~ MATCHER + end + + # Get the full path to the directory containing the draft files + def containing_dir(source, dir) + File.join(source, dir, '_drafts') + end + + # Extract information from the post filename. + # + # name - The String filename of the post file. + # + # Returns nothing. + def process(name) + m, slug, ext = *name.match(MATCHER) + self.date = File.mtime(File.join(@base, name)) + self.slug = slug + self.ext = ext + end + + end + +end diff --git a/lib/jekyll/migrators/csv.rb b/lib/jekyll/migrators/csv.rb deleted file mode 100644 index ce5203b7..00000000 --- a/lib/jekyll/migrators/csv.rb +++ /dev/null @@ -1,26 +0,0 @@ -module Jekyll - module CSV - # Reads a csv with title, permalink, body, published_at, and filter. - # It creates a post file for each row in the csv - def self.process(file = "posts.csv") - FileUtils.mkdir_p "_posts" - posts = 0 - FasterCSV.foreach(file) do |row| - next if row[0] == "title" - posts += 1 - name = row[3].split(" ")[0]+"-"+row[1]+(row[4] =~ /markdown/ ? ".markdown" : ".textile") - File.open("_posts/#{name}", "w") do |f| - f.puts <<-HEADER ---- -layout: post -title: #{row[0]} ---- - - HEADER - f.puts row[2] - end - end - "Created #{posts} posts!" - end - end -end diff --git a/lib/jekyll/migrators/drupal.rb b/lib/jekyll/migrators/drupal.rb deleted file mode 100644 index 6acd5de0..00000000 --- a/lib/jekyll/migrators/drupal.rb +++ /dev/null @@ -1,103 +0,0 @@ -require 'rubygems' -require 'sequel' -require 'fileutils' -require 'safe_yaml' - -# NOTE: This converter requires Sequel and the MySQL gems. -# The MySQL gem can be difficult to install on OS X. Once you have MySQL -# installed, running the following commands should work: -# $ sudo gem install sequel -# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config - -module Jekyll - module Drupal - # Reads a MySQL database via Sequel and creates a post file for each post - # in wp_posts that has post_status = 'publish'. This restriction is made - # because 'draft' posts are not guaranteed to have valid dates. - QUERY = "SELECT n.nid, \ - n.title, \ - nr.body, \ - n.created, \ - n.status \ - FROM node AS n, \ - node_revisions AS nr \ - WHERE (n.type = 'blog' OR n.type = 'story') \ - AND n.vid = nr.vid" - - def self.process(dbname, user, pass, host = 'localhost', prefix = '') - db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8') - - if prefix != '' - QUERY[" node "] = " " + prefix + "node " - QUERY[" node_revisions "] = " " + prefix + "node_revisions " - end - - FileUtils.mkdir_p "_posts" - FileUtils.mkdir_p "_drafts" - - # Create the refresh layout - # Change the refresh url if you customized your permalink config - File.open("_layouts/refresh.html", "w") do |f| - f.puts < - - - - - - -EOF - end - - db[QUERY].each do |post| - # Get required fields and construct Jekyll compatible name - node_id = post[:nid] - title = post[:title] - content = post[:body] - created = post[:created] - time = Time.at(created) - is_published = post[:status] == 1 - dir = is_published ? "_posts" : "_drafts" - slug = title.strip.downcase.gsub(/(&|&)/, ' and ').gsub(/[\s\.\/\\]/, '-').gsub(/[^\w-]/, '').gsub(/[-_]{2,}/, '-').gsub(/^[-_]/, '').gsub(/[-_]$/, '') - name = time.strftime("%Y-%m-%d-") + slug + '.md' - - # Get the relevant fields as a hash, delete empty fields and convert - # to YAML for the header - data = { - 'layout' => 'post', - 'title' => title.to_s, - 'created' => created, - }.delete_if { |k,v| v.nil? || v == ''}.to_yaml - - # Write out the data and content to file - File.open("#{dir}/#{name}", "w") do |f| - f.puts data - f.puts "---" - f.puts content - end - - # Make a file to redirect from the old Drupal URL - if is_published - aliases = db["SELECT dst FROM #{prefix}url_alias WHERE src = ?", "node/#{node_id}"].all - - aliases.push(:dst => "node/#{node_id}") - - aliases.each do |url_alias| - FileUtils.mkdir_p url_alias[:dst] - File.open("#{url_alias[:dst]}/index.md", "w") do |f| - f.puts "---" - f.puts "layout: refresh" - f.puts "refresh_to_post_id: /#{time.strftime("%Y/%m/%d/") + slug}" - f.puts "---" - end - end - end - end - - # TODO: Make dirs & files for nodes of type 'page' - # Make refresh pages for these as well - - # TODO: Make refresh dirs & files according to entries in url_alias table - end - end -end diff --git a/lib/jekyll/migrators/enki.rb b/lib/jekyll/migrators/enki.rb deleted file mode 100644 index 61cb2562..00000000 --- a/lib/jekyll/migrators/enki.rb +++ /dev/null @@ -1,49 +0,0 @@ -# Adapted by Rodrigo Pinto -# Based on typo.rb by Toby DiPasquale - -require 'fileutils' -require 'rubygems' -require 'sequel' - -module Jekyll - module Enki - SQL = <<-EOS - SELECT p.id, - p.title, - p.slug, - p.body, - p.published_at as date, - p.cached_tag_list as tags - FROM posts p - EOS - - # Just working with postgres, but can be easily adapted - # to work with both mysql and postgres. - def self.process(dbname, user, pass, host = 'localhost') - FileUtils.mkdir_p('_posts') - db = Sequel.postgres(:database => dbname, - :user => user, - :password => pass, - :host => host, - :encoding => 'utf8') - - db[SQL].each do |post| - name = [ sprintf("%.04d", post[:date].year), - sprintf("%.02d", post[:date].month), - sprintf("%.02d", post[:date].day), - post[:slug].strip ].join('-') - name += '.textile' - - File.open("_posts/#{name}", 'w') do |f| - f.puts({ 'layout' => 'post', - 'title' => post[:title].to_s, - 'enki_id' => post[:id], - 'categories' => post[:tags] - }.delete_if { |k, v| v.nil? || v == '' }.to_yaml) - f.puts '---' - f.puts post[:body].delete("\r") - end - end - end - end -end diff --git a/lib/jekyll/migrators/joomla.rb b/lib/jekyll/migrators/joomla.rb deleted file mode 100644 index c7e72476..00000000 --- a/lib/jekyll/migrators/joomla.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'rubygems' -require 'sequel' -require 'fileutils' -require 'safe_yaml' - -# NOTE: This migrator is made for Joomla 1.5 databases. -# NOTE: This converter requires Sequel and the MySQL gems. -# The MySQL gem can be difficult to install on OS X. Once you have MySQL -# installed, running the following commands should work: -# $ sudo gem install sequel -# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config - -module Jekyll - module Joomla - def self.process(dbname, user, pass, host = 'localhost', table_prefix = 'jos_', section = '1') - db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8') - - FileUtils.mkdir_p("_posts") - - # Reads a MySQL database via Sequel and creates a post file for each - # post in wp_posts that has post_status = 'publish'. This restriction is - # made because 'draft' posts are not guaranteed to have valid dates. - query = "SELECT `title`, `alias`, CONCAT(`introtext`,`fulltext`) as content, `created`, `id` FROM #{table_prefix}content WHERE state = '0' OR state = '1' AND sectionid = '#{section}'" - - db[query].each do |post| - # Get required fields and construct Jekyll compatible name. - title = post[:title] - slug = post[:alias] - date = post[:created] - content = post[:content] - name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, date.day, - slug] - - # Get the relevant fields as a hash, delete empty fields and convert - # to YAML for the header. - data = { - 'layout' => 'post', - 'title' => title.to_s, - 'joomla_id' => post[:id], - 'joomla_url' => post[:alias], - 'date' => date - }.delete_if { |k,v| v.nil? || v == '' }.to_yaml - - # Write out the data and content to file - File.open("_posts/#{name}", "w") do |f| - f.puts data - f.puts "---" - f.puts content - end - end - end - end -end diff --git a/lib/jekyll/migrators/marley.rb b/lib/jekyll/migrators/marley.rb deleted file mode 100644 index 3aa74f49..00000000 --- a/lib/jekyll/migrators/marley.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'safe_yaml' -require 'fileutils' - -module Jekyll - module Marley - def self.regexp - { :id => /^\d{0,4}-{0,1}(.*)$/, - :title => /^#\s*(.*)\s+$/, - :title_with_date => /^#\s*(.*)\s+\(([0-9\/]+)\)$/, - :published_on => /.*\s+\(([0-9\/]+)\)$/, - :perex => /^([^\#\n]+\n)$/, - :meta => /^\{\{\n(.*)\}\}\n$/mi # Multiline Regexp - } - end - - def self.process(marley_data_dir) - raise ArgumentError, "marley dir #{marley_data_dir} not found" unless File.directory?(marley_data_dir) - - FileUtils.mkdir_p "_posts" - - posts = 0 - Dir["#{marley_data_dir}/**/*.txt"].each do |f| - next unless File.exists?(f) - - #copied over from marley's app/lib/post.rb - file_content = File.read(f) - meta_content = file_content.slice!( self.regexp[:meta] ) - body = file_content.sub( self.regexp[:title], '').sub( self.regexp[:perex], '').strip - - title = file_content.scan( self.regexp[:title] ).first.to_s.strip - prerex = file_content.scan( self.regexp[:perex] ).first.to_s.strip - published_on = DateTime.parse( post[:published_on] ) rescue File.mtime( File.dirname(f) ) - meta = ( meta_content ) ? YAML::load( meta_content.scan( self.regexp[:meta]).to_s ) : {} - meta['title'] = title - meta['layout'] = 'post' - - formatted_date = published_on.strftime('%Y-%m-%d') - post_name = File.dirname(f).split(%r{/}).last.gsub(/\A\d+-/, '') - - name = "#{formatted_date}-#{post_name}" - File.open("_posts/#{name}.markdown", "w") do |f| - f.puts meta.to_yaml - f.puts "---\n" - f.puts "\n#{prerex}\n\n" if prerex - f.puts body - end - posts += 1 - end - "Created #{posts} posts!" - end - end -end diff --git a/lib/jekyll/migrators/mephisto.rb b/lib/jekyll/migrators/mephisto.rb deleted file mode 100644 index 7622c722..00000000 --- a/lib/jekyll/migrators/mephisto.rb +++ /dev/null @@ -1,84 +0,0 @@ -# Quickly hacked together my Michael Ivey -# Based on mt.rb by Nick Gerakines, open source and publically -# available under the MIT license. Use this module at your own risk. - -require 'rubygems' -require 'sequel' -require 'fastercsv' -require 'fileutils' -require File.join(File.dirname(__FILE__),"csv.rb") - -# NOTE: This converter requires Sequel and the MySQL gems. -# The MySQL gem can be difficult to install on OS X. Once you have MySQL -# installed, running the following commands should work: -# $ sudo gem install sequel -# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config - -module Jekyll - module Mephisto - #Accepts a hash with database config variables, exports mephisto posts into a csv - #export PGPASSWORD if you must - def self.postgres(c) - sql = <<-SQL - BEGIN; - CREATE TEMP TABLE jekyll AS - SELECT title, permalink, body, published_at, filter FROM contents - WHERE user_id = 1 AND type = 'Article' ORDER BY published_at; - COPY jekyll TO STDOUT WITH CSV HEADER; - ROLLBACK; - SQL - command = %Q(psql -h #{c[:host] || "localhost"} -c "#{sql.strip}" #{c[:database]} #{c[:username]} -o #{c[:filename] || "posts.csv"}) - puts command - `#{command}` - CSV.process - end - - # This query will pull blog posts from all entries across all blogs. If - # you've got unpublished, deleted or otherwise hidden posts please sift - # through the created posts to make sure nothing is accidently published. - QUERY = "SELECT id, \ - permalink, \ - body, \ - published_at, \ - title \ - FROM contents \ - WHERE user_id = 1 AND \ - type = 'Article' AND \ - published_at IS NOT NULL \ - ORDER BY published_at" - - def self.process(dbname, user, pass, host = 'localhost') - db = Sequel.mysql(dbname, :user => user, - :password => pass, - :host => host, - :encoding => 'utf8') - - FileUtils.mkdir_p "_posts" - - db[QUERY].each do |post| - title = post[:title] - slug = post[:permalink] - date = post[:published_at] - content = post[:body] - - # Ideally, this script would determine the post format (markdown, - # html, etc) and create files with proper extensions. At this point - # it just assumes that markdown will be acceptable. - name = [date.year, date.month, date.day, slug].join('-') + ".markdown" - - data = { - 'layout' => 'post', - 'title' => title.to_s, - 'mt_id' => post[:entry_id], - }.delete_if { |k,v| v.nil? || v == ''}.to_yaml - - File.open("_posts/#{name}", "w") do |f| - f.puts data - f.puts "---" - f.puts content - end - end - - end - end -end diff --git a/lib/jekyll/migrators/mt.rb b/lib/jekyll/migrators/mt.rb deleted file mode 100644 index 09d89a79..00000000 --- a/lib/jekyll/migrators/mt.rb +++ /dev/null @@ -1,86 +0,0 @@ -# Created by Nick Gerakines, open source and publically available under the -# MIT license. Use this module at your own risk. -# I'm an Erlang/Perl/C++ guy so please forgive my dirty ruby. - -require 'rubygems' -require 'sequel' -require 'fileutils' -require 'safe_yaml' - -# NOTE: This converter requires Sequel and the MySQL gems. -# The MySQL gem can be difficult to install on OS X. Once you have MySQL -# installed, running the following commands should work: -# $ sudo gem install sequel -# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config - -module Jekyll - module MT - # This query will pull blog posts from all entries across all blogs. If - # you've got unpublished, deleted or otherwise hidden posts please sift - # through the created posts to make sure nothing is accidently published. - QUERY = "SELECT entry_id, \ - entry_basename, \ - entry_text, \ - entry_text_more, \ - entry_authored_on, \ - entry_title, \ - entry_convert_breaks \ - FROM mt_entry" - - def self.process(dbname, user, pass, host = 'localhost') - db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8') - - FileUtils.mkdir_p "_posts" - - db[QUERY].each do |post| - title = post[:entry_title] - slug = post[:entry_basename].gsub(/_/, '-') - date = post[:entry_authored_on] - content = post[:entry_text] - more_content = post[:entry_text_more] - entry_convert_breaks = post[:entry_convert_breaks] - - # Be sure to include the body and extended body. - if more_content != nil - content = content + " \n" + more_content - end - - # Ideally, this script would determine the post format (markdown, - # html, etc) and create files with proper extensions. At this point - # it just assumes that markdown will be acceptable. - name = [date.year, date.month, date.day, slug].join('-') + '.' + - self.suffix(entry_convert_breaks) - - data = { - 'layout' => 'post', - 'title' => title.to_s, - 'mt_id' => post[:entry_id], - 'date' => date - }.delete_if { |k,v| v.nil? || v == '' }.to_yaml - - File.open("_posts/#{name}", "w") do |f| - f.puts data - f.puts "---" - f.puts content - end - end - end - - def self.suffix(entry_type) - if entry_type.nil? || entry_type.include?("markdown") - # The markdown plugin I have saves this as - # "markdown_with_smarty_pants", so I just look for "markdown". - "markdown" - elsif entry_type.include?("textile") - # This is saved as "textile_2" on my installation of MT 5.1. - "textile" - elsif entry_type == "0" || entry_type.include?("richtext") - # Richtext looks to me like it's saved as HTML, so I include it here. - "html" - else - # Other values might need custom work. - entry_type - end - end - end -end diff --git a/lib/jekyll/migrators/posterous.rb b/lib/jekyll/migrators/posterous.rb deleted file mode 100644 index 0a2280f2..00000000 --- a/lib/jekyll/migrators/posterous.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'rubygems' -require 'jekyll' -require 'fileutils' -require 'net/http' -require 'uri' -require "json" - -# ruby -r './lib/jekyll/migrators/posterous.rb' -e 'Jekyll::Posterous.process(email, pass, api_key, blog)' - -module Jekyll - module Posterous - def self.fetch(uri_str, limit = 10) - # You should choose better exception. - raise ArgumentError, 'Stuck in a redirect loop. Please double check your email and password' if limit == 0 - - response = nil - Net::HTTP.start('posterous.com') do |http| - req = Net::HTTP::Get.new(uri_str) - req.basic_auth @email, @pass - response = http.request(req) - end - - case response - when Net::HTTPSuccess then response - when Net::HTTPRedirection then fetch(response['location'], limit - 1) - else response.error! - end - end - - def self.process(email, pass, api_token, blog = 'primary') - @email, @pass, @api_token = email, pass, api_token - FileUtils.mkdir_p "_posts" - - posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}").body) - page = 1 - - while posts.any? - posts.each do |post| - title = post["title"] - slug = title.gsub(/[^[:alnum:]]+/, '-').downcase - date = Date.parse(post["display_date"]) - content = post["body_html"] - published = !post["is_private"] - name = "%02d-%02d-%02d-%s.html" % [date.year, date.month, date.day, slug] - - # Get the relevant fields as a hash, delete empty fields and convert - # to YAML for the header - data = { - 'layout' => 'post', - 'title' => title.to_s, - 'published' => published - }.delete_if { |k,v| v.nil? || v == ''}.to_yaml - - # Write out the data and content to file - File.open("_posts/#{name}", "w") do |f| - f.puts data - f.puts "---" - f.puts content - end - end - - page += 1 - posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}&page=#{page}").body) - end - end - end -end diff --git a/lib/jekyll/migrators/rss.rb b/lib/jekyll/migrators/rss.rb deleted file mode 100644 index fec3d07c..00000000 --- a/lib/jekyll/migrators/rss.rb +++ /dev/null @@ -1,47 +0,0 @@ -# Created by Kendall Buchanan (https://github.com/kendagriff) on 2011-12-22. -# Use at your own risk. The end. -# -# Usage: -# (URL) -# ruby -r '_import/rss.rb' -e "Jekyll::MigrateRSS.process('http://yourdomain.com/your-favorite-feed.xml')" -# -# (Local file) -# ruby -r '_import/rss.rb' -e "Jekyll::MigrateRSS.process('./somefile/on/your/computer.xml')" - -require 'rubygems' -require 'rss/1.0' -require 'rss/2.0' -require 'open-uri' -require 'fileutils' -require 'safe_yaml' - -module Jekyll - module MigrateRSS - - # The `source` argument may be a URL or a local file. - def self.process(source) - content = "" - open(source) { |s| content = s.read } - rss = RSS::Parser.parse(content, false) - - raise "There doesn't appear to be any RSS items at the source (#{source}) provided." unless rss - - rss.items.each do |item| - formatted_date = item.date.strftime('%Y-%m-%d') - post_name = item.title.split(%r{ |!|/|:|&|-|$|,}).map { |i| i.downcase if i != '' }.compact.join('-') - name = "#{formatted_date}-#{post_name}" - - header = { - 'layout' => 'post', - 'title' => item.title - } - - File.open("_posts/#{name}.html", "w") do |f| - f.puts header.to_yaml - f.puts "---\n" - f.puts item.description - end - end - end - end -end \ No newline at end of file diff --git a/lib/jekyll/migrators/textpattern.rb b/lib/jekyll/migrators/textpattern.rb deleted file mode 100644 index 9eca2530..00000000 --- a/lib/jekyll/migrators/textpattern.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'rubygems' -require 'sequel' -require 'fileutils' -require 'safe_yaml' - -# NOTE: This converter requires Sequel and the MySQL gems. -# The MySQL gem can be difficult to install on OS X. Once you have MySQL -# installed, running the following commands should work: -# $ sudo gem install sequel -# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config - -module Jekyll - module TextPattern - # Reads a MySQL database via Sequel and creates a post file for each post. - # The only posts selected are those with a status of 4 or 5, which means - # "live" and "sticky" respectively. - # Other statuses are 1 => draft, 2 => hidden and 3 => pending. - QUERY = "SELECT Title, \ - url_title, \ - Posted, \ - Body, \ - Keywords \ - FROM textpattern \ - WHERE Status = '4' OR \ - Status = '5'" - - def self.process(dbname, user, pass, host = 'localhost') - db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8') - - FileUtils.mkdir_p "_posts" - - db[QUERY].each do |post| - # Get required fields and construct Jekyll compatible name. - title = post[:Title] - slug = post[:url_title] - date = post[:Posted] - content = post[:Body] - - name = [date.strftime("%Y-%m-%d"), slug].join('-') + ".textile" - - # Get the relevant fields as a hash, delete empty fields and convert - # to YAML for the header. - data = { - 'layout' => 'post', - 'title' => title.to_s, - 'tags' => post[:Keywords].split(',') - }.delete_if { |k,v| v.nil? || v == ''}.to_yaml - - # Write out the data and content to file. - File.open("_posts/#{name}", "w") do |f| - f.puts data - f.puts "---" - f.puts content - end - end - end - end -end diff --git a/lib/jekyll/migrators/tumblr.rb b/lib/jekyll/migrators/tumblr.rb deleted file mode 100644 index 4a1e19d7..00000000 --- a/lib/jekyll/migrators/tumblr.rb +++ /dev/null @@ -1,195 +0,0 @@ -require 'rubygems' -require 'open-uri' -require 'fileutils' -require 'nokogiri' -require 'date' -require 'json' -require 'uri' -require 'jekyll' - -module Jekyll - module Tumblr - def self.process(url, format = "html", grab_images = false, - add_highlights = false, rewrite_urls = true) - @grab_images = grab_images - FileUtils.mkdir_p "_posts/tumblr" - url += "/api/read/json/" - per_page = 50 - posts = [] - # Two passes are required so that we can rewrite URLs. - # First pass builds up an array of each post as a hash. - begin - current_page = (current_page || -1) + 1 - feed = open(url + "?num=#{per_page}&start=#{current_page * per_page}") - json = feed.readlines.join("\n")[21...-2] # Strip Tumblr's JSONP chars. - blog = JSON.parse(json) - puts "Page: #{current_page + 1} - Posts: #{blog["posts"].size}" - posts += blog["posts"].map { |post| post_to_hash(post, format) } - end until blog["posts"].size < per_page - # Rewrite URLs and create redirects. - posts = rewrite_urls_and_redirects posts if rewrite_urls - # Second pass for writing post files. - posts.each do |post| - if format == "md" - post[:content] = html_to_markdown post[:content] - post[:content] = add_syntax_highlights post[:content] if add_highlights - end - File.open("_posts/tumblr/#{post[:name]}", "w") do |f| - f.puts post[:header].to_yaml + "---\n" + post[:content] - end - end - end - - private - - # Converts each type of Tumblr post to a hash with all required - # data for Jekyll. - def self.post_to_hash(post, format) - case post['type'] - when "regular" - title = post["regular-title"] - content = post["regular-body"] - when "link" - title = post["link-text"] || post["link-url"] - content = "#{title}" - unless post["link-description"].nil? - content << "
" + post["link-description"] - end - when "photo" - title = post["photo-caption"] - max_size = post.keys.map{ |k| k.gsub("photo-url-", "").to_i }.max - url = post["photo-url"] || post["photo-url-#{max_size}"] - ext = "." + post[post.keys.select { |k| - k =~ /^photo-url-/ && post[k].split("/").last =~ /\./ - }.first].split(".").last - content = "" - unless post["photo-link-url"].nil? - content = "#{content}" - end - when "audio" - if !post["id3-title"].nil? - title = post["id3-title"] - content = post.at["audio-player"] + "
" + post["audio-caption"] - else - title = post["audio-caption"] - content = post.at["audio-player"] - end - when "quote" - title = post["quote-text"] - content = "
#{post["quote-text"]}
" - unless post["quote-source"].nil? - content << "—" + post["quote-source"] - end - when "conversation" - title = post["conversation-title"] - content = "
" - post["conversation"]["line"].each do |line| - content << "
#{line['label']}
#{line}
" - end - content << "
" - when "video" - title = post["video-title"] - content = post["video-player"] - unless post["video-caption"].nil? - content << "
" + post["video-caption"] - end - end - date = Date.parse(post['date']).to_s - title = Nokogiri::HTML(title).text - slug = title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '') - slug = slug.slice(0..200) if slug.length > 200 - { - :name => "#{date}-#{slug}.#{format}", - :header => { - "layout" => "post", - "title" => title, - "tags" => post["tags"], - }, - :content => content, - :url => post["url"], - :slug => post["url-with-slug"], - } - end - - # Create a Hash of old urls => new urls, for rewriting and - # redirects, and replace urls in each post. Instantiate Jekyll - # site/posts to get the correct permalink format. - def self.rewrite_urls_and_redirects(posts) - site = Jekyll::Site.new(Jekyll.configuration({})) - urls = Hash[posts.map { |post| - # Create an initial empty file for the post so that - # we can instantiate a post object. - File.open("_posts/tumblr/#{post[:name]}", "w") - tumblr_url = URI.parse(post[:slug]).path - jekyll_url = Jekyll::Post.new(site, Dir.pwd, "", "tumblr/" + post[:name]).url - redirect_dir = tumblr_url.sub(/\//, "") + "/" - FileUtils.mkdir_p redirect_dir - File.open(redirect_dir + "index.html", "w") do |f| - f.puts "" - end - [tumblr_url, jekyll_url] - }] - posts.map { |post| - urls.each do |tumblr_url, jekyll_url| - post[:content].gsub!(/#{tumblr_url}/i, jekyll_url) - end - post - } - end - - # Uses Python's html2text to convert a post's content to - # markdown. Preserve HTML tables as per the markdown docs. - def self.html_to_markdown(content) - preserve = ["table", "tr", "th", "td"] - preserve.each do |tag| - content.gsub!(/<#{tag}/i, "$$" + tag) - content.gsub!(/<\/#{tag}/i, "||" + tag) - end - content = %x[echo '#{content.gsub("'", "''")}' | html2text] - preserve.each do |tag| - content.gsub!("$$" + tag, "<" + tag) - content.gsub!("||" + tag, " -require 'fileutils' -require 'rubygems' -require 'sequel' -require 'safe_yaml' - -module Jekyll - module Typo - # This SQL *should* work for both MySQL and PostgreSQL, but I haven't - # tested PostgreSQL yet (as of 2008-12-16). - SQL = <<-EOS - SELECT c.id id, - c.title title, - c.permalink slug, - c.body body, - c.published_at date, - c.state state, - COALESCE(tf.name, 'html') filter - FROM contents c - LEFT OUTER JOIN text_filters tf - ON c.text_filter_id = tf.id - EOS - - def self.process dbname, user, pass, host='localhost' - FileUtils.mkdir_p '_posts' - db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8') - db[SQL].each do |post| - next unless post[:state] =~ /published/ - - name = [ sprintf("%.04d", post[:date].year), - sprintf("%.02d", post[:date].month), - sprintf("%.02d", post[:date].day), - post[:slug].strip ].join('-') - - # Can have more than one text filter in this field, but we just want - # the first one for this. - name += '.' + post[:filter].split(' ')[0] - - File.open("_posts/#{name}", 'w') do |f| - f.puts({ 'layout' => 'post', - 'title' => post[:title].to_s, - 'typo_id' => post[:id] - }.delete_if { |k, v| v.nil? || v == '' }.to_yaml) - f.puts '---' - f.puts post[:body].delete("\r") - end - end - end - - end -end diff --git a/lib/jekyll/migrators/wordpress.rb b/lib/jekyll/migrators/wordpress.rb deleted file mode 100644 index 8d0ecf71..00000000 --- a/lib/jekyll/migrators/wordpress.rb +++ /dev/null @@ -1,295 +0,0 @@ -require 'rubygems' -require 'sequel' -require 'fileutils' -require 'safe_yaml' - -# NOTE: This converter requires Sequel and the MySQL gems. -# The MySQL gem can be difficult to install on OS X. Once you have MySQL -# installed, running the following commands should work: -# $ sudo gem install sequel -# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config - -module Jekyll - module WordPress - - # Main migrator function. Call this to perform the migration. - # - # dbname:: The name of the database - # user:: The database user name - # pass:: The database user's password - # host:: The address of the MySQL database host. Default: 'localhost' - # options:: A hash table of configuration options. - # - # Supported options are: - # - # :table_prefix:: Prefix of database tables used by WordPress. - # Default: 'wp_' - # :clean_entities:: If true, convert non-ASCII characters to HTML - # entities in the posts, comments, titles, and - # names. Requires the 'htmlentities' gem to - # work. Default: true. - # :comments:: If true, migrate post comments too. Comments - # are saved in the post's YAML front matter. - # Default: true. - # :categories:: If true, save the post's categories in its - # YAML front matter. - # :tags:: If true, save the post's tags in its - # YAML front matter. - # :more_excerpt:: If true, when a post has no excerpt but - # does have a tag, use the - # preceding post content as the excerpt. - # Default: true. - # :more_anchor:: If true, convert a tag into - # two HTML anchors with ids "more" and - # "more-NNN" (where NNN is the post number). - # Default: true. - # :status:: Array of allowed post statuses. Only - # posts with matching status will be migrated. - # Known statuses are :publish, :draft, :private, - # and :revision. If this is nil or an empty - # array, all posts are migrated regardless of - # status. Default: [:publish]. - # - def self.process(dbname, user, pass, host='localhost', options={}) - options = { - :table_prefix => 'wp_', - :clean_entities => true, - :comments => true, - :categories => true, - :tags => true, - :more_excerpt => true, - :more_anchor => true, - :status => [:publish] # :draft, :private, :revision - }.merge(options) - - if options[:clean_entities] - begin - require 'htmlentities' - rescue LoadError - STDERR.puts "Could not require 'htmlentities', so the " + - ":clean_entities option is now disabled." - options[:clean_entities] = false - end - end - - FileUtils.mkdir_p("_posts") - - db = Sequel.mysql(dbname, :user => user, :password => pass, - :host => host, :encoding => 'utf8') - - px = options[:table_prefix] - - posts_query = " - SELECT - posts.ID AS `id`, - posts.guid AS `guid`, - posts.post_type AS `type`, - posts.post_status AS `status`, - posts.post_title AS `title`, - posts.post_name AS `slug`, - posts.post_date AS `date`, - posts.post_content AS `content`, - posts.post_excerpt AS `excerpt`, - posts.comment_count AS `comment_count`, - users.display_name AS `author`, - users.user_login AS `author_login`, - users.user_email AS `author_email`, - users.user_url AS `author_url` - FROM #{px}posts AS `posts` - LEFT JOIN #{px}users AS `users` - ON posts.post_author = users.ID" - - if options[:status] and not options[:status].empty? - status = options[:status][0] - posts_query << " - WHERE posts.post_status = '#{status.to_s}'" - options[:status][1..-1].each do |status| - posts_query << " OR - posts.post_status = '#{status.to_s}'" - end - end - - db[posts_query].each do |post| - process_post(post, db, options) - end - end - - - def self.process_post(post, db, options) - px = options[:table_prefix] - - title = post[:title] - if options[:clean_entities] - title = clean_entities(title) - end - - slug = post[:slug] - if !slug or slug.empty? - slug = sluggify(title) - end - - date = post[:date] || Time.now - name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, - date.day, slug] - content = post[:content].to_s - if options[:clean_entities] - content = clean_entities(content) - end - - excerpt = post[:excerpt].to_s - - more_index = content.index(//) - more_anchor = nil - if more_index - if options[:more_excerpt] and - (post[:excerpt].nil? or post[:excerpt].empty?) - excerpt = content[0...more_index] - end - if options[:more_anchor] - more_link = "more" - content.sub!(//, - "" + - "") - end - end - - categories = [] - tags = [] - - if options[:categories] or options[:tags] - - cquery = - "SELECT - terms.name AS `name`, - ttax.taxonomy AS `type` - FROM - #{px}terms AS `terms`, - #{px}term_relationships AS `trels`, - #{px}term_taxonomy AS `ttax` - WHERE - trels.object_id = '#{post[:id]}' AND - trels.term_taxonomy_id = ttax.term_taxonomy_id AND - terms.term_id = ttax.term_id" - - db[cquery].each do |term| - if options[:categories] and term[:type] == "category" - if options[:clean_entities] - categories << clean_entities(term[:name]) - else - categories << term[:name] - end - elsif options[:tags] and term[:type] == "post_tag" - if options[:clean_entities] - tags << clean_entities(term[:name]) - else - tags << term[:name] - end - end - end - end - - comments = [] - - if options[:comments] and post[:comment_count].to_i > 0 - cquery = - "SELECT - comment_ID AS `id`, - comment_author AS `author`, - comment_author_email AS `author_email`, - comment_author_url AS `author_url`, - comment_date AS `date`, - comment_date_gmt AS `date_gmt`, - comment_content AS `content` - FROM #{px}comments - WHERE - comment_post_ID = '#{post[:id]}' AND - comment_approved != 'spam'" - - - db[cquery].each do |comment| - - comcontent = comment[:content].to_s - if comcontent.respond_to?(:force_encoding) - comcontent.force_encoding("UTF-8") - end - if options[:clean_entities] - comcontent = clean_entities(comcontent) - end - comauthor = comment[:author].to_s - if options[:clean_entities] - comauthor = clean_entities(comauthor) - end - - comments << { - 'id' => comment[:id].to_i, - 'author' => comauthor, - 'author_email' => comment[:author_email].to_s, - 'author_url' => comment[:author_url].to_s, - 'date' => comment[:date].to_s, - 'date_gmt' => comment[:date_gmt].to_s, - 'content' => comcontent, - } - end - - comments.sort!{ |a,b| a['id'] <=> b['id'] } - end - - # Get the relevant fields as a hash, delete empty fields and - # convert to YAML for the header. - data = { - 'layout' => post[:type].to_s, - 'status' => post[:status].to_s, - 'published' => (post[:status].to_s == "publish"), - 'title' => title.to_s, - 'author' => post[:author].to_s, - 'author_login' => post[:author_login].to_s, - 'author_email' => post[:author_email].to_s, - 'author_url' => post[:author_url].to_s, - 'excerpt' => excerpt, - 'more_anchor' => more_anchor, - 'wordpress_id' => post[:id], - 'wordpress_url' => post[:guid].to_s, - 'date' => date, - 'categories' => options[:categories] ? categories : nil, - 'tags' => options[:tags] ? tags : nil, - 'comments' => options[:comments] ? comments : nil, - }.delete_if { |k,v| v.nil? || v == '' }.to_yaml - - # Write out the data and content to file - File.open("_posts/#{name}", "w") do |f| - f.puts data - f.puts "---" - f.puts content - end - end - - - def self.clean_entities( text ) - if text.respond_to?(:force_encoding) - text.force_encoding("UTF-8") - end - text = HTMLEntities.new.encode(text, :named) - # We don't want to convert these, it would break all - # HTML tags in the post and comments. - text.gsub!("&", "&") - text.gsub!("<", "<") - text.gsub!(">", ">") - text.gsub!(""", '"') - text.gsub!("'", "'") - text.gsub!("/", "/") - text - end - - - def self.sluggify( title ) - begin - require 'unidecode' - title = title.to_ascii - rescue LoadError - STDERR.puts "Could not require 'unidecode'. If your post titles have non-ASCII characters, you could get nicer permalinks by installing unidecode." - end - title.downcase.gsub(/[^0-9A-Za-z]+/, " ").strip.gsub(" ", "-") - end - - end -end diff --git a/lib/jekyll/migrators/wordpressdotcom.rb b/lib/jekyll/migrators/wordpressdotcom.rb deleted file mode 100644 index bf423384..00000000 --- a/lib/jekyll/migrators/wordpressdotcom.rb +++ /dev/null @@ -1,82 +0,0 @@ -# coding: utf-8 - -require 'rubygems' -require 'hpricot' -require 'fileutils' -require 'safe_yaml' -require 'time' - -module Jekyll - # This importer takes a wordpress.xml file, which can be exported from your - # wordpress.com blog (/wp-admin/export.php). - module WordpressDotCom - def self.process(filename = "wordpress.xml") - import_count = Hash.new(0) - doc = Hpricot::XML(File.read(filename)) - - (doc/:channel/:item).each do |item| - title = item.at(:title).inner_text.strip - permalink_title = item.at('wp:post_name').inner_text - # Fallback to "prettified" title if post_name is empty (can happen) - if permalink_title == "" - permalink_title = sluggify(title) - end - - date = Time.parse(item.at('wp:post_date').inner_text) - status = item.at('wp:status').inner_text - - if status == "publish" - published = true - else - published = false - end - - type = item.at('wp:post_type').inner_text - tags = (item/:category).map{|c| c.inner_text}.reject{|c| c == 'Uncategorized'}.uniq - - metas = Hash.new - item.search("wp:postmeta").each do |meta| - key = meta.at('wp:meta_key').inner_text - value = meta.at('wp:meta_value').inner_text - metas[key] = value; - end - - name = "#{date.strftime('%Y-%m-%d')}-#{permalink_title}.html" - header = { - 'layout' => type, - 'title' => title, - 'tags' => tags, - 'status' => status, - 'type' => type, - 'published' => published, - 'meta' => metas - } - - begin - FileUtils.mkdir_p "_#{type}s" - File.open("_#{type}s/#{name}", "w") do |f| - f.puts header.to_yaml - f.puts '---' - f.puts item.at('content:encoded').inner_text - end - rescue => e - puts "Couldn't import post!" - puts "Title: #{title}" - puts "Name/Slug: #{name}\n" - puts "Error: #{e.message}" - next - end - - import_count[type] += 1 - end - - import_count.each do |key, value| - puts "Imported #{value} #{key}s" - end - end - - def self.sluggify(title) - title.downcase.split.join('-').gsub('/','-') - end - end -end diff --git a/lib/jekyll/mime.types b/lib/jekyll/mime.types new file mode 100644 index 00000000..b90b1658 --- /dev/null +++ b/lib/jekyll/mime.types @@ -0,0 +1,1588 @@ +# This file maps Internet media types to unique file extension(s). +# Although created for httpd, this file is used by many software systems +# and has been placed in the public domain for unlimited redisribution. +# +# The table below contains both registered and (common) unregistered types. +# A type that has no unique extension can be ignored -- they are listed +# here to guide configurations toward known types and to make it easier to +# identify "new" types. File extensions are also commonly used to indicate +# content languages and encodings, so choose them carefully. +# +# Internet media types should be registered as described in RFC 4288. +# The registry is at . +# +# MIME type (lowercased) Extensions +# ============================================ ========== +# application/1d-interleaved-parityfec +# application/3gpp-ims+xml +# application/activemessage +application/andrew-inset ez +# application/applefile +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +# application/atomicmail +application/atomsvc+xml atomsvc +# application/auth-policy+xml +# application/batch-smtp +# application/beep+xml +# application/calendar+xml +# application/cals-1840 +# application/ccmp+xml +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +# application/cea-2018+xml +# application/cellml+xml +# application/cfw +# application/cnrp+xml +# application/commonground +# application/conference-info+xml +# application/cpl+xml +# application/csta+xml +# application/cstadata+xml +application/cu-seeme cu +# application/cybercash +application/davmount+xml davmount +# application/dca-rft +# application/dec-dx +# application/dialog-info+xml +# application/dicom +# application/dns +application/docbook+xml dbk +# application/dskpp+xml +application/dssc+der dssc +application/dssc+xml xdssc +# application/dvcs +application/ecmascript ecma +# application/edi-consent +# application/edi-x12 +# application/edifact +application/emma+xml emma +# application/epp+xml +application/epub+zip epub +# application/eshop +# application/example +application/exi exi +# application/fastinfoset +# application/fastsoap +# application/fits +application/font-tdpfr pfr +# application/framework-attributes+xml +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +# application/h224 +# application/held+xml +# application/http +application/hyperstudio stk +# application/ibe-key-request+xml +# application/ibe-pkg-reply+xml +# application/ibe-pp-data +# application/iges +# application/im-iscomposing+xml +# application/index +# application/index.cmd +# application/index.obj +# application/index.response +# application/index.vnd +application/inkml+xml ink inkml +# application/iotp +application/ipfix ipfix +# application/ipp +# application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/jsonml+json jsonml +# application/kpml-request+xml +# application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +# application/macwriteii +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma nb mb +# application/mathml-content+xml +# application/mathml-presentation+xml +application/mathml+xml mathml +# application/mbms-associated-procedure-description+xml +# application/mbms-deregister+xml +# application/mbms-envelope+xml +# application/mbms-msk+xml +# application/mbms-msk-response+xml +# application/mbms-protection-description+xml +# application/mbms-reception-report+xml +# application/mbms-register+xml +# application/mbms-register-response+xml +# application/mbms-user-service-description+xml +application/mbox mbox +# application/media_control+xml +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +# application/mikey +application/mods+xml mods +# application/moss-keys +# application/moss-signature +# application/mosskey-data +# application/mosskey-request +application/mp21 m21 mp21 +application/mp4 mp4s +# application/mpeg4-generic +# application/mpeg4-iod +# application/mpeg4-iod-xmt +# application/msc-ivr+xml +# application/msc-mixer+xml +application/msword doc dot +application/mxf mxf +# application/nasdata +# application/news-checkgroups +# application/news-groupinfo +# application/news-transmission +# application/nss +# application/ocsp-request +# application/ocsp-response +application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onetoc onetoc2 onetmp onepkg +application/oxps oxps +# application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +# application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +# application/pidf+xml +# application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +# application/poc-settings+xml +application/postscript ai eps ps +# application/prs.alvestrand.titrax-sheet +application/prs.cww cww +# application/prs.nprend +# application/prs.plucker +# application/prs.rdf-xml-crypt +# application/prs.xsf+xml +application/pskc+xml pskcxml +# application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +# application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +# application/riscos +# application/rlmi+xml +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +# application/rpki-updown +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +# application/rtx +# application/samlassertion+xml +# application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +# application/set-payment +application/set-payment-initiation setpay +# application/set-registration +application/set-registration-initiation setreg +# application/sgml +# application/sgml-open-catalog +application/shf+xml shf +# application/sieve +# application/simple-filter+xml +# application/simple-message-summary +# application/simplesymbolcontainer +# application/slate +# application/smil +application/smil+xml smi smil +# application/soap+fastinfoset +# application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +# application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +# application/tamp-apex-update +# application/tamp-apex-update-confirm +# application/tamp-community-update +# application/tamp-community-update-confirm +# application/tamp-error +# application/tamp-sequence-adjust +# application/tamp-sequence-adjust-confirm +# application/tamp-status-query +# application/tamp-status-response +# application/tamp-update +# application/tamp-update-confirm +application/tei+xml tei teicorpus +application/thraud+xml tfi +# application/timestamp-query +# application/timestamp-reply +application/timestamped-data tsd +# application/tve-trigger +# application/ulpfec +# application/vcard+xml +# application/vemmi +# application/vividence.scriptfile +# application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +# application/vnd.3gpp.sms +# application/vnd.3gpp2.bcmcsinfo+xml +# application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +# application/vnd.adobe.partial-upload +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +# application/vnd.aether.imp +# application/vnd.ah-barcode +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +# application/vnd.amundsen.maze+xml +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +# application/vnd.arastra.swi +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +# application/vnd.autopackage +# application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +# application/vnd.bluetooth.ep.oob +application/vnd.bmi bmi +application/vnd.businessobjects rep +# application/vnd.cab-jscript +# application/vnd.canon-cpdl +# application/vnd.canon-lips +# application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +# application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +# application/vnd.collection+json +# application/vnd.commerce-battelle +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +# application/vnd.ctct.ws+xml +# application/vnd.cups-pdf +# application/vnd.cups-postscript +application/vnd.cups-ppd ppd +# application/vnd.cups-raster +# application/vnd.cups-raw +# application/vnd.curl +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +# application/vnd.cybank +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.dece.zip uvz uvvz +application/vnd.denovo.fcselayout-link fe_launch +# application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dna dna +application/vnd.dolby.mlp mlp +# application/vnd.dolby.mobile.1 +# application/vnd.dolby.mobile.2 +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +# application/vnd.dvb.dvbj +# application/vnd.dvb.esgcontainer +# application/vnd.dvb.ipdcdftnotifaccess +# application/vnd.dvb.ipdcesgaccess +# application/vnd.dvb.ipdcesgaccess2 +# application/vnd.dvb.ipdcesgpdd +# application/vnd.dvb.ipdcroaming +# application/vnd.dvb.iptv.alfec-base +# application/vnd.dvb.iptv.alfec-enhancement +# application/vnd.dvb.notif-aggregate-root+xml +# application/vnd.dvb.notif-container+xml +# application/vnd.dvb.notif-generic+xml +# application/vnd.dvb.notif-ia-msglist+xml +# application/vnd.dvb.notif-ia-registration-request+xml +# application/vnd.dvb.notif-ia-registration-response+xml +# application/vnd.dvb.notif-init+xml +# application/vnd.dvb.pfr +application/vnd.dvb.service svc +# application/vnd.dxr +application/vnd.dynageo geo +# application/vnd.easykaraoke.cdgdownload +# application/vnd.ecdis-update +application/vnd.ecowin.chart mag +# application/vnd.ecowin.filerequest +# application/vnd.ecowin.fileupdate +# application/vnd.ecowin.series +# application/vnd.ecowin.seriesrequest +# application/vnd.ecowin.seriesupdate +# application/vnd.emclient.accessrequest+xml +application/vnd.enliven nml +# application/vnd.eprints.data+xml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +# application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +# application/vnd.etsi.aoc+xml +# application/vnd.etsi.cug+xml +# application/vnd.etsi.iptvcommand+xml +# application/vnd.etsi.iptvdiscovery+xml +# application/vnd.etsi.iptvprofile+xml +# application/vnd.etsi.iptvsad-bc+xml +# application/vnd.etsi.iptvsad-cod+xml +# application/vnd.etsi.iptvsad-npvr+xml +# application/vnd.etsi.iptvservice+xml +# application/vnd.etsi.iptvsync+xml +# application/vnd.etsi.iptvueprofile+xml +# application/vnd.etsi.mcid+xml +# application/vnd.etsi.overload-control-policy-dataset+xml +# application/vnd.etsi.sci+xml +# application/vnd.etsi.simservs+xml +# application/vnd.etsi.tsl+xml +# application/vnd.etsi.tsl.der +# application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +# application/vnd.f-secure.mobile +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed dataless +# application/vnd.ffsns +# application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +# application/vnd.font-fontforge-sfd +application/vnd.framemaker fm frame maker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +# application/vnd.fujixerox.art-ex +# application/vnd.fujixerox.art4 +# application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +# application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +# application/vnd.geocube+xml +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +# application/vnd.globalplatform.card-content-mgt +# application/vnd.globalplatform.card-content-mgt-response +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +# application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +# application/vnd.hal+json +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +# application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +# application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +# application/vnd.hzn-3d-crossword +# application/vnd.ibm.afplinedata +# application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +# application/vnd.informedcontrol.rms+xml +# application/vnd.informix-visionary +# application/vnd.infotech.project +# application/vnd.infotech.project+xml +# application/vnd.innopath.wamp.notification +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +# application/vnd.intertrust.digibox +# application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +# application/vnd.iptc.g2.conceptitem+xml +# application/vnd.iptc.g2.knowledgeitem+xml +# application/vnd.iptc.g2.newsitem+xml +# application/vnd.iptc.g2.newsmessage+xml +# application/vnd.iptc.g2.packageitem+xml +# application/vnd.iptc.g2.planningitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +# application/vnd.japannet-directory-service +# application/vnd.japannet-jpnstore-wakeup +# application/vnd.japannet-payment-wakeup +# application/vnd.japannet-registration +# application/vnd.japannet-registration-wakeup +# application/vnd.japannet-setstore-wakeup +# application/vnd.japannet-verification +# application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +# application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +# application/vnd.marlin.drm.actiontoken+xml +# application/vnd.marlin.drm.conftoken+xml +# application/vnd.marlin.drm.license+xml +# application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +# application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +# application/vnd.minisoft-hp3000-save +# application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +# application/vnd.motorola.flexsuite +# application/vnd.motorola.flexsuite.adsi +# application/vnd.motorola.flexsuite.fis +# application/vnd.motorola.flexsuite.gotap +# application/vnd.motorola.flexsuite.kmr +# application/vnd.motorola.flexsuite.ttc +# application/vnd.motorola.flexsuite.wem +# application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +# application/vnd.ms-asf +application/vnd.ms-cab-compressed cab +# application/vnd.ms-color.iccprofile +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +# application/vnd.ms-office.activex+xml +application/vnd.ms-officetheme thmx +# application/vnd.ms-opentype +# application/vnd.ms-package.obfuscated-opentype +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +# application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +# application/vnd.ms-printing.printticket+xml +application/vnd.ms-project mpp mpt +# application/vnd.ms-tnef +# application/vnd.ms-wmdrm.lic-chlg-req +# application/vnd.ms-wmdrm.lic-resp +# application/vnd.ms-wmdrm.meter-chlg-req +# application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +# application/vnd.msign +# application/vnd.multiad.creator +# application/vnd.multiad.creator.cif +# application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +# application/vnd.ncd.control +# application/vnd.ncd.reference +# application/vnd.nervana +# application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf ntf nitf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +# application/vnd.nokia.catalogs +# application/vnd.nokia.conml+wbxml +# application/vnd.nokia.conml+xml +# application/vnd.nokia.isds-radio-presets +# application/vnd.nokia.iptv.config+xml +# application/vnd.nokia.landmark+wbxml +# application/vnd.nokia.landmark+xml +# application/vnd.nokia.landmarkcollection+xml +# application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +# application/vnd.nokia.ncd +# application/vnd.nokia.pcd+wbxml +# application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +# application/vnd.ntt-local.file-transfer +# application/vnd.ntt-local.sip-ta_remote +# application/vnd.ntt-local.sip-ta_tcp_stream +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +# application/vnd.obn +# application/vnd.oftn.l10n+json +# application/vnd.oipf.contentaccessdownload+xml +# application/vnd.oipf.contentaccessstreaming+xml +# application/vnd.oipf.cspg-hexbinary +# application/vnd.oipf.dae.svg+xml +# application/vnd.oipf.dae.xhtml+xml +# application/vnd.oipf.mippvcontrolmessage+xml +# application/vnd.oipf.pae.gem +# application/vnd.oipf.spdiscovery+xml +# application/vnd.oipf.spdlist+xml +# application/vnd.oipf.ueprofile+xml +# application/vnd.oipf.userprofile+xml +application/vnd.olpc-sugar xo +# application/vnd.oma-scws-config +# application/vnd.oma-scws-http-request +# application/vnd.oma-scws-http-response +# application/vnd.oma.bcast.associated-procedure-parameter+xml +# application/vnd.oma.bcast.drm-trigger+xml +# application/vnd.oma.bcast.imd+xml +# application/vnd.oma.bcast.ltkm +# application/vnd.oma.bcast.notification+xml +# application/vnd.oma.bcast.provisioningtrigger +# application/vnd.oma.bcast.sgboot +# application/vnd.oma.bcast.sgdd+xml +# application/vnd.oma.bcast.sgdu +# application/vnd.oma.bcast.simple-symbol-container +# application/vnd.oma.bcast.smartcard-trigger+xml +# application/vnd.oma.bcast.sprov+xml +# application/vnd.oma.bcast.stkm +# application/vnd.oma.cab-address-book+xml +# application/vnd.oma.cab-feature-handler+xml +# application/vnd.oma.cab-pcc+xml +# application/vnd.oma.cab-user-prefs+xml +# application/vnd.oma.dcd +# application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +# application/vnd.oma.drm.risd+xml +# application/vnd.oma.group-usage-list+xml +# application/vnd.oma.pal+xml +# application/vnd.oma.poc.detailed-progress-report+xml +# application/vnd.oma.poc.final-report+xml +# application/vnd.oma.poc.groups+xml +# application/vnd.oma.poc.invocation-descriptor+xml +# application/vnd.oma.poc.optimized-progress-report+xml +# application/vnd.oma.push +# application/vnd.oma.scidm.messages+xml +# application/vnd.oma.xcap-directory+xml +# application/vnd.omads-email+xml +# application/vnd.omads-file+xml +# application/vnd.omads-folder+xml +# application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +# application/vnd.openxmlformats-officedocument.custom-properties+xml +# application/vnd.openxmlformats-officedocument.customxmlproperties+xml +# application/vnd.openxmlformats-officedocument.drawing+xml +# application/vnd.openxmlformats-officedocument.drawingml.chart+xml +# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml +# application/vnd.openxmlformats-officedocument.extended-properties+xml +# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml +# application/vnd.openxmlformats-officedocument.presentationml.comments+xml +# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +# application/vnd.openxmlformats-officedocument.presentationml.slide+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml +# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml +# application/vnd.openxmlformats-officedocument.presentationml.tags+xml +application/vnd.openxmlformats-officedocument.presentationml.template potx +# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml +# application/vnd.openxmlformats-officedocument.theme+xml +# application/vnd.openxmlformats-officedocument.themeoverride+xml +# application/vnd.openxmlformats-officedocument.vmldrawing +# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml +# application/vnd.openxmlformats-package.core-properties+xml +# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml +# application/vnd.openxmlformats-package.relationships+xml +# application/vnd.quobject-quoxdocument +# application/vnd.osa.netdeploy +application/vnd.osgeo.mapguide.package mgp +# application/vnd.osgi.bundle +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +# application/vnd.otps.ct-kip+xml +application/vnd.palm pdb pqa oprc +# application/vnd.paos.xml +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +# application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.pmi.widget wg +# application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +# application/vnd.powerbuilder6-s +# application/vnd.powerbuilder7 +# application/vnd.powerbuilder7-s +# application/vnd.powerbuilder75 +# application/vnd.powerbuilder75-s +# application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +# application/vnd.pwg-multiplexed +# application/vnd.pwg-xhtml-print+xml +# application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +# application/vnd.radisys.moml+xml +# application/vnd.radisys.msml+xml +# application/vnd.radisys.msml-audit+xml +# application/vnd.radisys.msml-audit-conf+xml +# application/vnd.radisys.msml-audit-conn+xml +# application/vnd.radisys.msml-audit-dialog+xml +# application/vnd.radisys.msml-audit-stream+xml +# application/vnd.radisys.msml-conf+xml +# application/vnd.radisys.msml-dialog+xml +# application/vnd.radisys.msml-dialog-base+xml +# application/vnd.radisys.msml-dialog-fax-detect+xml +# application/vnd.radisys.msml-dialog-fax-sendrecv+xml +# application/vnd.radisys.msml-dialog-group+xml +# application/vnd.radisys.msml-dialog-speech+xml +# application/vnd.radisys.msml-dialog-transform+xml +# application/vnd.rainstor.data +# application/vnd.rapid +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +# application/vnd.renlearn.rlprint +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +# application/vnd.rs-274x +# application/vnd.ruckus.download +# application/vnd.s3sms +application/vnd.sailingtracker.track st +# application/vnd.sbm.cid +# application/vnd.sbm.mid2 +# application/vnd.scribus +# application/vnd.sealed.3df +# application/vnd.sealed.csf +# application/vnd.sealed.doc +# application/vnd.sealed.eml +# application/vnd.sealed.mht +# application/vnd.sealed.net +# application/vnd.sealed.ppt +# application/vnd.sealed.tiff +# application/vnd.sealed.xls +# application/vnd.sealedmedia.softseal.html +# application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +# application/vnd.smart.notebook +application/vnd.smart.teacher teacher +# application/vnd.software602.filler.form+xml +# application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +# application/vnd.sss-cod +# application/vnd.sss-dtf +# application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +# application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +# application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +# application/vnd.swiftview-ics +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +# application/vnd.syncml.dm.notification +# application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +# application/vnd.truedoc +# application/vnd.ubisoft.webplayer +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +# application/vnd.uplanet.alert +# application/vnd.uplanet.alert-wbxml +# application/vnd.uplanet.bearer-choice +# application/vnd.uplanet.bearer-choice-wbxml +# application/vnd.uplanet.cacheop +# application/vnd.uplanet.cacheop-wbxml +# application/vnd.uplanet.channel +# application/vnd.uplanet.channel-wbxml +# application/vnd.uplanet.list +# application/vnd.uplanet.list-wbxml +# application/vnd.uplanet.listcmd +# application/vnd.uplanet.listcmd-wbxml +# application/vnd.uplanet.signal +application/vnd.vcx vcx +# application/vnd.vd-study +# application/vnd.vectorworks +# application/vnd.verimatrix.vcas +# application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +# application/vnd.vividence.scriptfile +application/vnd.vsf vsf +# application/vnd.wap.sic +# application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +# application/vnd.wfa.wsc +# application/vnd.wmc +# application/vnd.wmf.bootstrap +# application/vnd.wolfram.mathematica +# application/vnd.wolfram.mathematica.package +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +# application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +# application/vnd.wv.csp+wbxml +# application/vnd.wv.csp+xml +# application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +# application/vnd.xfdl.webform +# application/vnd.xmi+xml +# application/vnd.xmpie.cpkg +# application/vnd.xmpie.dpkg +# application/vnd.xmpie.plan +# application/vnd.xmpie.ppkg +# application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +# application/vnd.yamaha.remote-setup +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +# application/vnd.yamaha.through-ngn +# application/vnd.yamaha.tunnel-udpencap +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +# application/vq-rtcpxr +# application/watcherinfo+xml +# application/whoispp-query +# application/whoispp-response +application/widget wgt +application/winhlp hlp +# application/wita +# application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +# application/x-amf +application/x-apple-diskimage dmg +application/x-authorware-bin aab x32 u32 vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cbr cbr cba cbt cbz cb7 +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-conference nsc +# application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-dgc-compressed dgc +application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +# application/x-font-dos +# application/x-font-framemaker +application/x-font-ghostscript gsf +# application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf otf +application/x-font-pcf pcf +application/x-font-snf snf +# application/x-font-speedo +# application/x-font-sunos-news +application/x-font-ttf ttf ttc +application/x-font-type1 pfa pfb pfm afm +application/x-font-woff woff +# application/x-font-vfont +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +# application/x-gzip +application/x-hdf hdf +application/x-install-instructions install +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-lzh-compressed lzh lha +application/x-mie mie +application/x-mobipocket-ebook prc mobi +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf wmz emf emz +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-nzb nzb +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-research-info-systems ris +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-tgif obj +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +# application/x400-bp +application/xaml+xml xaml +# application/xcap-att+xml +# application/xcap-caps+xml +application/xcap-diff+xml xdf +# application/xcap-el+xml +# application/xcap-error+xml +# application/xcap-ns+xml +# application/xcon-conference-info-diff+xml +# application/xcon-conference-info+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +# application/xhtml-voice+xml +application/xml xml xsl +application/xml-dtd dtd +# application/xml-external-parsed-entity +# application/xmpp+xml +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yin+xml yin +application/zip zip +# audio/1d-interleaved-parityfec +# audio/32kadpcm +# audio/3gpp +# audio/3gpp2 +# audio/ac3 +audio/adpcm adp +# audio/amr +# audio/amr-wb +# audio/amr-wb+ +# audio/asc +# audio/atrac-advanced-lossless +# audio/atrac-x +# audio/atrac3 +audio/basic au snd +# audio/bv16 +# audio/bv32 +# audio/clearmode +# audio/cn +# audio/dat12 +# audio/dls +# audio/dsr-es201108 +# audio/dsr-es202050 +# audio/dsr-es202211 +# audio/dsr-es202212 +# audio/dv +# audio/dvi4 +# audio/eac3 +# audio/evrc +# audio/evrc-qcp +# audio/evrc0 +# audio/evrc1 +# audio/evrcb +# audio/evrcb0 +# audio/evrcb1 +# audio/evrcwb +# audio/evrcwb0 +# audio/evrcwb1 +# audio/example +# audio/fwdred +# audio/g719 +# audio/g722 +# audio/g7221 +# audio/g723 +# audio/g726-16 +# audio/g726-24 +# audio/g726-32 +# audio/g726-40 +# audio/g728 +# audio/g729 +# audio/g7291 +# audio/g729d +# audio/g729e +# audio/gsm +# audio/gsm-efr +# audio/gsm-hr-08 +# audio/ilbc +# audio/ip-mr_v2.5 +# audio/isac +# audio/l16 +# audio/l20 +# audio/l24 +# audio/l8 +# audio/lpc +audio/midi mid midi kar rmi +# audio/mobile-xmf +audio/mp4 mp4a +# audio/mp4a-latm +# audio/mpa +# audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +# audio/mpeg4-generic +# audio/musepack +audio/ogg oga ogg spx +# audio/opus +# audio/parityfec +# audio/pcma +# audio/pcma-wb +# audio/pcmu-wb +# audio/pcmu +# audio/prs.sid +# audio/qcelp +# audio/red +# audio/rtp-enc-aescm128 +# audio/rtp-midi +# audio/rtx +audio/s3m s3m +audio/silk sil +# audio/smv +# audio/smv0 +# audio/smv-qcp +# audio/sp-midi +# audio/speex +# audio/t140c +# audio/t38 +# audio/telephone-event +# audio/tone +# audio/uemclip +# audio/ulpfec +# audio/vdvi +# audio/vmr-wb +# audio/vnd.3gpp.iufp +# audio/vnd.4sb +# audio/vnd.audiokoz +# audio/vnd.celp +# audio/vnd.cisco.nse +# audio/vnd.cmles.radio-events +# audio/vnd.cns.anp1 +# audio/vnd.cns.inf1 +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +# audio/vnd.dlna.adts +# audio/vnd.dolby.heaac.1 +# audio/vnd.dolby.heaac.2 +# audio/vnd.dolby.mlp +# audio/vnd.dolby.mps +# audio/vnd.dolby.pl2 +# audio/vnd.dolby.pl2x +# audio/vnd.dolby.pl2z +# audio/vnd.dolby.pulse.1 +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +# audio/vnd.dvb.file +# audio/vnd.everad.plj +# audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +# audio/vnd.nokia.mobile-xmf +# audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +# audio/vnd.octel.sbc +# audio/vnd.qcelp +# audio/vnd.rhetorex.32kadpcm +audio/vnd.rip rip +# audio/vnd.sealedmedia.softseal.mpeg +# audio/vnd.vmx.cvsd +# audio/vorbis +# audio/vorbis-config +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aiff aifc +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +# audio/x-tta +audio/x-wav wav +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +# chemical/x-pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +# image/example +# image/fits +image/g3fax g3 +image/gif gif +image/ief ief +# image/jp2 +image/jpeg jpeg jpg jpe +# image/jpm +# image/jpx +image/ktx ktx +# image/naplps +image/png png +image/prs.btif btif +# image/prs.pti +image/sgi sgi +image/svg+xml svg svgz +# image/t38 +image/tiff tiff tif +# image/tiff-fx +image/vnd.adobe.photoshop psd +# image/vnd.cns.inf2 +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.dvb.subtitle sub +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +# image/vnd.globalgraphics.pgb +# image/vnd.microsoft.icon +# image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +# image/vnd.radiance +# image/vnd.sealed.png +# image/vnd.sealedmedia.softseal.gif +# image/vnd.sealedmedia.softseal.jpg +# image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +image/x-mrsid-image sid +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +# message/cpim +# message/delivery-status +# message/disposition-notification +# message/example +# message/external-body +# message/feedback-report +# message/global +# message/global-delivery-status +# message/global-disposition-notification +# message/global-headers +# message/http +# message/imdn+xml +# message/news +# message/partial +message/rfc822 eml mime +# message/s-http +# message/sip +# message/sipfrag +# message/tracking-status +# message/vnd.si.simp +# model/example +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +# model/vnd.flatland.3dml +model/vnd.gdl gdl +# model/vnd.gs-gdl +# model/vnd.gs.gdl +model/vnd.gtw gtw +# model/vnd.moml+xml +model/vnd.mts mts +# model/vnd.parasolid.transmit.binary +# model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +# multipart/alternative +# multipart/appledouble +# multipart/byteranges +# multipart/digest +# multipart/encrypted +# multipart/example +# multipart/form-data +# multipart/header-set +# multipart/mixed +# multipart/parallel +# multipart/related +# multipart/report +# multipart/signed +# multipart/voice-message +# text/1d-interleaved-parityfec +text/cache-manifest appcache +text/calendar ics ifb +text/css css +text/csv csv +# text/directory +# text/dns +# text/ecmascript +# text/enriched +# text/example +# text/fwdred +text/html html htm +# text/javascript +text/n3 n3 +# text/parityfec +text/plain txt text conf def list log in +# text/prs.fallenstein.rst +text/prs.lines.tag dsc +# text/vnd.radisys.msml-basic-layout +# text/red +# text/rfc822-headers +text/richtext rtx +# text/rtf +# text/rtp-enc-aescm128 +# text/rtx +text/sgml sgml sgm +# text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/turtle ttl +# text/ulpfec +text/uri-list uri uris urls +text/vcard vcard +# text/vnd.abc +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.scurl scurl +text/vnd.curl.mcurl mcurl +# text/vnd.dmclientscript +text/vnd.dvb.subtitle sub +# text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +# text/vnd.iptc.newsml +# text/vnd.iptc.nitf +# text/vnd.latex-z +# text/vnd.motorola.reflex +# text/vnd.ms-mediapackage +# text/vnd.net2phone.commcenter.command +# text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +# text/vnd.trolltech.linguist +# text/vnd.wap.si +# text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-java-source java +text/x-opml opml +text/x-pascal p pas +text/x-nfo nfo +text/x-setext etx +text/x-sfv sfv +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +# text/xml +# text/xml-external-parsed-entity +# video/1d-interleaved-parityfec +video/3gpp 3gp +# video/3gpp-tt +video/3gpp2 3g2 +# video/bmpeg +# video/bt656 +# video/celb +# video/dv +# video/example +video/h261 h261 +video/h263 h263 +# video/h263-1998 +# video/h263-2000 +video/h264 h264 +# video/h264-rcdo +# video/h264-svc +video/jpeg jpgv +# video/jpeg2000 +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +# video/mp1s +# video/mp2p +# video/mp2t +video/mp4 mp4 mp4v mpg4 +# video/mp4v-es +video/mpeg mpeg mpg mpe m1v m2v +# video/mpeg4-generic +# video/mpv +# video/nv +video/ogg ogv +# video/parityfec +# video/pointer +video/quicktime qt mov +# video/raw +# video/rtp-enc-aescm128 +# video/rtx +# video/smpte292m +# video/ulpfec +# video/vc1 +# video/vnd.cctv +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +# video/vnd.dece.mp4 +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +# video/vnd.directv.mpeg +# video/vnd.directv.mpeg-tts +# video/vnd.dlna.mpeg-tts +video/vnd.dvb.file dvb +video/vnd.fvt fvt +# video/vnd.hns.video +# video/vnd.iptvforum.1dparityfec-1010 +# video/vnd.iptvforum.1dparityfec-2005 +# video/vnd.iptvforum.2dparityfec-1010 +# video/vnd.iptvforum.2dparityfec-2005 +# video/vnd.iptvforum.ttsavc +# video/vnd.iptvforum.ttsmpeg2 +# video/vnd.motorola.video +# video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +# video/vnd.nokia.interleaved-multimedia +# video/vnd.nokia.videovoip +# video/vnd.objectvideo +# video/vnd.sealed.mpeg1 +# video/vnd.sealed.mpeg4 +# video/vnd.sealed.swf +# video/vnd.sealedmedia.softseal.mov +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mkv mk3d mks +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index 68d4b213..0de5e254 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -56,10 +56,16 @@ module Jekyll # # Returns the template String. def template - if self.site.permalink_style == :pretty && !index? && html? - "/:basename/" + if self.site.permalink_style == :pretty + if index? && html? + "/:path/" + elsif html? + "/:path/:basename/" + else + "/:path/:basename:output_ext" + end else - "/:basename:output_ext" + "/:path/:basename:output_ext" end end @@ -73,6 +79,7 @@ module Jekyll permalink else { + "path" => @dir, "basename" => self.basename, "output_ext" => self.output_ext, }.inject(template) { |result, token| @@ -116,7 +123,7 @@ module Jekyll # Returns the Hash representation of this Page. def to_liquid self.data.deep_merge({ - "url" => File.join(@dir, self.url), + "url" => self.url, "content" => self.content }) end @@ -128,7 +135,7 @@ module Jekyll def destination(dest) # The url needs to be unescaped in order to preserve the correct # filename. - path = File.join(dest, @dir, CGI.unescape(self.url)) + path = File.join(dest, CGI.unescape(self.url)) path = File.join(path, "index.html") if self.url =~ /\/$/ path end diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index b8d0ad55..d40993de 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -29,12 +29,11 @@ module Jekyll # site - The Site. # base - The String path to the dir containing the post file. # name - The String filename of the post file. - # categories - An Array of Strings for the categories for this post. # # Returns the new Post. def initialize(site, source, dir, name) @site = site - @base = File.join(source, dir, '_posts') + @base = self.containing_dir(source, dir) @name = name self.categories = dir.split('/').reject { |x| x.empty? } @@ -65,6 +64,11 @@ module Jekyll end end + # Get the full path to the directory containing the post files + def containing_dir(source, dir) + return File.join(source, dir, '_posts') + end + # Read the YAML frontmatter. # # base - The String path to the dir containing the file. diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 2deae484..3b21c6ad 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -5,7 +5,7 @@ module Jekyll attr_accessor :config, :layouts, :posts, :pages, :static_files, :categories, :exclude, :include, :source, :dest, :lsi, :pygments, :permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts, - :keep_files + :show_drafts, :keep_files attr_accessor :converters, :generators @@ -18,13 +18,14 @@ module Jekyll self.safe = config['safe'] self.source = File.expand_path(config['source']) self.dest = File.expand_path(config['destination']) - self.plugins = Array(config['plugins']).map { |d| File.expand_path(d) } + self.plugins = plugins_path self.lsi = config['lsi'] self.pygments = config['pygments'] self.permalink_style = config['permalink'].to_sym self.exclude = config['exclude'] || [] self.include = config['include'] || [] self.future = config['future'] + self.show_drafts = config['show_drafts'] || nil self.limit_posts = config['limit_posts'] || nil self.keep_files = config['keep_files'] || [] @@ -87,16 +88,18 @@ module Jekyll end end - self.converters = Jekyll::Converter.subclasses.select do |c| - !self.safe || c.safe - end.map do |c| - c.new(self.config) - end + self.converters = instantiate_subclasses(Jekyll::Converter) + self.generators = instantiate_subclasses(Jekyll::Generator) + end - self.generators = Jekyll::Generator.subclasses.select do |c| - !self.safe || c.safe - end.map do |c| - c.new(self.config) + # Internal: Setup the plugin search path + # + # Returns an Array of plugin search paths + def plugins_path + if (config['plugins'] == Jekyll::DEFAULTS['plugins']) + [File.join(self.source, config['plugins'])] + else + Array(config['plugins']).map { |d| File.expand_path(d) } end end @@ -137,6 +140,18 @@ module Jekyll self.read_posts(dir) + if self.show_drafts + self.read_drafts(dir) + end + + self.posts.sort! + + # limit the posts if :limit_posts option is set + if limit_posts + limit = self.posts.length < limit_posts ? self.posts.length : limit_posts + self.posts = self.posts[-limit, limit] + end + entries.each do |f| f_abs = File.join(base, f) f_rel = File.join(dir, f) @@ -163,9 +178,7 @@ module Jekyll # # Returns nothing. def read_posts(dir) - base = File.join(self.source, dir, '_posts') - return unless File.exists?(base) - entries = Dir.chdir(base) { filter_entries(Dir['**/*']) } + entries = get_entries(dir, '_posts') # first pass processes, but does not yet render post content entries.each do |f| @@ -173,19 +186,28 @@ module Jekyll post = Post.new(self, self.source, dir, f) if post.published && (self.future || post.date <= self.time) - self.posts << post - post.categories.each { |c| self.categories[c] << post } - post.tags.each { |c| self.tags[c] << post } + aggregate_post_info(post) end end end + end - self.posts.sort! + # Read all the files in //_drafts and create a new Post + # object with each one. + # + # dir - The String relative path of the directory to read. + # + # Returns nothing. + def read_drafts(dir) + entries = get_entries(dir, '_drafts') - # limit the posts if :limit_posts option is set - if limit_posts - limit = self.posts.length < limit_posts ? self.posts.length : limit_posts - self.posts = self.posts[-limit, limit] + # first pass processes, but does not yet render draft content + entries.each do |f| + if Draft.valid?(f) + draft = Draft.new(self, self.source, dir, f) + + aggregate_post_info(draft) + end end end @@ -253,7 +275,7 @@ module Jekyll end # Private: creates a regular expression from the keep_files array - # + # # Examples # ['.git','.svn'] creates the following regex: /\/(\.git|\/.svn)/ # @@ -338,7 +360,7 @@ module Jekyll ['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.glob_include?(e) || - File.symlink?(e) + (File.symlink?(e) && self.safe) end end end @@ -356,5 +378,43 @@ module Jekyll raise "Converter implementation not found for #{klass}" end end + + # Create array of instances of the subclasses of the class or module + # passed in as argument. + # + # klass - class or module containing the subclasses which should be + # instantiated + # + # Returns array of instances of subclasses of parameter + def instantiate_subclasses(klass) + klass.subclasses.select do |c| + !self.safe || c.safe + end.sort.map do |c| + c.new(self.config) + end + end + + # Read the entries from a particular directory for processing + # + # dir - The String relative path of the directory to read + # subfolder - The String directory to read + # + # Returns the list of entries to process + def get_entries(dir, subfolder) + base = File.join(self.source, dir, subfolder) + return [] unless File.exists?(base) + entries = Dir.chdir(base) { filter_entries(Dir['**/*']) } + end + + # Aggregate post information + # + # post - The Post object to aggregate information for + # + # Returns nothing + def aggregate_post_info(post) + self.posts << post + post.categories.each { |c| self.categories[c] << post } + post.tags.each { |c| self.tags[c] << post } + end end end diff --git a/lib/jekyll/tags/gist.rb b/lib/jekyll/tags/gist.rb new file mode 100644 index 00000000..d3eb0b37 --- /dev/null +++ b/lib/jekyll/tags/gist.rb @@ -0,0 +1,19 @@ +# Gist Liquid Tag +# +# Example: +# {% gist 1234567 %} + +module Jekyll + class GistTag < Liquid::Tag + def initialize(tag_name, gist, tokens) + super + @gist = gist.strip + end + + def render(context) + "" + end + end +end + +Liquid::Template.register_tag('gist', Jekyll::GistTag) diff --git a/lib/jekyll/tags/highlight.rb b/lib/jekyll/tags/highlight.rb index b36a8a01..c84ea111 100644 --- a/lib/jekyll/tags/highlight.rb +++ b/lib/jekyll/tags/highlight.rb @@ -30,7 +30,13 @@ module Jekyll end end else - raise SyntaxError.new("Syntax Error in 'highlight' - Valid syntax: highlight [linenos]") + raise SyntaxError.new <<-eos +Syntax Error in tag 'highlight' while parsing the following markup: + + #{markup} + +Valid syntax: highlight [linenos] +eos end end diff --git a/lib/jekyll/tags/post_url.rb b/lib/jekyll/tags/post_url.rb index ff4a29b8..6dbec9be 100644 --- a/lib/jekyll/tags/post_url.rb +++ b/lib/jekyll/tags/post_url.rb @@ -23,7 +23,11 @@ module Jekyll site = context.registers[:site] site.posts.each do |p| - if p == @post + if p.slug == @post.slug \ + and p.date.year == @post.date.year \ + and p.date.month == @post.date.month \ + and p.date.day == @post.date.day + return p.url end end diff --git a/test/helper.rb b/test/helper.rb index c4df5f28..f4bdcf19 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -5,6 +5,7 @@ if RUBY_VERSION > '1.9' && ENV["COVERAGE"] == "true" end require 'rubygems' +require 'test/unit' gem 'RedCloth', '>= 4.2.1' require 'jekyll' diff --git a/test/source/_plugins/dummy.rb b/test/source/_plugins/dummy.rb new file mode 100644 index 00000000..bfd46e1c --- /dev/null +++ b/test/source/_plugins/dummy.rb @@ -0,0 +1,8 @@ +module Jekyll + class Dummy < Generator + priority :high + + def generate(site) + end + end +end diff --git a/test/source/contacts/bar.html b/test/source/contacts/bar.html new file mode 100644 index 00000000..1615afe2 --- /dev/null +++ b/test/source/contacts/bar.html @@ -0,0 +1,5 @@ +--- +title: Contact Information +--- + +Contact Information diff --git a/test/source/contacts/index.html b/test/source/contacts/index.html new file mode 100644 index 00000000..1615afe2 --- /dev/null +++ b/test/source/contacts/index.html @@ -0,0 +1,5 @@ +--- +title: Contact Information +--- + +Contact Information diff --git a/test/suite.rb b/test/suite.rb index 98923ca1..81b61719 100644 --- a/test/suite.rb +++ b/test/suite.rb @@ -8,4 +8,4 @@ require 'test/unit' tests = Dir[File.expand_path("#{File.dirname(__FILE__)}/test_*.rb")] tests.each do |file| require file -end \ No newline at end of file +end diff --git a/test/test_configuration.rb b/test/test_configuration.rb index 76e8a812..40b091de 100644 --- a/test/test_configuration.rb +++ b/test/test_configuration.rb @@ -7,23 +7,49 @@ class TestConfiguration < Test::Unit::TestCase end should "fire warning with no _config.yml" do - mock(YAML).load_file(@path) { raise "No such file or directory - #{@path}" } - mock($stderr).puts("WARNING: Could not read configuration. Using defaults (and options).") - mock($stderr).puts("\tNo such file or directory - #{@path}") + mock(YAML).safe_load_file(@path) { raise SystemCallError, "No such file or directory - #{@path}" } + mock($stderr).puts("Configuration file: none") assert_equal Jekyll::DEFAULTS, Jekyll.configuration({}) end should "load configuration as hash" do - mock(YAML).load_file(@path) { Hash.new } - mock($stdout).puts("Configuration from #{@path}") + mock(YAML).safe_load_file(@path) { Hash.new } + mock($stdout).puts("Configuration file: #{@path}") assert_equal Jekyll::DEFAULTS, Jekyll.configuration({}) end should "fire warning with bad config" do - mock(YAML).load_file(@path) { Array.new } - mock($stderr).puts("WARNING: Could not read configuration. Using defaults (and options).") - mock($stderr).puts("\tInvalid configuration - #{@path}") + mock(YAML).safe_load_file(@path) { Array.new } + mock($stderr).puts(" WARNING: Error reading configuration. Using defaults (and options).") + mock($stderr).puts("Configuration file: (INVALID) #{@path}") assert_equal Jekyll::DEFAULTS, Jekyll.configuration({}) end end + context "loading config from external file" do + setup do + @paths = { + :default => File.join(Dir.pwd, '_config.yml'), + :other => File.join(Dir.pwd, '_config.live.yml'), + :empty => "" + } + end + + should "load default config if no config_file is set" do + mock(YAML).safe_load_file(@paths[:default]) { Hash.new } + mock($stdout).puts("Configuration file: #{@paths[:default]}") + assert_equal Jekyll::DEFAULTS, Jekyll.configuration({}) + end + + should "load different config if specified" do + mock(YAML).safe_load_file(@paths[:other]) { {"baseurl" => "http://wahoo.dev"} } + mock($stdout).puts("Configuration file: #{@paths[:other]}") + assert_equal Jekyll::DEFAULTS.deep_merge({ "baseurl" => "http://wahoo.dev" }), Jekyll.configuration({ "config" => @paths[:other] }) + end + + should "load default config if path passed is empty" do + mock(YAML).safe_load_file(@paths[:default]) { Hash.new } + mock($stdout).puts("Configuration file: #{@paths[:default]}") + assert_equal Jekyll::DEFAULTS, Jekyll.configuration({ "config" => @paths[:empty] }) + end + end end diff --git a/test/test_kramdown.rb b/test/test_kramdown.rb index 8aa72faf..981cdaf3 100644 --- a/test/test_kramdown.rb +++ b/test/test_kramdown.rb @@ -23,11 +23,11 @@ class TestKramdown < Test::Unit::TestCase should "convert quotes to smart quotes" do markdown = Converters::Markdown.new(@config) - assert_equal "

“Pit’hy”

", markdown.convert(%{"Pit'hy"}).strip + assert_equal "

“Pit’hy”

", markdown.convert(%{"Pit'hy"}).strip override = { 'kramdown' => { 'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo' } } markdown = Converters::Markdown.new(@config.deep_merge(override)) - assert_equal "

«Pit›hy»

", markdown.convert(%{"Pit'hy"}).strip + assert_equal "

«Pit›hy»

", markdown.convert(%{"Pit'hy"}).strip end end end diff --git a/test/test_page.rb b/test/test_page.rb index 3c7c9fed..fda7cd9c 100644 --- a/test/test_page.rb +++ b/test/test_page.rb @@ -1,8 +1,10 @@ require 'helper' class TestPage < Test::Unit::TestCase - def setup_page(file) - @page = Page.new(@site, source_dir, '', file) + def setup_page(*args) + dir, file = args + dir, file = ['', dir] if file.nil? + @page = Page.new(@site, source_dir, dir, file) end def do_render(page) @@ -23,6 +25,18 @@ class TestPage < Test::Unit::TestCase assert_equal "/contacts.html", @page.url end + context "in a directory hierarchy" do + should "create url based on filename" do + @page = setup_page('/contacts', 'bar.html') + assert_equal "/contacts/bar.html", @page.url + end + + should "create index url based on filename" do + @page = setup_page('/contacts', 'index.html') + assert_equal "/contacts/index.html", @page.url + end + end + should "deal properly with extensions" do @page = setup_page('deal.with.dots.html') assert_equal ".html", @page.ext @@ -47,6 +61,28 @@ class TestPage < Test::Unit::TestCase @page = setup_page('index.html') assert_equal '/', @page.dir end + + context "in a directory hierarchy" do + should "create url based on filename" do + @page = setup_page('/contacts', 'bar.html') + assert_equal "/contacts/bar/", @page.url + end + + should "create index url based on filename" do + @page = setup_page('/contacts', 'index.html') + assert_equal "/contacts/", @page.url + end + + should "return dir correctly" do + @page = setup_page('/contacts', 'bar.html') + assert_equal '/contacts/bar/', @page.dir + end + + should "return dir correctly for index page" do + @page = setup_page('/contacts', 'index.html') + assert_equal '/contacts/', @page.dir + end + end end context "with any other url style" do @@ -131,6 +167,36 @@ class TestPage < Test::Unit::TestCase assert File.directory?(dest_dir) assert File.exists?(File.join(dest_dir, '.htaccess')) end + + context "in a directory hierarchy" do + should "write properly the index" do + page = setup_page('/contacts', 'index.html') + do_render(page) + page.write(dest_dir) + + assert File.directory?(dest_dir) + assert File.exists?(File.join(dest_dir, 'contacts', 'index.html')) + end + + should "write properly" do + page = setup_page('/contacts', 'bar.html') + do_render(page) + page.write(dest_dir) + + assert File.directory?(dest_dir) + assert File.exists?(File.join(dest_dir, 'contacts', 'bar.html')) + end + + should "write properly without html extension" do + page = setup_page('/contacts', 'bar.html') + page.site.permalink_style = :pretty + do_render(page) + page.write(dest_dir) + + assert File.directory?(dest_dir) + assert File.exists?(File.join(dest_dir, 'contacts', 'bar', 'index.html')) + end + end end end diff --git a/test/test_site.rb b/test/test_site.rb index c698a887..07182727 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -7,6 +7,11 @@ class TestSite < Test::Unit::TestCase assert_equal [File.join(Dir.pwd, '_plugins')], site.plugins end + should "look for plugins under the site directory by default" do + site = Site.new(Jekyll::DEFAULTS.merge({'source' => File.expand_path(source_dir)})) + assert_equal [File.join(source_dir, '_plugins')], site.plugins + end + should "have an array for plugins if passed as a string" do site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => '/tmp/plugins'})) assert_equal ['/tmp/plugins'], site.plugins @@ -26,6 +31,7 @@ class TestSite < Test::Unit::TestCase site = Site.new(Jekyll::DEFAULTS.merge({'plugins' => nil})) assert_equal [], site.plugins end + end context "creating sites" do setup do @@ -39,6 +45,21 @@ class TestSite < Test::Unit::TestCase assert_equal Hash.new, @site.tags end + should "give site with parsed pages and posts to generators" do + @site.reset + @site.read + class MyGenerator < Generator + def generate(site) + site.pages.dup.each do |page| + raise "#{page} isn't a page" unless page.is_a?(Page) + raise "#{page} doesn't respond to :name" unless page.respond_to?(:name) + end + end + end + @site.generate + assert_not_equal 0, @site.pages.size + end + should "reset data before processing" do clear_dest @site.process @@ -118,6 +139,11 @@ class TestSite < Test::Unit::TestCase assert_equal mtime3, mtime4 # no modifications, so must be the same end + should "setup plugins in priority order" do + assert_equal @site.converters.sort_by(&:class).map{|c|c.class.priority}, @site.converters.map{|c|c.class.priority} + assert_equal @site.generators.sort_by(&:class).map{|g|g.class.priority}, @site.generators.map{|g|g.class.priority} + end + should "read layouts" do @site.read_layouts assert_equal ["default", "simple"].sort, @site.layouts.keys.sort @@ -166,6 +192,22 @@ class TestSite < Test::Unit::TestCase assert_equal files, @site.filter_entries(files) end + should "filter symlink entries when safe mode enabled" do + stub(Jekyll).configuration do + Jekyll::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'safe' => true}) + end + site = Site.new(Jekyll.configuration) + stub(File).symlink?('symlink.js') {true} + files = %w[symlink.js] + assert_equal [], site.filter_entries(files) + end + + should "not filter symlink entries when safe mode disabled" do + stub(File).symlink?('symlink.js') {true} + files = %w[symlink.js] + assert_equal files, @site.filter_entries(files) + end + context 'error handling' do should "raise if destination is included in source" do stub(Jekyll).configuration do diff --git a/test/test_tags.rb b/test/test_tags.rb index 3d97410b..caefb9ac 100644 --- a/test/test_tags.rb +++ b/test/test_tags.rb @@ -203,4 +203,22 @@ CONTENT assert_match %r{/2008/11/21/complex/}, @result end end + + context "simple gist inclusion" do + setup do + @gist = 358471 + content = < 'pretty', 'source' => source_dir, 'destination' => dest_dir, 'read_posts' => true}) + end + + should "write script tag" do + assert_match %r{}, @result + end + end end diff --git a/test/test_wordpress_migrator.rb b/test/test_wordpress_migrator.rb deleted file mode 100644 index 945fbc8b..00000000 --- a/test/test_wordpress_migrator.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'helper' -require 'jekyll/migrators/wordpress' -require 'htmlentities' - -class TestWordpressMigrator < Test::Unit::TestCase - should "clean slashes from slugs" do - test_title = "blogs part 1/2" - assert_equal("blogs-part-1-2", Jekyll::WordPress.sluggify(test_title)) - end -end diff --git a/test/test_wordpressdotcom_migrator.rb b/test/test_wordpressdotcom_migrator.rb deleted file mode 100644 index fb38737b..00000000 --- a/test/test_wordpressdotcom_migrator.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'helper' -require 'jekyll/migrators/wordpressdotcom' - -class TestWordpressDotComMigrator < Test::Unit::TestCase - should "clean slashes from slugs" do - test_title = "blogs part 1/2" - assert_equal("blogs-part-1-2", Jekyll::WordpressDotCom.sluggify(test_title)) - end -end