puppet-forge-server 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
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 'open-uri'
18
+ require 'open_uri_redirections'
19
+
20
+ module PuppetForgeServer::Http
21
+ class HttpClient
22
+ def get(url)
23
+ open_uri(url).read
24
+ end
25
+
26
+ def download(url)
27
+ open_uri(url)
28
+ end
29
+
30
+ private
31
+ def open_uri(url)
32
+ open(url, 'User-Agent' => "Puppet-Forge-Server/#{PuppetForgeServer::VERSION}", :allow_redirections => :safe)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,37 @@
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::Models
18
+ class Builder
19
+ def initialize(attributes={})
20
+ attributes.each do |name, value|
21
+ send("#{name}=", value) unless value.to_s.empty?
22
+ end
23
+ end
24
+
25
+ def method_missing (method_name, *args, &block)
26
+ STDERR.puts "Method #{method_name} with args #{args} not found in #{self.class.to_s}" unless method_name == :to_ary
27
+ end
28
+
29
+ def to_hash
30
+ hash = {}
31
+ self.instance_variables.each do |var|
32
+ hash[var.to_s.delete('@')] = self.instance_variable_get var
33
+ end
34
+ hash
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,46 @@
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
+
18
+ module PuppetForgeServer::Models
19
+ class Metadata < Builder
20
+
21
+ attr_accessor :author, :name, :version, :dependencies, :summary, :description, :project_page, :types
22
+ attr_accessor :checksums, :source, :license, :issues_url, :operatingsystem_support, :requirements
23
+
24
+ def initialize(attributes)
25
+ super(attributes)
26
+ end
27
+
28
+ def ==(other)
29
+ other && self.class.equal?(other.class) &&
30
+ @author == other.author &&
31
+ @name == other.name &&
32
+ @version == other.version
33
+ end
34
+
35
+ def hash
36
+ @author.hash ^ @name.hash ^ @version.hash
37
+ end
38
+
39
+ def eql?(other)
40
+ other && self.class.equal?(other.class) &&
41
+ @author.eql?(other.author) &&
42
+ @name.eql?(other.name) &&
43
+ @version.eql?(other.version)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,61 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 drrb
4
+ # Copyright 2014 North Development AB
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'rubygems/package'
19
+
20
+ class Hash
21
+ def deep_merge(other)
22
+ merge(other) do |key, old_val, new_val|
23
+ if old_val.instance_of? Array
24
+ old_val + new_val
25
+ else
26
+ new_val
27
+ end
28
+ end
29
+ end
30
+
31
+ def deep_merge!(other)
32
+ replace(deep_merge(other))
33
+ end
34
+ end
35
+
36
+ class Array
37
+ def deep_merge
38
+ inject({}) do |merged, map|
39
+ merged.deep_merge(map)
40
+ end
41
+ end
42
+
43
+ def version_sort_by
44
+ sort_by do |element|
45
+ version = yield(element)
46
+ Gem::Version.new(version)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Used by PuppetForgeServer::Utils::Archiver
52
+ class Gem::Package::TarReader
53
+ # Old versions of RubyGems don't include Enumerable in here
54
+ def find
55
+ each do |entry|
56
+ if yield(entry)
57
+ return entry
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,88 @@
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 'rack/mount'
18
+
19
+ module PuppetForgeServer
20
+ class Server
21
+ include PuppetForgeServer::Utils::OptionParser
22
+ include PuppetForgeServer::Utils::Http
23
+
24
+ def initialize(log = STDERR)
25
+ @log = log
26
+ end
27
+
28
+ def go(args)
29
+ begin
30
+ options = parse_options(args)
31
+ backends = backends(options)
32
+ server = build(backends)
33
+ announce(options, backends)
34
+ start(server, options)
35
+ rescue PuppetForgeServer::Errors::Expected
36
+ @log.puts "Error: #{error}"
37
+ end
38
+ end
39
+
40
+ def build(backends)
41
+ Rack::Mount::RouteSet.new do |set|
42
+ set.add_route PuppetForgeServer::App::Version1.new(backends)
43
+ set.add_route ::PuppetForgeServer::App::Version3.new(backends)
44
+ end
45
+ end
46
+
47
+ def announce(options, backends)
48
+ options = options.clone
49
+ options.default = 'default'
50
+ @log.puts " +- Daemonizing: #{options[:daemonize]}"
51
+ @log.puts " |- Port: #{options[:port]}"
52
+ @log.puts " |- Host: #{options[:hostname]}"
53
+ @log.puts " |- Pidfile: #{options[:pidfile]}" if options[:pidfile]
54
+ @log.puts " |- Server: #{options[:server]}"
55
+ @log.puts ' `- Backends:'
56
+ backends.each do |backend|
57
+ @log.puts " - #{backend.inspect}"
58
+ end
59
+ end
60
+
61
+ def start(server, options)
62
+ FileUtils.mkdir_p File.dirname(options[:pidfile]) if options[:pidfile]
63
+ Rack::Server.start(
64
+ :app => server,
65
+ :Host => options[:hostname],
66
+ :Port => options[:port],
67
+ :server => options[:server],
68
+ :daemonize => options[:daemonize],
69
+ :pid => options[:pidfile]
70
+ )
71
+ end
72
+
73
+ private
74
+ def backends(options)
75
+ options[:backend].map do |type, typed_backends|
76
+ typed_backends.map do |url|
77
+ case type
78
+ when 'Proxy'
79
+ @log.puts "Detecting API version for #{url}..."
80
+ PuppetForgeServer::Backends.const_get("#{type}V#{get_api_version(url)}").new(url.chomp('/'), options[:cache_basedir])
81
+ else
82
+ PuppetForgeServer::Backends.const_get(type).new(url)
83
+ end
84
+ end
85
+ end.flatten.sort_by { |backend| backend.PRIORITY }
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,29 @@
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 'rubygems/package'
18
+ require 'zlib'
19
+
20
+ module PuppetForgeServer::Utils
21
+ module Archiver
22
+ def read_entry(path, entry_name_regex)
23
+ tar = Gem::Package::TarReader.new(Zlib::GzipReader.open(path))
24
+ tar.rewind
25
+ entry = tar.find { |e| e.full_name =~ entry_name_regex } or raise "Couldn't find entry in archive matching #{entry_name_regex.inspect}"
26
+ entry.read
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
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
+
18
+ module PuppetForgeServer::Utils
19
+ module Buffer
20
+ def download(buffer)
21
+ headers = buffer.respond_to?(:size) ? {'Content-Length' => buffer.size.to_s} : {}
22
+ [200, headers, buffer]
23
+ end
24
+
25
+ def get_buffer(backends, path)
26
+ backends.each do |backend|
27
+ buffer = backend.get_file_buffer(path)
28
+ return buffer if buffer
29
+ end
30
+ nil
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
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
+
18
+ module PuppetForgeServer::Utils
19
+ module Http
20
+ def get_api_version(url)
21
+ check_url = '/v3/modules/puppetlabs-stdlib'
22
+ begin
23
+ PuppetForgeServer::Http::HttpClient.new.get("#{url.chomp('/')}#{check_url}")
24
+ 3
25
+ rescue OpenURI::HTTPError
26
+ 1
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,76 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 drrb
4
+ # Copyright 2014 North Development AB
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'optparse'
19
+ require 'tmpdir'
20
+
21
+ module PuppetForgeServer::Utils
22
+ module OptionParser
23
+ include PuppetForgeServer::Utils::Url
24
+
25
+ @@DEFAULT_DAEMONIZE = false
26
+ @@DEFAULT_PORT = 8080
27
+ @@DEFAULT_PID_FILE = File.join(Dir.tmpdir.to_s, 'puppet-forge-server', 'server.pid')
28
+ @@DEFAULT_CACHE_DIR = File.join(Dir.tmpdir.to_s, 'puppet-forge-server', 'cache')
29
+
30
+ def parse_options(args)
31
+ options = {:daemonize => @@DEFAULT_DAEMONIZE, :cache_basedir => @@DEFAULT_CACHE_DIR, :port => @@DEFAULT_PORT}
32
+ option_parser = ::OptionParser.new do |opts|
33
+ opts.banner = "Usage: #{File.basename $0} [options]"
34
+ opts.version = PuppetForgeServer::VERSION
35
+
36
+ opts.on('-p', '--port PORT', 'Port to listen on (defaults to whatever Rack wants to use)') do |port|
37
+ options[:port] = port
38
+ end
39
+
40
+ opts.on('-b', '--bind-host HOSTNAME', 'Host name to bind to (defaults to whatever Rack wants to use)') do |hostname|
41
+ options[:hostname] = hostname
42
+ end
43
+
44
+ opts.on('--daemonize', 'Run the server in the background') do
45
+ options[:daemonize] = true
46
+ options[:pidfile] = @@DEFAULT_PID_FILE unless options[:pidfile]
47
+ end
48
+
49
+ opts.on('--pidfile FILE', 'Write a pidfile to this location after starting') do |pidfile|
50
+ options[:pidfile] = pidfile
51
+ end
52
+
53
+ options[:backend] = {'Directory' => [], 'Proxy' => [], 'Source' => []}
54
+ opts.on('-m', '--module-dir DIR', 'Directory containing packaged modules (can be specified multiple times)') do |module_dir|
55
+ options[:backend]['Directory'] << module_dir
56
+ end
57
+ opts.on('-x', '--proxy URL', 'Remote forge to proxy (can be specified multiple times)') do |url|
58
+ options[:backend]['Proxy'] << normalize_url(url)
59
+ end
60
+ opts.on('--source-dir DIR', "Directory containing a module's source (can be specified multiple times)") do |module_dir|
61
+ options[:backend]['Source'] << module_dir
62
+ end
63
+
64
+ opts.on('--cache-basedir DIR', "Cache all proxies' downloaded modules under this directory") do |cache_basedir|
65
+ options[:cache_basedir] = cache_basedir
66
+ end
67
+ end
68
+ begin
69
+ option_parser.parse(args)
70
+ rescue ::OptionParser::InvalidOption => parse_error
71
+ raise PuppetForgeServer::Errors::Expected, parse_error.message + "\n" + option_parser.help
72
+ end
73
+ return options
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 drrb
4
+ # Copyright 2014 North Development AB
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'uri'
19
+
20
+ module PuppetForgeServer::Utils
21
+ module Url
22
+ def normalize_url(uri_string)
23
+ begin
24
+ url = URI.parse(uri_string)
25
+ rescue URI::InvalidURIError => e
26
+ raise PuppetForgeServer::Error::Expected, "Invalid URL '#{uri_string}': #{e.message}"
27
+ end
28
+ if url.scheme
29
+ raise PuppetForgeServer::Error::Expected, "Invalid URL '#{uri_string}': unsupported protocol '#{url.scheme}'" unless url.scheme =~ /^https?$/
30
+ else
31
+ uri_string = "http://#{uri_string}"
32
+ end
33
+ uri_string.sub /\/$/, ''
34
+ end
35
+ end
36
+ end