carthage_remote_cache 0.0.5 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
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