diff --git a/.gitignore b/.gitignore index 7878408..996017a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ test/version_tmp tmp .rake_t_cache /Gemfile.lock +.DS_Store diff --git a/lib/puppet_library/app/views/index.haml b/lib/puppet_library/app/views/index.haml index e6fb27a..e7330b4 100644 --- a/lib/puppet_library/app/views/index.haml +++ b/lib/puppet_library/app/views/index.haml @@ -24,6 +24,13 @@ $(document).ready(function() { var source = "modules.json#{ query.nil? ? '' : '?q=' + query }"; $.getJSON(source, function(modules) { + + modules.sort(function(a, b){ + var aFull_name = a.full_name.toLowerCase(); + var bFull_name = b.full_name.toLowerCase(); + return ((aFull_name < bFull_name) ? -1 : ((aFull_name > bFull_name) ? 1 : 0)); + }); + $.each(modules, function(index, module) { var item = $("
  • "); item.append($("").append($("").attr("href", module.full_name).text(module.full_name))); diff --git a/lib/puppet_library/app/views/layout.haml b/lib/puppet_library/app/views/layout.haml index 6f3b06e..a3107bb 100644 --- a/lib/puppet_library/app/views/layout.haml +++ b/lib/puppet_library/app/views/layout.haml @@ -27,7 +27,7 @@ %style :plain body { - padding-top: 50px; + padding-top: 100px; } input.search-query { padding-left:32px; diff --git a/lib/puppet_library/app/views/module.haml b/lib/puppet_library/app/views/module.haml index af99ca7..c54d2c9 100644 --- a/lib/puppet_library/app/views/module.haml +++ b/lib/puppet_library/app/views/module.haml @@ -23,3 +23,8 @@ %ul - metadata["releases"].each do |release| %li= release["version"] + + +%hr + +%div= metadata["documentation"] diff --git a/lib/puppet_library/archive/archive_reader.rb b/lib/puppet_library/archive/archive_reader.rb index 4854dac..2855c26 100644 --- a/lib/puppet_library/archive/archive_reader.rb +++ b/lib/puppet_library/archive/archive_reader.rb @@ -23,6 +23,13 @@ def initialize(path) @path = path end + def check_entry?(entry_name_regex) + tar = Gem::Package::TarReader.new(Zlib::GzipReader.open(@path)) + tar.rewind + entry = tar.find {|e| e.full_name =~ entry_name_regex } + !entry.nil? + end + def read_entry(entry_name_regex) tar = Gem::Package::TarReader.new(Zlib::GzipReader.open(@path)) tar.rewind diff --git a/lib/puppet_library/forge.rb b/lib/puppet_library/forge.rb index 1e59d4f..a4718f9 100644 --- a/lib/puppet_library/forge.rb +++ b/lib/puppet_library/forge.rb @@ -22,6 +22,7 @@ class ModuleNotFound < Exception require 'puppet_library/forge/abstract' require 'puppet_library/forge/cache' require 'puppet_library/forge/directory' + require 'puppet_library/forge/source_directory' require 'puppet_library/forge/forge' require 'puppet_library/forge/git_repository' require 'puppet_library/forge/multi' diff --git a/lib/puppet_library/forge/abstract.rb b/lib/puppet_library/forge/abstract.rb index 7b592f6..dd5b33f 100644 --- a/lib/puppet_library/forge/abstract.rb +++ b/lib/puppet_library/forge/abstract.rb @@ -154,13 +154,18 @@ def dependency_names dependencies.map {|d| d["name"]} end + def documentation + @metadata["documentation"] + end + def to_info { "author" => author, "full_name" => full_name, "name" => name, "desc" => description, - "releases" => [ { "version" => version } ] + "releases" => [ { "version" => version } ], + "documentation" => documentation } end @@ -182,6 +187,7 @@ def to_search_result "desc" => summary, "project_url" => project_page, "releases" => [{ "version" => version}], + "documentation" => documentation, "version" => version, "tag_list" => [author, name] } diff --git a/lib/puppet_library/forge/directory.rb b/lib/puppet_library/forge/directory.rb index 6c22527..49b8554 100644 --- a/lib/puppet_library/forge/directory.rb +++ b/lib/puppet_library/forge/directory.rb @@ -15,6 +15,7 @@ # along with this program. If not, see . require 'json' +require 'redcarpet' require 'puppet_library/forge/abstract' require 'puppet_library/archive/archive_reader' require 'puppet_library/util/config_api' @@ -78,7 +79,17 @@ def get_metadata(author, module_name) def read_metadata(archive_path) archive = PuppetLibrary::Archive::ArchiveReader.new(archive_path) metadata_file = archive.read_entry %r[[^/]+/metadata\.json$] - JSON.parse(metadata_file) + parsedJSON = JSON.parse(metadata_file) + + readme_regex = %r[/README[\.(md|markdown)]] + if archive.check_entry? readme_regex + readmeText = archive.read_entry readme_regex + markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(:with_tocdata => true), extensions = {}) + readmeHTML = markdown.render(readmeText).force_encoding("UTF-8") + parsedJSON["documentation"] = readmeHTML + end + parsedJSON + rescue => error warn "Error reading from module archive #{archive_path}: #{error}" return nil diff --git a/lib/puppet_library/forge/source_directory.rb b/lib/puppet_library/forge/source_directory.rb new file mode 100644 index 0000000..7e8db2e --- /dev/null +++ b/lib/puppet_library/forge/source_directory.rb @@ -0,0 +1,123 @@ +# -*- encoding: utf-8 -*- +# Puppet Library +# Copyright (C) 2014 drrb +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'json' +require 'redcarpet' +require 'puppet_library/forge/abstract' +require 'puppet_library/util/config_api' + +module PuppetLibrary::Forge + + # A forge that serves modules in unpacked format from a directory on disk. + # + # Note: + # * The modules must be in unpacked format + # * The modules (directories) must be named in the format modulename + # * The modules must contain a +metadata.json+ file + # + # Usage: + # + # forge = PuppetLibrary::Forge::SourceDirectory.configure do + # # The path to serve the modules from + # path "/var/modules/cache" + # end + class SourceDirectory < PuppetLibrary::Forge::Abstract + def self.configure(&block) + config_api = PuppetLibrary::Util::ConfigApi.for(SourceDirectory) do + required :path, "path to the modules' source" do |path| + Dir.new(File.expand_path(path)) + end + end + config = config_api.configure(&block) + SourceDirectory.new(config.get_path) + end + + # * :module_dir - The directory containing the unpackaged modules. + def initialize(module_dir) + super(self) + @module_dir = module_dir + end + + def get_module(author, name, version) + file_name = "#{name}" + path = File.join(@module_dir.path, file_name) + if File.exist? path + File.open(path, 'r:UTF-8') + else + nil + end + end + + def get_all_metadata + get_metadata("*","*") + + end + + def get_metadata(author, module_name) + archives = Dir["#{@module_dir.path}/*#{module_name}*"] + archives.map {|path| read_metadata(path) }.compact + end + + private + def read_metadata(directory_path) + metadata_file_path = File.join(directory_path, "metadata.json") + modulefile_path = File.join(directory_path, "Modulefile") + + if File.exist?(metadata_file_path) + metadata_file = File.open(metadata_file_path, "r:UTF-8").read + parsedJSON = JSON.parse(metadata_file) + elsif File.exist?(modulefile_path) + parsedJSON = PuppetLibrary::PuppetModule::Modulefile.read(modulefile_path).to_metadata + else + return nil + end + + Dir.chdir("#{directory_path}") + + # firstly trying to get the README.md file + readmePath = Dir["README.md"].last + + if readmePath.nil? || !File.exist?(readmePath) + readmePath = Dir["README*"].last + end + + if !readmePath.nil? && File.exist?(readmePath) + markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(:with_toc_data => true), extensions = {}) + readmeText = File.open("#{directory_path}/#{readmePath}").read + readmeHTML = markdown.render(readmeText) + parsedJSON["documentation"] = readmeHTML + end + + parsedJSON + + rescue => error + warn "Error reading from module archive #{directory_path}: #{error.backtrace.join("\n")}" + return { + "name" => "unknown/#{directory_path.split("/").last}", + "version" => "unknown", + "source" => "unknown", + "author" => "unknown", + "license" => "unknown", + "summary" => "unknown", + "description" => "unknown", + "project_page" => "unknown", + "dependencies" => "unknown", + "documentation" => nil + } + end + end +end diff --git a/lib/puppet_library/puppet_library.rb b/lib/puppet_library/puppet_library.rb index 0b63a9d..0d73960 100644 --- a/lib/puppet_library/puppet_library.rb +++ b/lib/puppet_library/puppet_library.rb @@ -18,6 +18,7 @@ require 'optparse' require 'rack' require 'yaml' +require 'puppet_library/forge/source_directory' require 'puppet_library/forge/directory' require 'puppet_library/forge/multi' require 'puppet_library/forge/proxy' @@ -86,6 +87,11 @@ def parse_options(args) opts.on("--cache-basedir DIR", "Cache all proxies' downloaded modules under this directory") do |cache_basedir| options[:cache_basedir] = cache_basedir end + + #new option --modulepath + opts.on("--modulepath DIR", "Directory containing all module's sources") do |modulepath| + options[:forges] << [Forge::SourceDirectory, modulepath] + end end begin option_parser.parse(args) @@ -161,7 +167,7 @@ def load_defaults!(options) def process_options!(options) options[:forges].map! do |(forge_type, config)| - if [ Forge::Directory, Forge::Source ].include? forge_type + if [ Forge::Directory, Forge::Source, Forge::SourceDirectory ].include? forge_type [ forge_type, [ Dir.new(sanitize_path(config)) ]] elsif forge_type == Forge::Proxy && options[:cache_basedir] cache_dir = File.join(options[:cache_basedir], url_hostname(config)) diff --git a/puppet-library.gemspec b/puppet-library.gemspec index 8abcb9c..d63292e 100644 --- a/puppet-library.gemspec +++ b/puppet-library.gemspec @@ -41,6 +41,7 @@ Gem::Specification.new do |spec| spec.add_dependency "haml" spec.add_dependency "docile", ">= 1.0.0" spec.add_dependency "open4" + spec.add_dependency "redcarpet", "~> 2.3.0" spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "coveralls" diff --git a/spec/forge/abstract_spec.rb b/spec/forge/abstract_spec.rb index dc729e0..88e3041 100644 --- a/spec/forge/abstract_spec.rb +++ b/spec/forge/abstract_spec.rb @@ -76,6 +76,7 @@ module PuppetLibrary::Forge "name"=>"apache", "desc"=>"Puppet module for Apache", "project_url"=>"https://github.com/puppetlabs/puppetlabs-apache", + "documentation" => nil, "releases"=>[{"version"=>"0.10.0"}], "version"=>"0.10.0", "tag_list"=>["puppetlabs", "apache"] @@ -91,6 +92,7 @@ module PuppetLibrary::Forge "desc"=>"Puppet module for NTP", "project_url"=>"https://github.com/dodgybrothers/puppet-ntp", "releases"=>[{"version"=>"1.0.0"}], + "documentation" => nil, "version"=>"1.0.0", "tag_list"=>["dodgybrothers", "ntp"] }] @@ -127,6 +129,7 @@ module PuppetLibrary::Forge "desc"=>"New Puppet module for Apache", "project_url"=>"https://github.com/puppetlabs/puppetlabs-apache-new", "releases"=>[{"version"=>"1.0.0"},{"version"=>"0.10.0"}], + "documentation" => nil, "version"=>"1.0.0", "tag_list"=>["puppetlabs", "apache"] }] @@ -145,6 +148,7 @@ module PuppetLibrary::Forge "desc"=>"Puppet module for Apache", "project_url"=>"https://github.com/puppetlabs/puppetlabs-apache", "releases"=>[{"version"=>"0.10.0"}], + "documentation" => nil, "version"=>"0.10.0", "tag_list"=>["puppetlabs", "apache"] },{ @@ -154,6 +158,7 @@ module PuppetLibrary::Forge "desc"=>"Puppet module for NTP", "project_url"=>"https://github.com/dodgybrothers/puppet-ntp", "releases"=>[{"version"=>"1.0.0"}], + "documentation" => nil, "version"=>"1.0.0", "tag_list"=>["dodgybrothers", "ntp"] }]