Skip to content

Add s3 support #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cocoapods-binary.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "cocoapods", ">= 1.5.0", "< 2.0"
spec.add_dependency "fourflusher", "~> 2.0"
spec.add_dependency "xcpretty", "~> 0.3.0"
spec.add_dependency "aws-sdk-s3", "~> 1"

spec.add_development_dependency 'bundler', '~> 1.3'
spec.add_development_dependency 'rake'
Expand Down
18 changes: 18 additions & 0 deletions lib/cocoapods-binary/Main.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ def use_shared_cache!
DSL.shared_cache_enabled = true
end

# Enable s3 shared cache, requires use_shared_cache!
# Frameworks also stored in s3 bucket
# Options hash depends on:
# - login(optional) : if not provided default aws creds strategy will be applied
# - password(optional) : if not provided default aws creds strategy will be applied
# - region(optional): if not provided default aws region strategy will be applied
# - endpoint(optional): if not provided default aws endpoint will be used, supported for custom s3 like implementation, like Ceph
# - bucket(required): s3 bucket name
# - prefix(optional): prefix for object key
def use_s3_cache(options)
DSL.shared_s3_cache_enabled = true
DSL.s3_options = options
end

# Add custom xcodebuild option to the prebuilding action
#
# You may use this for your special demands. For example: the default archs in dSYMs
Expand Down Expand Up @@ -80,6 +94,10 @@ def set_custom_xcodebuild_options_for_prebuilt_frameworks(options)

class_attr_accessor :shared_cache_enabled
shared_cache_enabled = false
class_attr_accessor :shared_s3_cache_enabled
shared_s3_cache_enabled = false
class_attr_accessor :s3_options
s3_options = {}

class_attr_accessor :custom_build_options
class_attr_accessor :custom_build_options_simulator
Expand Down
5 changes: 3 additions & 2 deletions lib/cocoapods-binary/Prebuild.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def prebuild_frameworks!
output_path.mkpath unless output_path.exist?

if Prebuild::SharedCache.has?(target, options)
framework_cache_path = Prebuild::SharedCache.framework_cache_path_for(target, options)
framework_cache_path = Prebuild::SharedCache.local_framework_cache_path_for(target, options)
UI.puts "Using #{target.label} from cache"
FileUtils.cp_r "#{framework_cache_path}/.", output_path
else
Expand Down Expand Up @@ -178,6 +178,7 @@ def prebuild_frameworks!
# This is for target with only .a and .h files
if not target.should_build?
Prebuild::Passer.target_names_to_skip_integration_framework << target.name
target_folder.mkpath unless target_folder.exist?
FileUtils.cp_r(root_path, target_folder, :remove_destination => true)
next
end
Expand Down Expand Up @@ -244,4 +245,4 @@ def prebuild_frameworks!


end
end
end
97 changes: 92 additions & 5 deletions lib/cocoapods-binary/helper/shared_cache.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'aws-sdk-s3'
require 'digest'
require_relative '../tool/tool'
require 'zip'

module Pod
class Prebuild
Expand All @@ -11,34 +13,119 @@ class SharedCache
#
# @return [Boolean]
def self.has?(target, options)
has_local_cache_for(target, options) || has_s3_cache_for(target, options)
end

# `true` if there is local cache for the target
# `false` otherwise
#
# @return [Boolean]
def self.has_local_cache_for?(target, options)
if Podfile::DSL.shared_cache_enabled
framework_cache_path_for(target, options).exist?
path = local_framework_cache_path_for(target, options)
path.exist?
else
false
end
end

# Copies input_path to target's cache
# `true` if there is s3 cache for the target
# `false` otherwise
#
# @return [Boolean]
def has_s3_cache_for?(target, options)
result = false
if Podfile::DSL.shared_s3_cache_enabled
s3_cache_path = s3_framework_cache_path_for(target, options)
s3_cache_path = Podfile::DSL.s3_options[:prefix] + s3_cache_path unless Podfile::DSL.s3_options[:prefix].nil?
s3 = Aws::S3::Resource.new(create_s3_options)
if s3.bucket(Podfile::DSL.s3_options[:bucket]).object("#{s3_cache_path}").exists?
Dir.mktmpdir {|dir|
s3.bucket(Podfile::DSL.s3_options[:bucket]).object("#{s3_cache_path}").get(response_target: "#{dir}/framework.zip")
unzip("#{dir}/framework.zip", path)
result = true
}
end
end
result
end

# @return [{}] AWS connection options
def self.create_s3_options
options = {}
creds = Aws::Credentials.new(Podfile::DSL.s3_options[:login], Podfile::DSL.s3_options[:password]) unless Podfile::DSL.s3_options[:login].nil? and Podfile::DSL.s3_options[:password].nil?
options[:credentials] = creds unless creds.nil?
options[:region] = Podfile::DSL.s3_options[:region] unless Podfile::DSL.s3_options[:region].nil?
options[:endpoint] = Podfile::DSL.s3_options[:endpoint] unless Podfile::DSL.s3_options[:endpoint].nil?

options
end

def self.zip(dir, zip_dir)
Zip::File.open(zip_dir, Zip::File::CREATE)do |zipfile|
Find.find(dir) do |path|
Find.prune if File.basename(path)[0] == ?.
dest = /#{dir}\/(\w.*)/.match(path)
# Skip files if they exists
begin
zipfile.add(dest[1],path) if dest
rescue Zip::ZipEntryExistsError
end
end
end
end

def self.unzip(zip, unzip_dir, remove_after = false)
Zip::File.open(zip) do |zip_file|
zip_file.each do |f|
f_path=File.join(unzip_dir, f.name)
FileUtils.mkdir_p(File.dirname(f_path))
zip_file.extract(f, f_path) unless File.exist?(f_path)
end
end
FileUtils.rm(zip) if remove_after
end

# Copies input_path to target's cache and save to s3 if applicable
def self.cache(target, input_path, options)
if not Podfile::DSL.shared_cache_enabled
return
end
cache_path = framework_cache_path_for(target, options)
cache_path = local_framework_cache_path_for(target, options)
cache_path.mkpath unless cache_path.exist?
FileUtils.cp_r "#{input_path}/.", cache_path
if Podfile::DSL.shared_s3_cache_enabled
s3_cache_path = s3_framework_cache_path_for(target, options)
s3 = Aws::S3::Resource.new(create_s3_options)
Dir.mktmpdir {|dir|
zip(cache_path, "#{dir}/framework.zip")
s3.bucket(Podfile::DSL.s3_options[:bucket]).object("#{Podfile::DSL.s3_options[:prefix]}/#{s3_cache_path}").upload_file("#{dir}/framework.zip")
}
end
end

# Path of the target's cache
# Path of the target's local cache
#
# @return [Pathname]
def self.framework_cache_path_for(target, options)
def self.local_framework_cache_path_for(target, options)
framework_cache_path = cache_root + xcode_version
framework_cache_path = framework_cache_path + target.name
framework_cache_path = framework_cache_path + target.version
options_with_platform = options + [target.platform.name]
framework_cache_path = framework_cache_path + Digest::MD5.hexdigest(options_with_platform.to_s).to_s
end

# Path of the target's s3 cache
#
# @return [Pathname]
def self.s3_framework_cache_path_for(target, options)
framework_cache_path = Pathname.new('') + xcode_version
framework_cache_path = framework_cache_path + target.name
framework_cache_path = framework_cache_path + target.version
options_with_platform = options + [target.platform.name]
framework_cache_path = framework_cache_path + Digest::MD5.hexdigest(options_with_platform.to_s).to_s
end

# Current xcode version.
#
# @return [String]
Expand Down