puppet-forge-server 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module PuppetForgeServer::Api::V3
18
+ module Releases
19
+ def get_releases(metadata)
20
+ metadata.map do |element|
21
+ name = element[:metadata].name.sub(/^[^-]+-/, '')
22
+
23
+ {
24
+ :uri => "/v3/releases/#{element[:metadata].name}-#{element[:metadata].version}",
25
+ :module => {
26
+ :uri => "/v3/modules/#{element[:metadata].name}",
27
+ :name => name
28
+ },
29
+ :metadata => element[:metadata].to_hash,
30
+ :version => element[:metadata].version,
31
+ :tags => element[:tags] ? element[:tags] : [element[:metadata].author, name],
32
+ :file_uri => "/v3/files#{element[:path]}",
33
+ :file_md5 => element[:checksum]
34
+ }
35
+ end.version_sort_by { |r| r[:version] }.reverse
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,67 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'sinatra/base'
18
+ require 'json'
19
+
20
+ module PuppetForgeServer::App
21
+ class Version1 < Sinatra::Base
22
+ include PuppetForgeServer::Api::V1::Releases
23
+ include PuppetForgeServer::Api::V1::Modules
24
+ include PuppetForgeServer::Utils::Buffer
25
+
26
+ def initialize(backends)
27
+ super(nil)
28
+ @backends = backends
29
+ end
30
+
31
+ get '/api/v1/releases.json' do
32
+ unless params[:module]
33
+ halt 400, {'error' => 'The number of version constraints in the query does not match the number of module names'}.to_json
34
+ end
35
+
36
+ author, name = params[:module].split '/'
37
+ version = params[:version] if params[:version]
38
+
39
+ metadata = @backends.map do |backend|
40
+ backend.get_metadata(author, name, {:version => version, :with_checksum => false})
41
+ end.flatten.uniq
42
+
43
+ halt 400, {'errors' => ["'#{params[:module]}' is not a valid module slug"]}.to_json if metadata.empty?
44
+
45
+ {"#{author}/#{name}" => get_releases(metadata)}.to_json
46
+ end
47
+
48
+ get '/api/v1/files/*' do
49
+ captures = params[:captures].first
50
+ buffer = get_buffer(@backends, captures)
51
+
52
+ halt 404, {'errors' => ['404 Not found']}.to_json unless buffer
53
+
54
+ content_type 'application/octet-stream'
55
+ attachment captures.split('/').last
56
+ download buffer
57
+ end
58
+
59
+ get '/modules.json' do
60
+ query = params[:q]
61
+ metadata = @backends.map do |backend|
62
+ backend.query_metadata(query, {:with_checksum => false})
63
+ end.flatten.uniq
64
+ get_modules(metadata).to_json
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,68 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'sinatra/base'
18
+
19
+ module PuppetForgeServer::App
20
+ class Version3 < Sinatra::Base
21
+ include PuppetForgeServer::Api::V3::Releases
22
+ include PuppetForgeServer::Api::V3::Modules
23
+ include PuppetForgeServer::Utils::Buffer
24
+
25
+ def initialize(backends)
26
+ super(nil)
27
+ @backends = backends
28
+ end
29
+
30
+ get '/v3/releases' do
31
+ halt 400, {'error' => 'The number of version constraints in the query does not match the number of module names'}.to_json unless params[:module]
32
+
33
+ author, name, version = params[:module].split '-'
34
+ metadata = @backends.map do |backend|
35
+ backend.get_metadata(author, name, {:version => version})
36
+ end.flatten.uniq
37
+
38
+ halt 404, {'pagination' => {'next' => false}, 'results' => []}.to_json if metadata.empty?
39
+ {'pagination' => {'next' => false}, 'results' => get_releases(metadata)}.to_json
40
+ end
41
+
42
+ get '/v3/files/*' do
43
+ captures = params[:captures].first
44
+ buffer = get_buffer(@backends, captures)
45
+
46
+ halt 404, {'errors' => ['404 Not found']}.to_json unless buffer
47
+
48
+ content_type 'application/octet-stream'
49
+ attachment captures.split('/').last
50
+ download buffer
51
+ end
52
+
53
+ get '/v3/modules/:author-:name' do
54
+ author = params[:author]
55
+ name = params[:name]
56
+
57
+ halt 400, {'errors' => "'#{params[:module]}' is not a valid module slug"}.to_json unless author && name
58
+
59
+ metadata = @backends.map do |backend|
60
+ backend.get_metadata(author, name)
61
+ end.flatten.uniq
62
+
63
+ halt 404, {'errors' => ['404 Not found']}.to_json if metadata.empty?
64
+
65
+ get_modules(metadata).to_json
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,67 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'digest/md5'
18
+ require 'pathname'
19
+
20
+ module PuppetForgeServer::Backends
21
+ class Directory
22
+ include PuppetForgeServer::Utils::Archiver
23
+
24
+ # Give highest priority to locally hosted modules
25
+ @@PRIORITY = 0
26
+ attr_reader :PRIORITY
27
+
28
+ def initialize(url)
29
+ @module_dir = url
30
+ end
31
+
32
+ def query_metadata(query, options = {})
33
+ get_file_metadata("*#{query}*.tar.gz", options)
34
+ end
35
+
36
+ def get_metadata(author, name, options = {})
37
+ version = options[:version] ? options[:version] : '*'
38
+ get_file_metadata("#{author}-#{name}-#{version}.tar.gz", options)
39
+ end
40
+
41
+ def get_file_buffer(relative_path)
42
+ path = File.join(File.expand_path(@module_dir), relative_path)
43
+ File.open(path, 'r') if File.exist?(path)
44
+ end
45
+
46
+ private
47
+ def read_metadata(archive_path)
48
+ metadata_file = read_entry(archive_path, %r[[^/]+/metadata\.json$])
49
+ JSON.parse(metadata_file)
50
+ rescue => error
51
+ warn "Error reading from module archive #{archive_path}: #{error}"
52
+ return nil
53
+ end
54
+
55
+ def get_file_metadata(file_name, options)
56
+ options = ({:with_checksum => true}).merge(options)
57
+ Dir["#{@module_dir}/**/#{file_name}"].map do |path|
58
+ checksum = Digest::MD5.hexdigest(File.read(path)) if options[:with_checksum] == true
59
+ {
60
+ :metadata => PuppetForgeServer::Models::Metadata.new(read_metadata(path)),
61
+ :checksum => checksum,
62
+ :path => "/#{Pathname.new(path).relative_path_from(Pathname.new(@module_dir))}"
63
+ }
64
+ end.compact
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,63 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'json'
18
+ require 'digest/sha1'
19
+
20
+ module PuppetForgeServer::Backends
21
+ class Proxy
22
+
23
+ def initialize(url, cache_dir, http_client)
24
+ @url = url
25
+ @cache_dir = File.join(cache_dir, Digest::SHA1.hexdigest(@url))
26
+ @http_client = http_client
27
+
28
+ # Create directory structure for all alphabetic letters
29
+ (10...36).each do |i|
30
+ FileUtils.mkdir_p(File.join(@cache_dir, i.to_s(36)))
31
+ end
32
+ end
33
+
34
+ def get_file_buffer(relative_path)
35
+ file_name = relative_path.split('/').last
36
+ File.join(@cache_dir, file_name[0], file_name)
37
+ path = Dir["#{@cache_dir}/**/#{file_name}"].first
38
+ unless File.exist?("#{path}")
39
+ buffer = download("/#{relative_path}")
40
+ File.open(File.join(@cache_dir, file_name[0], file_name), 'wb') do |file|
41
+ file.write(buffer.read)
42
+ end
43
+ path = File.join(@cache_dir, file_name[0], file_name)
44
+ end
45
+ File.open(path, 'rb')
46
+ rescue OpenURI::HTTPError
47
+ # ignore
48
+ end
49
+
50
+ protected
51
+ def get(relative_url)
52
+ @http_client.get(url(relative_url))
53
+ end
54
+
55
+ def download(relative_url)
56
+ @http_client.download(url(relative_url))
57
+ end
58
+
59
+ def url(relative_url)
60
+ @url + relative_url
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,69 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'json'
18
+ require 'digest/md5'
19
+
20
+ module PuppetForgeServer::Backends
21
+ class ProxyV1 < PuppetForgeServer::Backends::Proxy
22
+
23
+ # Priority should be lower than v3 API proxies as v3 requires less API calls
24
+ @@PRIORITY = 15
25
+ attr_reader :PRIORITY
26
+
27
+ def initialize(url, cache_dir, http_client = PuppetForgeServer::Http::HttpClient.new)
28
+ super(url, cache_dir, http_client)
29
+ end
30
+
31
+ def get_metadata(author, name, options = {})
32
+ options = ({:with_checksum => true}).merge(options)
33
+ query ="#{author}/#{name}"
34
+ get_module_metadata(JSON.parse(get("/modules.json?q=#{query}")).select { |e| e['full_name'].match("#{query}") }, options)
35
+ end
36
+
37
+ def query_metadata(query, options = {})
38
+ options = ({:with_checksum => true}).merge(options)
39
+ get_module_metadata(JSON.parse(get("/modules.json?q=#{query}")).select { |e| e['full_name'].match("*#{query}*") }, options)
40
+ end
41
+
42
+ private
43
+ def read_metadata(element, release)
44
+ element['project_page'] = element['project_url']
45
+ element['name'] = element['full_name'] ? element['full_name'].gsub('/', '-') : element['name']
46
+ element['description'] = element['desc']
47
+ element['version'] = release['version'] ? release['version'] : element['version']
48
+ element['dependencies'] = release['dependencies'] ? release['dependencies'] : []
49
+ %w(project_url full_name releases tag_list desc).each { |key| element.delete(key) }
50
+ element
51
+ end
52
+
53
+ def get_module_metadata(modules, options)
54
+ modules.map do |element|
55
+ version = options['version'] ? "&version=#{options['version']}" : ''
56
+ JSON.parse(get("/api/v1/releases.json?module=#{element['author']}/#{element['name']}#{version}")).values.first.map do |release|
57
+ tags = element['tag_list'] ? element['tag_list'] : nil
58
+ raw_metadata = read_metadata(element, release)
59
+ {
60
+ :metadata => PuppetForgeServer::Models::Metadata.new(raw_metadata),
61
+ :checksum => options[:with_checksum] ? Digest::MD5.hexdigest(File.read(get_file_buffer(release['file']))) : nil,
62
+ :path => "#{release['file']}",
63
+ :tags => tags
64
+ }
65
+ end
66
+ end.compact
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,63 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'json'
18
+
19
+ module PuppetForgeServer::Backends
20
+ class ProxyV3 < PuppetForgeServer::Backends::Proxy
21
+
22
+ @@PRIORITY = 10
23
+ attr_reader :PRIORITY
24
+
25
+ def initialize(url, cache_dir, http_client = PuppetForgeServer::Http::HttpClient.new)
26
+ super(url, cache_dir, http_client)
27
+ end
28
+
29
+ def get_metadata(author, name, options = {})
30
+ options = ({:with_checksum => true}).merge(options)
31
+ query ="#{author}-#{name}"
32
+ releases = options[:version] ? [JSON.parse(get("/v3/releases/#{query}-#{options[:version]}"))] : get_all_release_pages("/v3/releases?module=#{query}")
33
+ get_release_metadata(releases)
34
+ end
35
+
36
+ def query_metadata(query, options = {})
37
+ author, name = query.split('-')
38
+ get_metadata(author, name, options) if author && name
39
+ end
40
+
41
+ private
42
+ def get_all_release_pages(next_page)
43
+ releases = []
44
+ begin
45
+ result = JSON.parse(get(next_page))
46
+ releases += result['results']
47
+ next_page = result['pagination']['next']
48
+ end while next_page
49
+ releases
50
+ end
51
+
52
+ def get_release_metadata(releases)
53
+ releases.map do |element|
54
+ {
55
+ :metadata => PuppetForgeServer::Models::Metadata.new(element['metadata']),
56
+ :checksum => element['file_md5'],
57
+ :path => element['file_uri'],
58
+ :tags => element['tags']
59
+ }
60
+ end.compact
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module PuppetForgeServer::Errors
18
+ class Expected
19
+ end
20
+ end