Skip to content
This repository has been archived by the owner on Jun 20, 2021. It is now read-only.

Commit

Permalink
Cleaning up and refactoring FTP feature merge
Browse files Browse the repository at this point in the history
  • Loading branch information
mattt committed Dec 14, 2012
1 parent ec37854 commit 591b205
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 83 deletions.
1 change: 0 additions & 1 deletion bin/ipa
Expand Up @@ -14,7 +14,6 @@ program :help, 'Author', 'Mattt Thompson <m@mattt.me>'
program :help, 'Website', 'http://mattt.me'
program :help_formatter, :compact

# global_option '--verbose'
default_command :help

require 'shenzhen/commands'
1 change: 1 addition & 0 deletions lib/shenzhen.rb
Expand Up @@ -4,3 +4,4 @@ module Shenzhen

require 'shenzhen/agvtool'
require 'shenzhen/xcodebuild'
require 'shenzhen/plistbuddy'
1 change: 0 additions & 1 deletion lib/shenzhen/commands/build.rb
Expand Up @@ -9,7 +9,6 @@
c.option '-s', '--scheme SCHEME', 'Scheme used to build app'
c.option '--[no-]clean', 'Clean project before building'
c.option '--[no-]archive', 'Archive project after building'
c.option '-q', '--quiet', 'Silence warning and success messages'

c.action do |args, options|
validate_xcode_version!
Expand Down
9 changes: 9 additions & 0 deletions lib/shenzhen/plistbuddy.rb
@@ -0,0 +1,9 @@
module Shenzhen::PlistBuddy
class << self
def print(file, key)
output = `/usr/libexec/PlistBuddy -c "Print :#{key}" "#{file}" 2> /dev/null`

!output || output.empty? || /Does Not Exist/ === output ? nil : output.strip
end
end
end
136 changes: 55 additions & 81 deletions lib/shenzhen/plugins/ftp.rb
Expand Up @@ -5,88 +5,71 @@ module FTP
class Client

def initialize(host, user, pass)
@host, @user, @pass = host, user, pass
@host, @user, @password = host, user, pass

@connection = Net::FTP.new
@connection.passive = true
@connection.connect(@host)
end

def upload_build(files, options)
def upload_build(ipa, options)
path = expand_path_with_substitutions_from_ipa_plist(ipa, options[:path])

@ipa_path = files[:ipa]
@dsym_path = files[:dsym]
@ftp_path = get_path_from_ipa(@ipa_path, options[:path])
begin
@connection.login(@user, @password) rescue raise "Login authentication failed"

@connection.login(@user, @pass) rescue raise "Login authentication failed"
if options[:mkdir]
components, pwd = path.split(/\//), nil
components.each do |component|
pwd = File.join(*[pwd, component].compact)

if options[:mkdir]
paths = @ftp_path.split('/')
(1..paths.size).each do |i|
begin
path = paths.slice(0,i).join('/')
next if path == ""
@connection.mkdir path
rescue => exception
if !exception.to_s.match(/File exists/)
raise "Can not create folder \"#{path}\". FTP exception: #{exception}"
begin
@connection.mkdir pwd
rescue => exception
raise exception unless /File exists/ === exception.message
end
end
end
end

begin
@connection.chdir @ftp_path
rescue => exception
raise "Can not enter folder \"#{@ftp_path}\". FTP exception: #{exception}"
end

begin
@connection.putbinaryfile(@ipa_path,File.basename(@ipa_path))
rescue => exception
raise "Error while uploading ipa file to path \"#{@ftp_path}\". FTP exception: #{exception}"
end
@connection.chdir path unless path.empty?
@connection.putbinaryfile ipa, File.basename(ipa)

if @dsym_path
begin
@connection.putbinaryfile(@dsym_path,File.basename(@dsym_path))
rescue => exception
raise "Error while uploading dsym file to path \"#{@ftp_path}\". FTP exception: #{exception}"
end
end
if dsym = options.delete(:dsym)
@connection.putbinaryfile dsym, File.basename(dsym)
end

ensure
@connection.close

end
end

def get_path_from_ipa(ipa, path)
private

plist_regex = Regexp.new "({(CFBundle[^}]+)})"
if plist_regex.match path
def expand_path_with_substitutions_from_ipa_plist(ipa, path)
components = []

# unzip the ipa file to a temp dir in order to read its Info.plist file
tmp_dir = "#{Dir.tmpdir}/ShenzhenFtp"
system "rm -rf #{tmp_dir}; mkdir #{tmp_dir}; unzip -q #{ipa} -d #{tmp_dir} 2> /dev/null"

# replace all occurences of {CFBundle***} from the plist file to use with the path
path.gsub!(plist_regex) do
output = `/usr/libexec/PlistBuddy -c \"Print :#{$2}\" #{tmp_dir}/Payload/*.app/Info.plist 2> /dev/null`.chomp
output.size == 0 || /Does Not Exist/.match(output) ? $1 : output
end
substitutions = path.scan(/\{CFBundle[^}]+\}/)
return path if substitutions.empty?

system "rm -rf #{tmp_dir}"
Dir.mktmpdir do |dir|
system "unzip -q #{ipa} -d #{dir} 2> /dev/null"

end
plist = Dir["#{dir}/**/Info.plist"].last

path
substitutions.uniq.each do |substitution|
key = substitution[1...-1]
value = Shenzhen::PlistBuddy.print(plist, key)

end
path.gsub!(Regexp.new(substitution), value) if value
end
end

return path
end
end
end
end


command :'distribute:ftp' do |c|
c.syntax = "ipa distribute:ftp [options]"
c.summary = "Distribute an .ipa file over FTP"
Expand All @@ -96,61 +79,52 @@ def get_path_from_ipa(ipa, path)

c.option '-f', '--file FILE', ".ipa file for the build"
c.option '-d', '--dsym FILE', "zipped .dsym package for the build"
c.option '-h', '--host HOST', "FTP Host"
c.option '-h', '--host HOST', "FTP host"
c.option '-u', '--user USER', "FTP user"
c.option '-p', '--pass PASS', "FTP password"
c.option '-P', '--path PATH', "FTP Path. Might have any Info.plist params \n\t\t eg. \"/path/to/folder/{CFBundleVersion}/\" will be evaluated as \"/path/to/folder/1.0.0/\" depending on your ipa file"
c.option '-m', '--mkdir', "Folder tree will be created at the ftp server if it doesn't exist"
c.option '-q', '--quiet', "Silence warning and success messages"

c.option '-p', '--password PASS', "FTP password"
c.option '-P', '--path PATH', "FTP path. Values from Info.plist will be substituded for keys wrapped in {} \n\t\t eg. \"/path/to/folder/{CFBundleVersion}/\" could be evaluated as \"/path/to/folder/1.0.0/\""
c.option '--[no-]mkdir', "Create directories on FTP if they don't already exist"

c.action do |args, options|

determine_file! unless @file = options.file
say_error "Missing or unspecified .ipa file" and abort unless @file and File.exist?(@file)

determine_dsym! unless @dsym = options.dsym
say_error "Specified dSYM.zip file doesn't exist" if @dsym and !File.exist?(@dsym)
say_error "Specified dSYM.zip file doesn't exist" unless @dsym and File.exist?(@dsym)

@host = options.host
determine_host! unless @host = options.host
say_error "Missing FTP host" and abort unless @host

determine_user! unless @user = options.user
say_error "Missing FTP user" and abort unless @user

determine_pass! unless @pass = options.pass
say_error "Missing FTP password" and abort unless @pass

@path = options.path
say_error "Missing FTP Path" and abort unless @path
determine_password! unless @password = options.password
say_error "Missing FTP password" and abort unless @password

parameters = {}
parameters[:path] = @path
parameters[:mkdir] = options.mkdir ? true : false
@path = options.path || ""

client = Shenzhen::Plugins::FTP::Client.new @host, @user, @pass

files = {}
files[:ipa] = @file
files[:dsym] = @dsym if @dsym
client = Shenzhen::Plugins::FTP::Client.new(@host, @user, @password)

begin
client.upload_build files, parameters
client.upload_build @file, {:path => @path, :dsym => @dsym, :mkdir => !!options.mkdir}
say_ok "Build successfully uploaded to FTP" unless options.quiet
rescue => exception
say_error "Error while uploading to FTP: #{exception}"
end

end

private

def determine_user!
@user ||= ask "Ftp user:"
def determine_host!
@host ||= ask "FTP Host:"
end

def determine_pass!
@pass ||= ask("Ftp password:"){ |q| q.echo = "*" }
def determine_user!
@user ||= ask "Username:"
end

end
def determine_password!
@password ||= password "Password:"
end
end

0 comments on commit 591b205

Please sign in to comment.