puppet-forge-server 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +20 -0
- data/Gemfile +20 -0
- data/README.md +127 -0
- data/bin/puppet-forge-server +21 -0
- data/lib/puppet_forge_server.rb +63 -0
- data/lib/puppet_forge_server/api/v1/modules.rb +71 -0
- data/lib/puppet_forge_server/api/v1/releases.rb +31 -0
- data/lib/puppet_forge_server/api/v3/modules.rb +57 -0
- data/lib/puppet_forge_server/api/v3/releases.rb +38 -0
- data/lib/puppet_forge_server/app/version1.rb +67 -0
- data/lib/puppet_forge_server/app/version3.rb +68 -0
- data/lib/puppet_forge_server/backends/directory.rb +67 -0
- data/lib/puppet_forge_server/backends/proxy.rb +63 -0
- data/lib/puppet_forge_server/backends/proxy_v1.rb +69 -0
- data/lib/puppet_forge_server/backends/proxy_v3.rb +63 -0
- data/lib/puppet_forge_server/errors.rb +20 -0
- data/lib/puppet_forge_server/http/http_client.rb +35 -0
- data/lib/puppet_forge_server/models/builder.rb +37 -0
- data/lib/puppet_forge_server/models/metadata.rb +46 -0
- data/lib/puppet_forge_server/patches.rb +61 -0
- data/lib/puppet_forge_server/server.rb +88 -0
- data/lib/puppet_forge_server/utils/archiver.rb +29 -0
- data/lib/puppet_forge_server/utils/buffer.rb +33 -0
- data/lib/puppet_forge_server/utils/http.rb +30 -0
- data/lib/puppet_forge_server/utils/option_parser.rb +76 -0
- data/lib/puppet_forge_server/utils/url.rb +36 -0
- data/lib/puppet_forge_server/version.rb +19 -0
- data/puppet-forge-server.gemspec +47 -0
- metadata +172 -0
@@ -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
|