package_cloud 0.0.3 → 0.3.15
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.
- checksums.yaml +7 -0
- data/README.md +506 -16
- data/bin/package_cloud +1 -1
- data/lib/package_cloud/auth.rb +2 -1
- data/lib/package_cloud/cli/distro.rb +51 -0
- data/lib/package_cloud/cli/entry.rb +397 -0
- data/lib/package_cloud/cli/gpg_key.rb +76 -0
- data/lib/package_cloud/cli/master_token.rb +75 -0
- data/lib/package_cloud/cli/read_token.rb +39 -0
- data/lib/package_cloud/cli/repository.rb +52 -0
- data/lib/package_cloud/cli.rb +49 -16
- data/lib/package_cloud/client.rb +44 -3
- data/lib/package_cloud/config_file.rb +69 -14
- data/lib/package_cloud/gpg_key.rb +13 -0
- data/lib/package_cloud/master_token.rb +19 -0
- data/lib/package_cloud/read_token.rb +14 -0
- data/lib/package_cloud/repository.rb +187 -6
- data/lib/package_cloud/util.rb +17 -0
- data/lib/package_cloud/validator.rb +118 -0
- data/lib/package_cloud/version.rb +5 -1
- data/lib/package_cloud.rb +6 -0
- data/markdown_lint_config.rb +2 -0
- data/package_cloud.gemspec +14 -10
- metadata +152 -96
data/lib/package_cloud/cli.rb
CHANGED
|
@@ -1,22 +1,55 @@
|
|
|
1
|
-
require "colorize"
|
|
2
1
|
require "thor"
|
|
2
|
+
require "logger"
|
|
3
|
+
require "benchmark"
|
|
3
4
|
|
|
4
5
|
module PackageCloud
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
module CLI
|
|
7
|
+
autoload :Distro, "package_cloud/cli/distro"
|
|
8
|
+
autoload :Entry, "package_cloud/cli/entry"
|
|
9
|
+
autoload :MasterToken, "package_cloud/cli/master_token"
|
|
10
|
+
autoload :ReadToken, "package_cloud/cli/read_token"
|
|
11
|
+
autoload :Repository, "package_cloud/cli/repository"
|
|
12
|
+
autoload :GpgKey, "package_cloud/cli/gpg_key"
|
|
13
|
+
|
|
14
|
+
class Base < Thor
|
|
15
|
+
class_option "config", :desc => "Specify a path to config file containing your API token and URL; default is ~/.packagecloud"
|
|
16
|
+
class_option "url", :desc => "Specify the website URL to use; default is https://packagecloud.io. Useful for packagecloud:enterprise users."
|
|
17
|
+
class_option "verbose", :type => :boolean, :desc => "Enable verbose mode."
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
def get_valid(prompt)
|
|
21
|
+
selection = ""
|
|
22
|
+
times = 0
|
|
23
|
+
until yield(selection)
|
|
24
|
+
if times > 0
|
|
25
|
+
puts "#{selection} is not a valid selection."
|
|
26
|
+
end
|
|
27
|
+
print "#{prompt}: "
|
|
28
|
+
selection = ::Kernel.gets.chomp
|
|
29
|
+
times += 1
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
selection
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def config
|
|
36
|
+
$logger = ::Logger.new(STDOUT)
|
|
37
|
+
$verbose = !!options[:verbose]
|
|
38
|
+
if $verbose
|
|
39
|
+
$logger.level = ::Logger::DEBUG
|
|
40
|
+
$logger.debug("verbose mode enabled")
|
|
41
|
+
else
|
|
42
|
+
$logger.level = ::Logger::WARN
|
|
43
|
+
end
|
|
44
|
+
@config ||= begin
|
|
45
|
+
ConfigFile.new(options[:config] || "~/.packagecloud",
|
|
46
|
+
options[:url] || "https://packagecloud.io").tap(&:read_or_create)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def client
|
|
51
|
+
@client ||= Client.new(config)
|
|
52
|
+
end
|
|
20
53
|
end
|
|
21
54
|
end
|
|
22
55
|
end
|
data/lib/package_cloud/client.rb
CHANGED
|
@@ -7,14 +7,55 @@ module PackageCloud
|
|
|
7
7
|
@config = config
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
def repositories
|
|
11
|
+
url = PackageCloud::Util.compute_url(@config.base_url, "/api/v1/repos.json")
|
|
12
|
+
begin
|
|
13
|
+
attrs = JSON.parse(RestClient.get(url))
|
|
14
|
+
attrs.map { |a| Repository.new(a, @config) }
|
|
15
|
+
rescue RestClient::ResourceNotFound => e
|
|
16
|
+
print "failed!\n".color(:red)
|
|
17
|
+
exit(127)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
10
21
|
def repository(name)
|
|
11
|
-
base_url = @config.base_url
|
|
12
22
|
user, repo = name.split("/")
|
|
23
|
+
url = PackageCloud::Util.compute_url(@config.base_url, "/api/v1/repos/#{user}/#{repo}.json")
|
|
13
24
|
begin
|
|
14
|
-
attrs = JSON.parse(RestClient.get(
|
|
25
|
+
attrs = JSON.parse(RestClient.get(url))
|
|
26
|
+
if attrs["error"] == "not_found"
|
|
27
|
+
print "failed... Repository #{user}/#{repo} not found!\n".color(:red)
|
|
28
|
+
exit(127)
|
|
29
|
+
end
|
|
30
|
+
|
|
15
31
|
Repository.new(attrs, @config)
|
|
16
32
|
rescue RestClient::ResourceNotFound => e
|
|
17
|
-
print "failed!\n".red
|
|
33
|
+
print "failed!\n".color(:red)
|
|
34
|
+
exit(127)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def create_repo(name, priv)
|
|
39
|
+
url = PackageCloud::Util.compute_url(@config.base_url, "/api/v1/repos.json")
|
|
40
|
+
begin
|
|
41
|
+
JSON.parse(RestClient.post(url, :repository => {:name => name, :private => priv == "private" ? "1" : "0"}))
|
|
42
|
+
rescue RestClient::UnprocessableEntity => e
|
|
43
|
+
print "error!\n".color(:red)
|
|
44
|
+
json = JSON.parse(e.response)
|
|
45
|
+
json.each do |k,v|
|
|
46
|
+
puts "\n\t#{k}: #{v.join(", ")}\n"
|
|
47
|
+
end
|
|
48
|
+
puts ""
|
|
49
|
+
exit(1)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def distributions
|
|
54
|
+
url = PackageCloud::Util.compute_url(@config.base_url, "/api/v1/distributions.json")
|
|
55
|
+
begin
|
|
56
|
+
JSON.parse(RestClient.get(url))
|
|
57
|
+
rescue RestClient::ResourceNotFound => e
|
|
58
|
+
print "failed!\n".color(:red)
|
|
18
59
|
exit(127)
|
|
19
60
|
end
|
|
20
61
|
end
|
|
@@ -1,54 +1,109 @@
|
|
|
1
1
|
require "highline/import"
|
|
2
2
|
require "json"
|
|
3
|
+
require "uri"
|
|
4
|
+
require "cgi"
|
|
3
5
|
|
|
4
6
|
module PackageCloud
|
|
5
7
|
class ConfigFile
|
|
6
8
|
attr_reader :token
|
|
7
9
|
|
|
8
|
-
def initialize(filename = "~/.packagecloud", url = "packagecloud.io")
|
|
10
|
+
def initialize(filename = "~/.packagecloud", url = "https://packagecloud.io")
|
|
11
|
+
handle_locale
|
|
9
12
|
@filename = File.expand_path(filename)
|
|
10
|
-
@url = url
|
|
13
|
+
@url = URI(url)
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
def read_or_create
|
|
14
|
-
if
|
|
17
|
+
if ENV["PACKAGECLOUD_TOKEN"]
|
|
18
|
+
if ENV["PACKAGECLOUD_TOKEN"].length < 48
|
|
19
|
+
puts "Found PACKAGECLOUD_TOKEN environment variable but is empty or too short! Visit https://packagecloud.io/api_token and confirm it is correct."
|
|
20
|
+
exit!
|
|
21
|
+
end
|
|
22
|
+
@token = ENV["PACKAGECLOUD_TOKEN"]
|
|
23
|
+
@url = URI(ENV["PACKAGECLOUD_URL"]) if ENV["PACKAGECLOUD_URL"]
|
|
24
|
+
output_host_and_token
|
|
25
|
+
elsif File.exist?(@filename)
|
|
15
26
|
attrs = JSON.parse(File.read(@filename))
|
|
16
27
|
@token = attrs["token"] if attrs.has_key?("token")
|
|
17
|
-
@url = attrs["url"] if attrs.has_key?("url")
|
|
28
|
+
@url = URI(attrs["url"]) if attrs.has_key?("url")
|
|
29
|
+
fix_config_file!
|
|
30
|
+
output_host_and_token
|
|
18
31
|
else
|
|
19
32
|
puts "No config file exists at #{@filename}. Login to create one."
|
|
20
33
|
|
|
21
34
|
@token = login_from_console
|
|
35
|
+
print "Got your token. Writing a config file to #{@filename}... "
|
|
22
36
|
write
|
|
37
|
+
puts "success!"
|
|
23
38
|
end
|
|
24
39
|
end
|
|
25
40
|
|
|
26
41
|
def url
|
|
27
|
-
@url ||= "packagecloud.io"
|
|
42
|
+
@url ||= URI("https://packagecloud.io")
|
|
28
43
|
end
|
|
29
44
|
|
|
30
45
|
def base_url(username = token, password = "")
|
|
31
|
-
|
|
46
|
+
u = url.dup
|
|
47
|
+
u.user = CGI.escape(username)
|
|
48
|
+
u.password = CGI.escape(password)
|
|
49
|
+
u.to_s
|
|
32
50
|
end
|
|
33
51
|
|
|
34
52
|
private
|
|
53
|
+
def handle_locale
|
|
54
|
+
# Force the external encoding to be UTF-8 on windows and everywhere
|
|
55
|
+
# else. This will somtimes fail on windows because it seems the default
|
|
56
|
+
# windows encoding on windows is IBM 437 and it
|
|
57
|
+
# is very painful to change to UTF-8. The failure in this case will
|
|
58
|
+
# just be 1 "?" being printed per character that isn't
|
|
59
|
+
# representable.
|
|
60
|
+
Encoding.default_external = 'UTF-8'
|
|
61
|
+
end
|
|
62
|
+
|
|
35
63
|
def login_from_console
|
|
36
64
|
e = ask("Email:")
|
|
65
|
+
puts "If you signed up via social login (Github, Bitbucket etc.), and/or do not have a password, input: NIL"
|
|
37
66
|
p = ask("Password:") { |q| q.echo = false }
|
|
38
67
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
68
|
+
if p == "NIL"
|
|
69
|
+
puts "Copy your API Token from https://packagecloud.io/api_token and input below."
|
|
70
|
+
puts "(Note: An incorrectly inputted token will require deletion of the incorrectly generated $HOME/.packagecloud config file before rerunning the last command.)"
|
|
71
|
+
api_token = ask("Your API Token:") { |q| q.echo = false }
|
|
72
|
+
else
|
|
73
|
+
begin
|
|
74
|
+
api_token = PackageCloud::Auth.get_token(base_url(e, p))
|
|
75
|
+
rescue RestClient::Unauthorized => e
|
|
76
|
+
puts "Sorry, but we couldn't find you. Give it another try."
|
|
77
|
+
puts "(Or skip the login? Go to https://packagecloud.io/api_token to see instructions on downloading your $HOME/.packagecloud config file.)"
|
|
78
|
+
login_from_console
|
|
79
|
+
end
|
|
44
80
|
end
|
|
81
|
+
|
|
82
|
+
return api_token
|
|
45
83
|
end
|
|
46
84
|
|
|
47
85
|
def write
|
|
48
|
-
|
|
49
|
-
attrs = {url: @url, token: @token}
|
|
86
|
+
attrs = {:url => url.to_s, :token => @token}
|
|
50
87
|
File.open(@filename, "w", 0600) { |f| f << JSON.dump(attrs); f << "\r\n" }
|
|
51
|
-
puts "success!"
|
|
52
88
|
end
|
|
89
|
+
|
|
90
|
+
def output_host_and_token
|
|
91
|
+
token = @token[-4..-1].rjust(10, '*')
|
|
92
|
+
puts "Using #{@url} with token:#{token}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
## package_cloud versions prior to 0.2.17 have a bug in the
|
|
96
|
+
## config where the url is used verbatim as the key, instead of "url",
|
|
97
|
+
## this attempts to fix the config file
|
|
98
|
+
def fix_config_file!
|
|
99
|
+
if File.exist?(@filename) && File.writable?(@filename)
|
|
100
|
+
attrs = JSON.parse(File.read(@filename))
|
|
101
|
+
if !attrs.has_key?("url")
|
|
102
|
+
## overwrite the config file if "url" key not found
|
|
103
|
+
write
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
53
108
|
end
|
|
54
109
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module PackageCloud
|
|
2
|
+
class MasterToken < Object
|
|
3
|
+
def initialize(attrs, config)
|
|
4
|
+
@attrs = attrs
|
|
5
|
+
@config = config
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def read_tokens
|
|
9
|
+
@attrs["read_tokens"].map do |read_token|
|
|
10
|
+
ReadToken.new(@config, read_token)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def destroy
|
|
15
|
+
url = PackageCloud::Util.compute_url(@config.base_url, paths["self"])
|
|
16
|
+
RestClient.delete(url)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module PackageCloud
|
|
2
|
+
class ReadToken < Object
|
|
3
|
+
def initialize(config, attrs)
|
|
4
|
+
@config = config
|
|
5
|
+
@attrs = attrs
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def destroy(master_token_path, read_token_id)
|
|
9
|
+
base_url = @config.base_url
|
|
10
|
+
url = "#{base_url}#{master_token_path}/read_tokens/#{read_token_id}"
|
|
11
|
+
RestClient.delete(url)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
|
|
1
3
|
module PackageCloud
|
|
2
4
|
class Repository < Object
|
|
3
5
|
def initialize(attrs, config)
|
|
@@ -5,15 +7,150 @@ module PackageCloud
|
|
|
5
7
|
@config = config
|
|
6
8
|
end
|
|
7
9
|
|
|
8
|
-
def
|
|
10
|
+
def parse_dsc(dsc_path, dist_id)
|
|
11
|
+
file_data = File.new(dsc_path, 'rb')
|
|
12
|
+
base_url = @config.base_url
|
|
13
|
+
url = PackageCloud::Util.compute_url(base_url, paths["package_contents"])
|
|
14
|
+
begin
|
|
15
|
+
resp = RestClient::Request.execute(:method => 'post',
|
|
16
|
+
:url => url,
|
|
17
|
+
:timeout => nil,
|
|
18
|
+
:payload => { :package => {:package_file => file_data,
|
|
19
|
+
:distro_version_id => dist_id}})
|
|
20
|
+
resp = JSON.parse(resp)
|
|
21
|
+
print "success!\n"
|
|
22
|
+
resp["files"]
|
|
23
|
+
rescue RestClient::UnprocessableEntity => e
|
|
24
|
+
print "error:\n".color(:red)
|
|
25
|
+
json = JSON.parse(e.response)
|
|
26
|
+
json.each do |k,v|
|
|
27
|
+
puts "\n\t#{k}: #{v.join(", ")}\n"
|
|
28
|
+
end
|
|
29
|
+
puts ""
|
|
30
|
+
exit(1)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_upload
|
|
35
|
+
base_url = @config.base_url
|
|
36
|
+
url = PackageCloud::Util.compute_url(base_url, paths["create_upload"])
|
|
37
|
+
begin
|
|
38
|
+
JSON.parse(RestClient.post(url, {}))
|
|
39
|
+
rescue RestClient::UnprocessableEntity => e
|
|
40
|
+
print "error!\n".color(:red)
|
|
41
|
+
json = JSON.parse(e.response)
|
|
42
|
+
json.each do |k,v|
|
|
43
|
+
puts "\n\t#{k}: #{v.join(", ")}\n"
|
|
44
|
+
end
|
|
45
|
+
puts
|
|
46
|
+
exit(1)
|
|
47
|
+
rescue RestClient::ResourceNotFound => e
|
|
48
|
+
print "failed!\n".color(:red)
|
|
49
|
+
exit(127)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create_package(file_path, file_url, dist_id, files=nil, urls=nil, filetype=nil, coordinates=nil)
|
|
54
|
+
base_url = @config.base_url
|
|
55
|
+
url = PackageCloud::Util.compute_url(base_url, paths["create_package"])
|
|
56
|
+
params = {
|
|
57
|
+
:distro_version_id => dist_id,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if file_url
|
|
61
|
+
params[:url] = file_url
|
|
62
|
+
else
|
|
63
|
+
params[:package_file] = File.new(file_path, 'rb')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if coordinates
|
|
67
|
+
params[:coordinates] = coordinates
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if filetype == "dsc"
|
|
71
|
+
if urls
|
|
72
|
+
params[:source_urls] = urls
|
|
73
|
+
else
|
|
74
|
+
params[:source_files] = files.map do |f|
|
|
75
|
+
File.new(f, 'rb')
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
RestClient::Request.execute(
|
|
81
|
+
:method => 'post',
|
|
82
|
+
:url => url,
|
|
83
|
+
:timeout => nil,
|
|
84
|
+
:payload => { :package => params },
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
print "success!\n".color(:green)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def install_script(type)
|
|
91
|
+
url = urls["install_script"].gsub(/:package_type/, type)
|
|
92
|
+
|
|
93
|
+
# the URL we've obtained above already contains the correct tokens
|
|
94
|
+
# because the install script URL uses a master token for access, not
|
|
95
|
+
# your API token, so if we pass @config.base_url in to compute_url,
|
|
96
|
+
# we'll end up generating a URL like: https://token:@https://token:@...
|
|
97
|
+
# because @config.base_url has the url with the API token in it and url
|
|
98
|
+
# has the url (lol) with the master token in it.
|
|
99
|
+
#
|
|
100
|
+
# so just pass url in here.
|
|
101
|
+
url = PackageCloud::Util.compute_url(url, '')
|
|
102
|
+
script = RestClient.get(url)
|
|
103
|
+
|
|
104
|
+
# persist the script to a tempfile to make it easier to execute
|
|
105
|
+
file = Tempfile.new('foo')
|
|
106
|
+
file.write(script)
|
|
107
|
+
file.close
|
|
108
|
+
file
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def create_gpg_key(file_path)
|
|
9
112
|
file_data = File.new(file_path, 'rb')
|
|
10
|
-
base_url = @config.base_url
|
|
11
|
-
url = base_url
|
|
113
|
+
base_url = @config.base_url
|
|
114
|
+
url = PackageCloud::Util.compute_url(@config.base_url, paths["gpg_keys"])
|
|
115
|
+
params = { keydata: file_data }
|
|
116
|
+
|
|
117
|
+
print "Attempting to upload key file #{file_path}... "
|
|
118
|
+
|
|
12
119
|
begin
|
|
13
|
-
RestClient.
|
|
14
|
-
|
|
120
|
+
RestClient::Request.execute(:method => 'post',
|
|
121
|
+
:url => url,
|
|
122
|
+
:timeout => nil,
|
|
123
|
+
:payload => { :gpg_key => params })
|
|
15
124
|
rescue RestClient::UnprocessableEntity => e
|
|
16
|
-
print "error
|
|
125
|
+
print "error: ".color(:red)
|
|
126
|
+
json = JSON.parse(e.response)
|
|
127
|
+
puts json["error"]
|
|
128
|
+
puts ""
|
|
129
|
+
exit(1)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
print "success!\n".color(:green)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def gpg_keys
|
|
136
|
+
url = PackageCloud::Util.compute_url(@config.base_url, paths["gpg_keys"])
|
|
137
|
+
attrs = JSON.parse(RestClient.get(url))
|
|
138
|
+
attrs["gpg_keys"].map { |a| GpgKey.new(a, @config) }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def master_tokens
|
|
142
|
+
url = PackageCloud::Util.compute_url(@config.base_url, paths["master_tokens"])
|
|
143
|
+
attrs = JSON.parse(RestClient.get(url))
|
|
144
|
+
attrs.map { |a| MasterToken.new(a, @config) }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def create_master_token(name)
|
|
148
|
+
url = PackageCloud::Util.compute_url(@config.base_url, paths["create_master_token"])
|
|
149
|
+
begin
|
|
150
|
+
resp = RestClient.post(url, :master_token => {:name => name})
|
|
151
|
+
resp = JSON.parse(resp)
|
|
152
|
+
rescue RestClient::UnprocessableEntity => e
|
|
153
|
+
print "error:\n".color(:red)
|
|
17
154
|
json = JSON.parse(e.response)
|
|
18
155
|
json.each do |k,v|
|
|
19
156
|
puts "\n\t#{k}: #{v.join(", ")}\n"
|
|
@@ -21,6 +158,50 @@ module PackageCloud
|
|
|
21
158
|
puts ""
|
|
22
159
|
exit(1)
|
|
23
160
|
end
|
|
161
|
+
resp
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def promote(dist, package_name, dest_repo_name, scope=nil)
|
|
165
|
+
begin
|
|
166
|
+
url = PackageCloud::Util.compute_url(@config.base_url, paths["self"] + "/" + [dist, package_name, "promote.json"].compact.join("/"))
|
|
167
|
+
resp = if scope
|
|
168
|
+
RestClient.post(url, destination: dest_repo_name, scope: scope)
|
|
169
|
+
else
|
|
170
|
+
RestClient.post(url, destination: dest_repo_name)
|
|
171
|
+
end
|
|
172
|
+
resp = JSON.parse(resp)
|
|
173
|
+
rescue RestClient::UnprocessableEntity, RestClient::ResourceNotFound => e
|
|
174
|
+
print "error:\n".color(:red)
|
|
175
|
+
json = JSON.parse(e.response)
|
|
176
|
+
json.each do |k,v|
|
|
177
|
+
puts "\n\t#{k}: #{v.join(", ")}\n"
|
|
178
|
+
end
|
|
179
|
+
puts ""
|
|
180
|
+
exit(1)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def yank(dist, package_name, scope=nil)
|
|
185
|
+
begin
|
|
186
|
+
url = PackageCloud::Util.compute_url(@config.base_url, paths["self"] + "/" + [dist, package_name].compact.join("/"))
|
|
187
|
+
if scope
|
|
188
|
+
RestClient.delete(url, params: { scope: scope })
|
|
189
|
+
else
|
|
190
|
+
RestClient.delete(url)
|
|
191
|
+
end
|
|
192
|
+
rescue RestClient::ResourceNotFound => e
|
|
193
|
+
print "error:\n".color(:red)
|
|
194
|
+
json = JSON.parse(e.response)
|
|
195
|
+
json.each do |k,v|
|
|
196
|
+
puts "\n\t#{k}: #{v.join(", ")}\n"
|
|
197
|
+
end
|
|
198
|
+
puts ""
|
|
199
|
+
exit(1)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def private_human
|
|
204
|
+
send(:private) ? "private".color(:red) : "public".color(:green)
|
|
24
205
|
end
|
|
25
206
|
end
|
|
26
207
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'open-uri'
|
|
2
|
+
|
|
3
|
+
module PackageCloud
|
|
4
|
+
class Util
|
|
5
|
+
class << self
|
|
6
|
+
def compute_url(base_url, path)
|
|
7
|
+
url = base_url + path
|
|
8
|
+
proxy_uri = URI.parse(url).find_proxy()
|
|
9
|
+
if proxy_uri
|
|
10
|
+
RestClient.proxy = proxy_uri.to_s
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
url
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module PackageCloud
|
|
2
|
+
class Validator
|
|
3
|
+
def initialize(client)
|
|
4
|
+
@client = client
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def distribution_id_from_repo_url(repo, filenames)
|
|
8
|
+
_,_,dist_sel,ver_sel = repo.split("/")
|
|
9
|
+
package_type = dist_sel
|
|
10
|
+
puts "ambiguous extensions, so using repo url to deduce package_type, package_type: #{package_type}".color(:red)
|
|
11
|
+
|
|
12
|
+
# NOTE: The distributions pulled from API uses "py" (package_type) as key for "python"
|
|
13
|
+
# so we need to map "python" to "py"
|
|
14
|
+
# See PackageCloud::Validator#distributions
|
|
15
|
+
package_type = package_type == "python" ? "py": package_type
|
|
16
|
+
|
|
17
|
+
distribution_id(repo, filenames, package_type)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def distribution_id(repo, filenames, package_type)
|
|
21
|
+
if distributions[package_type]
|
|
22
|
+
_,_,dist_sel,ver_sel = repo.split("/")
|
|
23
|
+
|
|
24
|
+
# These are all 'single version' distros
|
|
25
|
+
if (dist_sel == "python" || dist_sel == "java" || dist_sel == "node" || dist_sel == "anyfile")
|
|
26
|
+
dist = distributions[package_type].detect { |d| d["index_name"] == dist_sel }
|
|
27
|
+
dist["versions"].first["id"]
|
|
28
|
+
elsif dist_sel && ver_sel
|
|
29
|
+
dist = distributions[package_type].detect { |d| d["index_name"] == dist_sel }
|
|
30
|
+
|
|
31
|
+
if dist
|
|
32
|
+
ver = dist["versions"].detect { |v| v["index_name"] == ver_sel || v["version_number"] == ver_sel }
|
|
33
|
+
|
|
34
|
+
if ver
|
|
35
|
+
ver["id"]
|
|
36
|
+
else
|
|
37
|
+
puts "#{ver_sel} isn't a valid version of #{dist["display_name"]}\n\n"
|
|
38
|
+
select_dist(repo, filenames, package_type)
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
puts "#{dist_sel} isn't a valid operating system.\n\n"
|
|
42
|
+
select_dist(repo, filenames, package_type)
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
puts "#{package_type} packages require an operating system and version to be selected.\n\n"
|
|
46
|
+
select_dist(repo, filenames, package_type)
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
def distributions
|
|
55
|
+
@distributions ||= @client.distributions
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def select_from(list)
|
|
59
|
+
selection = get_valid("0-#{list.length - 1}") do |s|
|
|
60
|
+
s =~ /^\d+$/ && list[s.to_i]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
list[selection.to_i]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def get_valid(prompt)
|
|
67
|
+
selection = ""
|
|
68
|
+
times = 0
|
|
69
|
+
until yield(selection)
|
|
70
|
+
if times > 0
|
|
71
|
+
puts "#{selection} is not a valid selection."
|
|
72
|
+
end
|
|
73
|
+
print "\n #{prompt}: "
|
|
74
|
+
selection = ::Kernel.gets.chomp
|
|
75
|
+
times += 1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
selection
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def select_dist(repo, filenames, package_type)
|
|
82
|
+
puts "If you don't see your OS or version here, send us an email at support@packagecloud.io:\n\n"
|
|
83
|
+
all_distros = distributions[package_type]
|
|
84
|
+
|
|
85
|
+
filtered_distros = all_distros.select {|dist| dist["index_name"] != "any" && dist["index_name"] != "rpm_any" }
|
|
86
|
+
|
|
87
|
+
filtered_distros.each_with_index do |dist, index|
|
|
88
|
+
puts "\t#{index}. #{dist["display_name"]}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
distro = select_from(filtered_distros)
|
|
92
|
+
|
|
93
|
+
puts "\nYou selected #{distro["display_name"]}. Select a version:\n\n"
|
|
94
|
+
distro["versions"].each_with_index do |ver, index|
|
|
95
|
+
puts "\t#{index}. #{ver["display_name"]} (#{ver["index_name"]})"
|
|
96
|
+
end
|
|
97
|
+
version = select_from(distro["versions"])
|
|
98
|
+
|
|
99
|
+
repo = repo.split("/")[0..1].join("/")
|
|
100
|
+
os_shortcut = "#{distro["index_name"]}/#{version["index_name"]}"
|
|
101
|
+
shortcut = "#{repo}/#{os_shortcut}"
|
|
102
|
+
if filenames.length > 1
|
|
103
|
+
puts "\nPush #{filenames.length} packages to #{shortcut}? "
|
|
104
|
+
else
|
|
105
|
+
puts "\nPush #{filenames.first} to #{shortcut}? "
|
|
106
|
+
end
|
|
107
|
+
answer = get_valid("(y/n)") { |sel| sel == "y" || sel == "n" }
|
|
108
|
+
|
|
109
|
+
if answer == "y"
|
|
110
|
+
print "\nContinuing...".color(:green)
|
|
111
|
+
puts " Note that next time you can push directly to #{os_shortcut} by specifying #{shortcut} on the commandline."
|
|
112
|
+
version["id"]
|
|
113
|
+
else
|
|
114
|
+
abort("Cancelled.")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/package_cloud.rb
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
require "package_cloud/version"
|
|
2
2
|
require "cgi"
|
|
3
|
+
require 'rainbow/ext/string'
|
|
3
4
|
|
|
4
5
|
module PackageCloud
|
|
5
6
|
autoload :Auth, "package_cloud/auth"
|
|
6
7
|
autoload :CLI, "package_cloud/cli"
|
|
7
8
|
autoload :Client, "package_cloud/client"
|
|
8
9
|
autoload :ConfigFile, "package_cloud/config_file"
|
|
10
|
+
autoload :MasterToken, "package_cloud/master_token"
|
|
9
11
|
autoload :Object, "package_cloud/object"
|
|
12
|
+
autoload :ReadToken, "package_cloud/read_token"
|
|
10
13
|
autoload :Repository, "package_cloud/repository"
|
|
14
|
+
autoload :Validator, "package_cloud/validator"
|
|
15
|
+
autoload :Util, "package_cloud/util"
|
|
16
|
+
autoload :GpgKey, "package_cloud/gpg_key"
|
|
11
17
|
end
|