require 'aws-sdk' # Workflow # Add gem to Gemfile or gem install # $ ios3 manifest # Creates a Manifest File from the template # $ ios3 upload # Uploads the Manifest and the .ipa from the RubyMotion build # First step is to upload the .ipa # After the ipa is uploaded then we can know the url of the ipa on S3 and put that in the manifest # Then we can upload the manifest # What info do I need from the user? # Bucket to upload to # Path within Bucket to upload to # this should be automatically /ios3/CFBundleName_underscores/CFBundleVersion # # # What do I need from the Filesystem? # AWSKEY # AWSSECRET # AWSREGION # CFBundleVersion # 1.0.0 # CFBundleIdentifier # com.humanswithkids.Blog # CFBundleName module S3 class Client def initialize(access_key_id, secret_access_key, region) @s3 = AWS::S3.new(:access_key_id => access_key_id, :secret_access_key => secret_access_key, :region => region) end def upload_build(ipa, options) # path = expand_path_with_substitutions_from_ipa_plist(ipa, options[:path]) if options[:path] # @s3.buckets.create(options[:bucket]) if options[:create] bucket = @s3.buckets[options[:bucket]] files = [] files << ipa # files << options[:dsym] if options[:dsym] files.each do |file| basename = File.basename(file) key = path ? File.join(path, basename) : basename File.open(file) do |descriptor| bucket.objects.create(key, descriptor, :acl => options[:acl]) end end end # private # # def expand_path_with_substitutions_from_ipa_plist(ipa, path) # substitutions = path.scan(/\{CFBundle[^}]+\}/) # return path if substitutions.empty? # # Dir.mktmpdir do |dir| # system "unzip -q #{ipa} -d #{dir} 2> /dev/null" # # plist = Dir["#{dir}/**/*.app/Info.plist"].last # # substitutions.uniq.each do |substitution| # key = substitution[1...-1] # value = Shenzhen::PlistBuddy.print(plist, key) # # path.gsub!(Regexp.new(substitution), value) if value # end # end # # return path # end end end # command :'manifest' do |c| # c.syntax = "ios3 manifest [options]" # escaped_ipa_url - can we get this from RubyMotion /build/iPhoneOS-8.0-Release/{app_name}.ipa # bundle_identifier # app_version # app_name # # end command :'upload' do |c| c.syntax = "ios3 upload [options]" c.summary = "Distribute an .ipa file over Amazon S3" c.description = "" c.example '', '$ ios3 upload -f ./file.ipa -a accesskeyid --bucket bucket-name' c.option '-b', '--bucket BUCKET', "S3 bucket" c.action do |args, options| determine_ipa! say_error "Missing or unspecified .ipa file" and abort unless @ipa and File.exist?(@ipa) determine_access_key_id! say_error "Missing AWS Access Key ID" and abort unless @access_key_id determine_secret_access_key! say_error "Missing AWS Secret Access Key" and abort unless @secret_access_key determine_bucket! unless @bucket = options.bucket say_error "Missing bucket" and abort unless @bucket determine_region! determine_acl! determine_path! client = S3::Client.new(@access_key_id, @secret_access_key, @region) begin client.upload_build @ipa, {:bucket => @bucket, :acl => @acl, :path => @path} say_ok "Build successfully uploaded to S3" rescue => exception say_error "Error while uploading to S3: #{exception}" end end private def determine_ipa! unless File.exist?('Rakefile') say_error "Run on root directoy of RubyMotion project." end # select *.ipa in Release directory. @ipa = Dir.glob("./build/{iPhoneOS}*-Release/*.{ipa}").first unless @ipa say_error "Can't find *.ipa. First, need to create archive file with `rake archive:distribution'." end @ipa end def determine_access_key_id! @access_key_id ||= ENV['AWS_ACCESS_KEY_ID'] @access_key_id ||= ask "Access Key ID:" end def determine_secret_access_key! @secret_access_key ||= ENV['AWS_SECRET_ACCESS_KEY'] @secret_access_key ||= ask "Secret Access Key:" end def determine_bucket! @bucket ||= ENV['S3_BUCKET'] @bucket ||= ask "S3 Bucket:" end def determine_region! @region ||= ENV['AWS_REGION'] || "us-east-1" end def determine_acl! @acl = "public_read" end def determine_path! # @path = "/ios3/#{cf_bundle_name}/#{cf_bundle_version}" @path = "" end end