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"]
}]