carthage_remote_cache 0.0.5 → 0.0.10

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.
data/lib/constants.rb CHANGED
@@ -1,12 +1,14 @@
1
- CARTHAGE_DIR = 'Carthage'
2
- CARTHAGE_BUILD_DIR = File.join(CARTHAGE_DIR, 'Build')
3
- CARTFILE_RESOLVED = 'Cartfile.resolved'
4
- CARTRCFILE = 'Cartrcfile'
1
+ CARTHAGE_DIR = "Carthage"
2
+ CARTHAGE_BUILD_DIR = File.join(CARTHAGE_DIR, "Build")
3
+ CARTFILE_RESOLVED = "Cartfile.resolved"
4
+ CARTRCFILE = "Cartrcfile"
5
5
  THREAD_POOL_SIZE = 8
6
6
 
7
7
  SERVER_DEFAULT_PORT = 9292
8
- SERVER_CACHE_DIR = File.join(Dir.home, '.carthagerc_server')
8
+ SERVER_CACHE_DIR = File.join(Dir.home, ".carthagerc_server")
9
9
 
10
10
  ARCHIVE_CHECKSUM_HEADER_REST_CLIENT = :archive_checksum
11
- ARCHIVE_CHECKSUM_HEADER_SINATRA_IN = 'HTTP_ARCHIVE_CHECKSUM'
12
- ARCHIVE_CHECKSUM_HEADER_SINATRA_OUT = 'Archive-Checksum'
11
+ ARCHIVE_CHECKSUM_HEADER_SINATRA_IN = "HTTP_ARCHIVE_CHECKSUM"
12
+ ARCHIVE_CHECKSUM_HEADER_SINATRA_OUT = "Archive-Checksum"
13
+
14
+ PLATFORMS = [:iOS, :macOS, :tvOS, :watchOS]
data/lib/crc32.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'digest'
2
- require 'zlib'
1
+ require "digest"
2
+ require "zlib"
3
3
 
4
4
  class Digest::CRC32 < Digest::Class
5
5
  include Digest::Instance
@@ -17,6 +17,6 @@ class Digest::CRC32 < Digest::Class
17
17
  end
18
18
 
19
19
  def finish
20
- [@crc32].pack('N')
20
+ [@crc32].pack("N")
21
21
  end
22
22
  end
data/lib/errors.rb CHANGED
@@ -19,6 +19,64 @@ class MultipleErrorsError < AppError
19
19
  end
20
20
  end
21
21
 
22
- class OutdatedFrameworkBuildError < AppError; end
22
+ class VersionFileDoesNotExistError < AppError; end
23
+
24
+ class OutdatedFrameworkBuildError < AppError
25
+ attr_reader :framework_name, :build_version, :cartfile_resolved_version
26
+
27
+ def initialize(framework_name, build_version, cartfile_resolved_version)
28
+ @framework_name = framework_name
29
+ @build_version = build_version
30
+ @cartfile_resolved_version = cartfile_resolved_version
31
+ end
32
+
33
+ def ==(o)
34
+ self.class == o.class && state == o.state
35
+ end
36
+
37
+ def to_s
38
+ "framework name: #{@framework_name}, build version: #{@build_version}, resolved version: #{@cartfile_resolved_version}"
39
+ end
40
+
41
+ protected
42
+
43
+ def state
44
+ [@framework_name, @build_version, @cartfile_resolved_version]
45
+ end
46
+ end
47
+
48
+ class FrameworkValidationError < AppError
49
+ def initialize(errors)
50
+ @errors = errors
51
+ end
52
+
53
+ def to_s
54
+ header = ["Framework", CARTHAGE_BUILD_DIR, CARTFILE_RESOLVED]
55
+ rows = @errors.map { |e| [e.framework_name, e.build_version, e.cartfile_resolved_version] }
56
+ table = Table.new(header, rows)
57
+ <<~EOS
58
+ Detected differences between existing frameworks in '#{CARTHAGE_BUILD_DIR}' and entries in '#{CARTFILE_RESOLVED}':
59
+
60
+ #{table}
61
+
62
+ To resolve the issue:
63
+ - run `carthagerc download` to fetch missing frameworks from the server.
64
+ - if the issue persists, run `carthage bootstrap` to build frameworks and `carthagerc upload` to populate the server.
65
+ EOS
66
+ end
67
+ end
23
68
 
24
69
  class MissingFrameworkDirectoryError < AppError; end
70
+
71
+ class ServerVersionMismatchError < AppError; end
72
+
73
+ class PlatformMismatchError < AppError
74
+ def initialize(platform)
75
+ @platform = platform
76
+ end
77
+
78
+ def to_s
79
+ platforms = PLATFORMS.map(&:to_s).join(", ")
80
+ "Platform '#{@platform}' doesn't match any of: #{platforms}"
81
+ end
82
+ end
data/lib/log.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'logger'
1
+ require "logger"
2
2
 
3
3
  $LOG = Logger.new(STDOUT)
4
4
  $LOG.level = Logger::INFO
data/lib/networking.rb CHANGED
@@ -1,23 +1,48 @@
1
- require 'rest-client'
2
- require 'uri'
1
+ require "rest-client"
2
+ require "uri"
3
3
 
4
4
  class Networking
5
- def initialize(config)
5
+ def initialize(config, is_retry_enabled)
6
6
  @config = config
7
+ @is_retry_enabled = is_retry_enabled
8
+ end
9
+
10
+ # Version
11
+
12
+ def get_server_version
13
+ url = new_version_url
14
+ $LOG.debug("Fetching server version from #{url}")
15
+ server_version = perform_network_request do
16
+ RestClient.get(url) do |response, request, result|
17
+ if response.code == 200
18
+ response.strip
19
+ else
20
+ raise AppError.new, "Failed to read server version from #{url}, response:\n #{response[0...300]}"
21
+ end
22
+ end
23
+ end
24
+ server_version
7
25
  end
8
26
 
9
27
  # Version Files
10
28
 
11
29
  # @return VersionFile or nil
12
- def download_version_file(carthage_dependency)
30
+ def download_version_file(carthage_dependency, platforms)
13
31
  url = new_version_file_url(carthage_dependency)
14
- $LOG.debug("Downloading version file from #{url}")
15
- version_file = RestClient.get(url) do |response, request, result|
16
- if response.code == 200
17
- File.write(carthage_dependency.version_filename, response.to_s)
18
- VersionFile.new(carthage_dependency.version_filename)
19
- else
20
- nil
32
+ params = {}
33
+ unless platforms.nil?
34
+ params[:platform] = platforms.map(&:to_s).join(",")
35
+ end
36
+
37
+ version_file = perform_network_request do
38
+ $LOG.debug("Downloading version file from #{url}, params: #{params}")
39
+ RestClient.get(url, { params: params }) do |response, request, result|
40
+ if response.code == 200
41
+ File.write(carthage_dependency.version_filename, response.to_s)
42
+ VersionFile.new(carthage_dependency.version_filename)
43
+ else
44
+ nil
45
+ end
21
46
  end
22
47
  end
23
48
  version_file
@@ -26,10 +51,12 @@ class Networking
26
51
  # @raise AppError on upload failure
27
52
  def upload_version_file(carthage_dependency)
28
53
  url = new_version_file_url(carthage_dependency)
29
- $LOG.debug("Uploading #{carthage_dependency.version_filename}")
30
- RestClient.post(url, :version_file => File.new(carthage_dependency.version_filepath)) do |response, request, result|
31
- unless response.code == 200
32
- raise AppError.new, "Version file upload #{carthage_dependency.version_filename} failed, response:\n #{response[0..300]}"
54
+ perform_network_request do
55
+ $LOG.debug("Uploading #{carthage_dependency.version_filename}")
56
+ RestClient.post(url, :version_file => File.new(carthage_dependency.version_filepath)) do |response, request, result|
57
+ unless response.code == 200
58
+ raise AppError.new, "Version file upload #{carthage_dependency.version_filename} failed, response:\n #{response[0..300]}"
59
+ end
33
60
  end
34
61
  end
35
62
  end
@@ -39,14 +66,16 @@ class Networking
39
66
  # @return Hash with CarthageArchive and checksum or nil
40
67
  def download_framework_archive(carthage_dependency, framework_name, platform)
41
68
  url = new_framework_url(carthage_dependency, framework_name, platform)
42
- $LOG.debug("Downloading framework from #{url}")
43
- archive = RestClient.get(url) do |response, request, result|
44
- if response.code == 200
45
- archive = CarthageArchive.new(framework_name, platform)
46
- File.write(archive.archive_path, response.to_s)
47
- {:archive => archive, :checksum => response.headers[ARCHIVE_CHECKSUM_HEADER_REST_CLIENT]}
48
- else
49
- nil
69
+ archive = perform_network_request do
70
+ $LOG.debug("Downloading framework from #{url}")
71
+ RestClient.get(url) do |response, request, result|
72
+ if response.code == 200
73
+ archive = CarthageArchive.new(framework_name, platform)
74
+ File.write(archive.archive_path, response.to_s)
75
+ { :archive => archive, :checksum => response.headers[ARCHIVE_CHECKSUM_HEADER_REST_CLIENT] }
76
+ else
77
+ nil
78
+ end
50
79
  end
51
80
  end
52
81
  archive
@@ -55,21 +84,27 @@ class Networking
55
84
  # @raise AppError when upload fails
56
85
  def upload_framework_archive(zipfile_name, carthage_dependency, framework_name, platform, checksum)
57
86
  url = new_framework_url(carthage_dependency, framework_name, platform)
58
- params = {:framework_file => File.new(zipfile_name)}
59
- headers = {ARCHIVE_CHECKSUM_HEADER_REST_CLIENT => checksum}
60
- $LOG.debug("Uploading framework to #{url}, headers: #{headers}")
61
- RestClient.post(url, params, headers) do |response, request, result|
62
- unless response.code == 200
63
- raise AppError.new, "Framework upload #{zipfile_name} failed, response:\n #{response[0..300]}"
87
+ params = { :framework_file => File.new(zipfile_name) }
88
+ headers = { ARCHIVE_CHECKSUM_HEADER_REST_CLIENT => checksum }
89
+ perform_network_request do
90
+ $LOG.debug("Uploading framework to #{url}, headers: #{headers}")
91
+ RestClient.post(url, params, headers) do |response, request, result|
92
+ unless response.code == 200
93
+ raise AppError.new, "Framework upload #{zipfile_name} failed, response:\n #{response[0..300]}"
94
+ end
64
95
  end
65
96
  end
66
97
  end
67
98
 
68
99
  private
69
100
 
101
+ def new_version_url
102
+ new_server_url(["version"])
103
+ end
104
+
70
105
  def new_version_file_url(carthage_dependency)
71
106
  new_server_url([
72
- 'versions',
107
+ "versions",
73
108
  @config.xcodebuild_version,
74
109
  @config.swift_version,
75
110
  carthage_dependency.guessed_framework_basename,
@@ -80,7 +115,7 @@ class Networking
80
115
 
81
116
  def new_framework_url(carthage_dependency, framework_name, platform)
82
117
  new_server_url([
83
- 'frameworks',
118
+ "frameworks",
84
119
  @config.xcodebuild_version,
85
120
  @config.swift_version,
86
121
  carthage_dependency.guessed_framework_basename,
@@ -96,13 +131,37 @@ class Networking
96
131
  :scheme => @config.server_uri.scheme,
97
132
  :host => @config.server_uri.host,
98
133
  :port => @config.server_uri.port,
99
- :path => '/' + sanitized_path_slices.join('/'),
134
+ :path => "/" + sanitized_path_slices.join("/"),
100
135
  )
101
136
  uri.to_s
102
137
  end
103
138
 
104
139
  # Mangle identifiers for URL paths.
105
140
  def sanitized(input)
106
- input.gsub(/\//, '_')
141
+ input.gsub(/\//, "_")
142
+ end
143
+
144
+ def perform_network_request
145
+ if @is_retry_enabled
146
+ retries_remaining = 3
147
+ sleep_time_seconds = 5
148
+ begin
149
+ result = yield
150
+ rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
151
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
152
+ if retries_remaining > 0
153
+ $LOG.warn("Network request failed - remaining retries: #{retries_remaining}, sleeping for: #{sleep_time_seconds}s, error: #{e.message}")
154
+ sleep(sleep_time_seconds)
155
+ retries_remaining -= 1
156
+ sleep_time_seconds *= 3
157
+ retry
158
+ else
159
+ raise e
160
+ end
161
+ end
162
+ result
163
+ else
164
+ yield
165
+ end
107
166
  end
108
167
  end
data/lib/server/config.ru CHANGED
@@ -1,6 +1,6 @@
1
- require 'rubygems'
2
- require 'bundler'
1
+ require "rubygems"
2
+ require "bundler"
3
3
  Bundler.require
4
4
 
5
- require './server_app.rb'
5
+ require "./server_app.rb"
6
6
  run Sinatra::Application
@@ -1,22 +1,41 @@
1
- require 'sinatra'
2
- require 'fileutils'
3
- require 'carthage_remote_cache'
1
+ require "json"
2
+ require "sinatra"
3
+ require "fileutils"
4
+ require "carthage_remote_cache"
4
5
 
5
- get '/' do
6
+ get "/" do
6
7
  "Welcome to carthage_remote_cache"
7
8
  end
8
9
 
9
- versions_path = '/versions/:xcodebuild_version/:swift_version/:dependency_name/:version/:version_filename'
10
- frameworks_path = '/frameworks/:xcodebuild_version/:swift_version/:dependency_name/:version/:framework_name/:platform'
10
+ version_path = "/version"
11
+ versions_path = "/versions/:xcodebuild_version/:swift_version/:dependency_name/:version/:version_filename"
12
+ frameworks_path = "/frameworks/:xcodebuild_version/:swift_version/:dependency_name/:version/:framework_name/:platform"
13
+
14
+ get version_path do
15
+ status(200)
16
+ VERSION
17
+ end
11
18
 
12
19
  get versions_path do
20
+ if params.key?(:platform)
21
+ begin
22
+ platforms = platform_to_symbols(params[:platform])
23
+ rescue AppError => e
24
+ status(400)
25
+ return JSON.pretty_generate({ "error" => e.message })
26
+ end
27
+ else
28
+ platforms = PLATFORMS
29
+ end
30
+
13
31
  dirname = params_to_framework_dir(params)
14
32
  filename = params[:version_filename]
15
33
  filepath = File.join(dirname, filename)
16
34
 
17
35
  if File.exist?(filepath)
18
36
  status(200)
19
- send_file(filepath)
37
+ version_file = VersionFile.new(filepath, platforms)
38
+ JSON.pretty_generate(version_file.json)
20
39
  else
21
40
  status(404)
22
41
  end
@@ -33,7 +52,7 @@ post versions_path do
33
52
  File.delete(target_filename) if File.exist?(target_filename)
34
53
 
35
54
  $LOG.info("Writing: #{target_filename}")
36
- File.open(target_filename, 'wb') do |target_file|
55
+ File.open(target_filename, "wb") do |target_file|
37
56
  target_file.write(source_file.read)
38
57
  end
39
58
 
@@ -69,7 +88,7 @@ post frameworks_path do
69
88
  File.delete(target_filename) if File.exist?(target_filename)
70
89
 
71
90
  $LOG.info("Writing: #{target_filename}")
72
- File.open(target_filename, 'wb') do |target_file|
91
+ File.open(target_filename, "wb") do |target_file|
73
92
  target_file.write(source_file.read)
74
93
  end
75
94
 
data/lib/shell_wrapper.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'open3'
1
+ require "open3"
2
2
 
3
3
  class ShellWrapper
4
4
  # @return
data/lib/table.rb ADDED
@@ -0,0 +1,58 @@
1
+ class Table
2
+ def initialize(header, rows)
3
+ @header = header
4
+ @rows = rows
5
+ @column_sizes = calculate_column_sizes
6
+ end
7
+
8
+ def to_s
9
+ lines = [
10
+ separator_line,
11
+ header_line,
12
+ separator_line,
13
+ @rows.map { |r| row_line(r) },
14
+ separator_line,
15
+ ]
16
+
17
+ lines
18
+ .flatten
19
+ .reject { |line| line.empty? }
20
+ .join("\n")
21
+ end
22
+
23
+ private
24
+
25
+ def calculate_column_sizes
26
+ all = [@header] + @rows
27
+ result = all.transpose.map do |row|
28
+ lengths = row.map { |r| r.length }
29
+ lengths.max + 2
30
+ end
31
+ result
32
+ end
33
+
34
+ def separator_line
35
+ dashes = @column_sizes.map { |size| "-" * size }
36
+ "+" + dashes.join("+") + "+"
37
+ end
38
+
39
+ def header_line
40
+ columns = @header.each_with_index.map do |column, index|
41
+ column_size = @column_sizes[index] - 1
42
+ " %-#{column_size}.#{column_size}s" % column
43
+ end
44
+ "|" + columns.join("|") + "|"
45
+ end
46
+
47
+ def row_line(row)
48
+ columns = row.each_with_index.map do |column, index|
49
+ column_size = @column_sizes[index] - 1
50
+ if index == 0
51
+ " %-#{column_size}.#{column_size}s" % column
52
+ else
53
+ "%#{column_size}.#{column_size}s " % column
54
+ end
55
+ end
56
+ "|" + columns.join("|") + "|"
57
+ end
58
+ end
data/lib/utils.rb CHANGED
@@ -15,7 +15,7 @@ end
15
15
  def quote(input)
16
16
  if input.is_a? String
17
17
  if input.empty?
18
- ''
18
+ ""
19
19
  else
20
20
  '"' + input + '"'
21
21
  end
@@ -23,7 +23,7 @@ def quote(input)
23
23
  input
24
24
  .map { |e| quote(e) }
25
25
  .select { |e| !e.empty? }
26
- .join(' ')
26
+ .join(" ")
27
27
  else
28
28
  raise AppError.new, "Unsupported type #{input}"
29
29
  end
@@ -32,13 +32,13 @@ end
32
32
  def platform_to_api_string(platform)
33
33
  case platform
34
34
  when :iOS
35
- 'iOS'
35
+ "iOS"
36
36
  when :macOS
37
- 'macOS'
37
+ "macOS"
38
38
  when :tvOS
39
- 'tvOS'
39
+ "tvOS"
40
40
  when :watchOS
41
- 'watchOS'
41
+ "watchOS"
42
42
  else
43
43
  raise AppError.new, "Unrecognized platform #{platform.inspect}"
44
44
  end
@@ -47,18 +47,28 @@ end
47
47
  def platform_to_carthage_dir_string(platform)
48
48
  case platform
49
49
  when :iOS
50
- 'iOS'
50
+ "iOS"
51
51
  when :macOS
52
- 'Mac'
52
+ "Mac"
53
53
  when :tvOS
54
- 'tvOS'
54
+ "tvOS"
55
55
  when :watchOS
56
- 'watchOS'
56
+ "watchOS"
57
57
  else
58
58
  raise AppError.new, "Unrecognized platform #{platform.inspect}"
59
59
  end
60
60
  end
61
61
 
62
+ def platform_to_symbols(string)
63
+ platforms = string.split(",").map(&:to_sym)
64
+ for platform in platforms
65
+ if !PLATFORMS.include?(platform)
66
+ raise PlatformMismatchError.new(platform)
67
+ end
68
+ end
69
+ platforms
70
+ end
71
+
62
72
  # @return string in "x.y MB" format
63
73
  def format_file_size(bytes)
64
74
  megabytes = bytes / 1000.0 / 1000.0