ios-box 0.2.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,23 +1,20 @@
1
1
  IosBox
2
2
  ======
3
3
 
4
- IosBox is collection of Rake Tasks that makes developing iOS apps more easy.
5
- It includes rake tasks that take care of updating app Info.plist with proper
6
- version information (e.g. build date, GIT hash, etc).
7
- Further version will integrate deployment options, such as deploy beta versions
8
- to TestFlight.
4
+ IosBox is tool that integrates with XCode to automate some of the tasks.
9
5
 
10
6
  Current Features
11
7
  ----------------
12
8
 
13
9
  Currently IosBox supports following features:
14
10
 
15
- * <b>Build Prepare</b> (`iosbox:build:prepare`)
16
- Build prepare task generates new build number and bundle version and stores
11
+ * <b>Build Prepare</b> (`build prepare`)
12
+ Build prepare task generates new build and bundle version and stores
17
13
  it to application Info.plist.
18
- It also saves some needed path information to .buildCache for other tasks
14
+ It also prepares buildcache for further tasks.
19
15
 
20
- * <b>Version Mungle</b> (`iosbox:version:*`)
16
+ * <b>Version Management</b> (`version`)
17
+ IosBox offers simple
21
18
  IosBox offers simple tasks to bump version numbers. Either it is patch, minor or
22
19
  major version bump, IosBox automatically handles increasing current version number.
23
20
 
@@ -29,39 +26,48 @@ In the roadmap are following features (but not yet planned)
29
26
  * Asset management, slicing assets according to receipt etc.
30
27
  * More to come, open for suggestions...
31
28
 
32
- Installation
33
- ------------
29
+ # Installation
34
30
 
35
31
  Install `IosBox` gem if you haven't done yet so
36
32
 
37
33
  $ gem install ios-box
38
34
 
39
- Create in the root of your project folder `Rakefile` -file with following contents:
40
-
41
- require 'ios-box'
42
-
43
- IosBox::Tasks.new do |config|
44
- config.target = "iosboxdev"
45
- end
46
-
47
35
  Integrate toolbox with your XCode project by executing following command:
48
36
 
49
- $ rake iosbox:integrate
37
+ $ ios-box integrate
50
38
 
51
39
  Notice! This command will modify your XCode project file and therefore can make your project to stop working.
52
40
  Make sure you have proper backups done.
53
41
 
54
- If you want to integrate IosBox manually, add following script as build phase, preferably as first phase.
42
+ # Usage
43
+
44
+ Run `ios-box help` in project folder to see available commands.
45
+
46
+ # Commands
47
+
48
+ ## ios-box integrate
49
+
50
+ Integrates ios-box to current project. During integration process you can
51
+ choose which targets build preparation task is ran.
52
+
53
+ ## ios-box build prepare
54
+
55
+ This task prepares build process and can be only ran during XCode build phase.
56
+
57
+ ## ios-box version show
58
+
59
+ Displays current version information of the project.
60
+
61
+ ## ios-box version build
55
62
 
56
- (cd $PROJECT_DIR; rake iosbox:build:prepare)
63
+ Increments build number.
57
64
 
58
- Usage
59
- -----
65
+ ## ios-box version bump [major|minor]
60
66
 
61
- Run `rake -T` in project folder to see available commands.
67
+ Bumps marketing version by one step. By default it increases patch level
68
+ but if ptional argument is given, either major or minor version is increased.
62
69
 
63
- Copyright
64
- ---------
70
+ # Copyright
65
71
 
66
72
  Copyright &copy; 2011 Mikko Kokkonen. See LICENSE.txt for
67
73
  further details.
data/bin/ios-box CHANGED
@@ -4,4 +4,4 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
4
 
5
5
  require 'ios-box/cli'
6
6
 
7
- Ios::Box::CLI.start
7
+ IOSBox::CLI.start
data/ios-box.gemspec CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/ios-box/version', __FILE__)
2
+ require File.expand_path('../lib/ios-box', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Mikko Kokkonen"]
@@ -13,9 +13,12 @@ Gem::Specification.new do |gem|
13
13
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
14
  gem.name = "ios-box"
15
15
  gem.require_paths = ["lib"]
16
- gem.version = Ios::Box::VERSION
16
+ gem.version = IOSBox::VERSION
17
17
 
18
18
  gem.add_runtime_dependency "thor"
19
19
  gem.add_runtime_dependency "grit"
20
20
  gem.add_runtime_dependency "plist"
21
+ gem.add_runtime_dependency "rubyzip"
22
+ gem.add_runtime_dependency "rest-client"
23
+ gem.add_runtime_dependency "nokogiri"
21
24
  end
data/lib/ios-box.rb CHANGED
@@ -1,7 +1,3 @@
1
- require "ios-box/version"
2
-
3
- module Ios
4
- module Box
5
- # Your code goes here...
6
- end
1
+ module IOSBox
2
+ VERSION = "0.2.3"
7
3
  end
data/lib/ios-box/cli.rb CHANGED
@@ -1,96 +1,99 @@
1
+ require 'ios-box/config'
1
2
  require 'ios-box/tools'
2
3
  require 'ios-box/iosbox'
3
4
  require 'thor'
4
5
  require 'pbxproject'
5
6
 
6
- module Ios
7
- module Box
8
- class CLI < Thor
9
- include Thor::Actions
10
-
11
- desc "version COMMAND", "Version related subcommands"
12
- subcommand "version", Tools::Version
13
-
14
- desc "build COMMAND", "Build related subcommands"
15
- subcommand "build", Tools::Build
16
-
17
- desc "integrate [PROJECT]", "Integrates ios-box with project, by default first founded"
18
- def integrate(project = nil)
19
- shell = Thor::Shell::Basic.new
20
-
21
- # Find our project
22
- if project.nil?
23
- project = Dir["*.xcodeproj"].first
24
- end
25
-
26
- unless File.exists?(project) and File.directory?(project)
27
- shell.error "Project #{project} is not valid."
28
- exit
29
- end
30
-
31
- shell.say "Integrating to project #{project}"
32
-
33
- # Find our project file, either from command-line or just using first one
34
- xcode = project || Dir["*.xcodeproj"].first
35
- raise "Cannot find project.pbxproj in #{xcode}" unless File.file? "#{xcode}/project.pbxproj"
36
-
37
- # Load our project file
38
- pbx = PBXProject::PBXProject.new :file => "#{xcode}/project.pbxproj"
39
- pbx.parse
40
-
41
- # If target missing, fetch first target
42
- # Find all targets
43
- targets = pbx.find_item :type => PBXProject::PBXTypes::PBXNativeTarget
44
- if targets.nil? or targets.empty?
45
- raise "XCode project does not have any targets!"
46
- end
47
-
48
- # Generate build phase
49
- # Try to find build phases
50
- # prebuilds = pbx.find_item(:type => PBXProject::PBXTypes::PBXShellScriptBuildPhase) || []
51
- # prebuilds.select! do |c|
52
- # !c.comment.match(/ios-box prepare/).nil?
53
- # end
54
- #
55
- prebuilds = [] # Always add new build phase
56
- if prebuilds.empty?
57
- initPhase = PBXProject::PBXTypes::PBXShellScriptBuildPhase.new(
58
- :shellPath => '/bin/sh',
59
- :shellScript => "\"(cd $PROJECT_DIR; #{%x{which ios-box}.strip} build prepare)\"",
60
- :showEnvVarsInLog => 0,
61
- :name => '"ios-box prepare"'
62
- )
63
- initPhase.comment = "ios-box prepare"
64
-
65
- pbx.add_item initPhase
66
- else
67
- initPhase = prebuilds.first
68
- end
69
-
70
- _targets = ""
71
- targets.each do |target|
72
- if shell.yes?("Integrate with target #{target.name.value}? [yn]")
73
- # Inject buildphase to target
74
- # Add to target
75
- target.add_build_phase initPhase, 0
76
- _targets << "config.targets << \"#{target.name.value}\""
77
- end
78
- end
79
-
80
- # Create iosbox configuration file
81
- create_file ".iosbox" do
82
- "# ios-box configuration file\n" +
83
- "# https://github.com/owl-forestry/ios-box\n" +
84
- "#\n" +
85
- "config.project = \"#{project}\"\n" +
86
- "#{_targets}\n"
7
+ module IOSBox
8
+ class CLI < Thor
9
+ include Thor::Actions
10
+
11
+ desc "version COMMAND", "Version related subcommands"
12
+ subcommand "version", Tools::Version
13
+
14
+ desc "build COMMAND", "Build related subcommands"
15
+ subcommand "build", Tools::Build
16
+
17
+ desc "config COMMAND", "Configuration related subcommands"
18
+ subcommand "config", Tools::Config
19
+
20
+ desc "deploy COMMAND", "Deploymend subcommands"
21
+ subcommand "deploy", Tools::Deploy
22
+
23
+ desc "integrate [PROJECT]", "Integrates ios-box with project, by default first founded"
24
+ def integrate(project = nil)
25
+ shell = Thor::Shell::Basic.new
26
+
27
+ # Find our project
28
+ if project.nil?
29
+ project = Dir["*.xcodeproj"].first
30
+ end
31
+
32
+ unless File.exists?(project) and File.directory?(project)
33
+ shell.error "Project #{project} is not valid."
34
+ exit
35
+ end
36
+
37
+ shell.say "Integrating to project #{project}"
38
+
39
+ # Find our project file, either from command-line or just using first one
40
+ xcode = project || Dir["*.xcodeproj"].first
41
+ raise "Cannot find project.pbxproj in #{xcode}" unless File.file? "#{xcode}/project.pbxproj"
42
+
43
+ # Load our project file
44
+ pbx = PBXProject::PBXProject.new :file => "#{xcode}/project.pbxproj"
45
+ pbx.parse
46
+
47
+ # If target missing, fetch first target
48
+ # Find all targets
49
+ targets = pbx.find_item :type => PBXProject::PBXTypes::PBXNativeTarget
50
+ if targets.nil? or targets.empty?
51
+ raise "XCode project does not have any targets!"
52
+ end
53
+
54
+ # Generate build phase
55
+ # Try to find build phases
56
+ # prebuilds = pbx.find_item(:type => PBXProject::PBXTypes::PBXShellScriptBuildPhase) || []
57
+ # prebuilds.select! do |c|
58
+ # !c.comment.match(/ios-box prepare/).nil?
59
+ # end
60
+ #
61
+ prebuilds = [] # Always add new build phase
62
+ if prebuilds.empty?
63
+ initPhase = PBXProject::PBXTypes::PBXShellScriptBuildPhase.new(
64
+ :shellPath => '/bin/sh',
65
+ :shellScript => "\"(cd $PROJECT_DIR; ios-box build prepare)\"",
66
+ :showEnvVarsInLog => 0,
67
+ :name => '"ios-box prepare"'
68
+ )
69
+ initPhase.comment = "ios-box prepare"
70
+
71
+ pbx.add_item initPhase
72
+ else
73
+ initPhase = prebuilds.first
74
+ end
75
+
76
+ targets.each do |target|
77
+ if shell.yes?("Integrate with target #{target.name.value}? [yn]")
78
+ # Inject buildphase to target
79
+ # Add to target
80
+ target.add_build_phase initPhase, 0
87
81
  end
88
- # Append buildcache to gitignore
89
- send((File.exists?(".gitignore") ? :append_to_file : :create_file), ".gitignore", ".buildcache\n")
90
-
91
- # Write project file
92
- pbx.write_to :file => "#{xcode}/project.pbxproj"
93
82
  end
83
+
84
+ # Create iosbox configuration file
85
+ config = Config.new
86
+ config.project = project
87
+ config.targets = targets.collect{|c| c.name.value}
88
+ config.growl = true # Enable Growl support
89
+ config.deploy = {'autonotes' => true} # Generate deployment changelogs from GIT logs
90
+ config.save(".iosbox")
91
+
92
+ # Append buildcache to gitignore
93
+ send((File.exists?(".gitignore") ? :append_to_file : :create_file), ".gitignore", ".buildcache\n")
94
+
95
+ # Write project file
96
+ pbx.write_to :file => "#{xcode}/project.pbxproj"
94
97
  end
95
98
  end
96
99
  end
@@ -1,23 +1,37 @@
1
- module Ios
2
- module Box
3
- class Config
4
- attr_accessor :project
5
- attr_reader :targets
1
+ require 'yaml'
2
+ require 'ostruct'
6
3
 
7
- def self.load(file = ".iosbox")
4
+ module IOSBox
5
+ class Config < OpenStruct
6
+ attr_accessor :file
7
+
8
+ def self.load(file)
9
+ if File.exists?(file)
10
+ config = self.new(YAML.load(File.read(file)))
11
+ else
8
12
  config = self.new
9
- config.instance_eval(File.read(file), file)
10
- config
11
- end
12
-
13
- def initialize
14
- @targets = []
15
- @project = nil
16
13
  end
17
-
18
- def config
19
- self
14
+
15
+ config.file = file
16
+ config
17
+ end
18
+
19
+ def save(file = nil)
20
+ puts "Saving config to #{file || @file}"
21
+ File.open(file || @file, 'w') {|io| io.puts @table.to_yaml }
22
+ end
23
+
24
+ def to_a
25
+ res = []
26
+ @table.collect do |k,v|
27
+ if v.kind_of?(Hash)
28
+ res << ["#{k.to_s}:", ""]
29
+ v.each {|k,v| res << [" #{k.to_s}", v]}
30
+ else
31
+ res << [k.to_s, v]
32
+ end
20
33
  end
34
+ res
21
35
  end
22
36
  end
23
37
  end
@@ -0,0 +1,96 @@
1
+ require 'plist'
2
+ require 'zip/zip'
3
+
4
+ module IOSBox
5
+ module Deploy
6
+ autoload :Testflight, 'ios-box/deploy/testflight'
7
+
8
+ class Deployer
9
+ attr_reader :iosbox
10
+
11
+ def initialize(iosbox)
12
+ @iosbox = iosbox
13
+
14
+ if iosbox.config.growl
15
+ begin
16
+ require 'ruby_gntp'
17
+
18
+ @growl = GNTP.new("ios-box")
19
+ @growl.register({:notifications => [
20
+ {:name => "Deployment Succeeded", :enabled => true},
21
+ {:name => "Deployment Failed", :enabled => true},
22
+ ]})
23
+ rescue LoadError
24
+ iosbox.config.growl = false
25
+ puts "Please install ruby_gntp gem if you want to enable Growl notifications."
26
+ end
27
+ end
28
+ end
29
+
30
+ def notify(opts)
31
+ return unless iosbox.config.growl
32
+
33
+ @growl.notify(
34
+ :name => opts[:name],
35
+ :title => opts[:title],
36
+ :text => opts[:text] || opts[:error]
37
+ )
38
+ end
39
+
40
+ def create_ipa(path)
41
+ puts "Creating IPA from path #{path}..."
42
+
43
+ # Check for missing plist
44
+ raise "Archive info.plist is missing" unless File.exists?(File.join(path, "Info.plist"))
45
+ pl = Plist::parse_xml(File.join(path, "Info.plist"))
46
+ raise "Invalid XCArchive version" unless pl['ArchiveVersion'] == 1
47
+
48
+ app_path = pl['ApplicationProperties']['ApplicationPath']
49
+ app_name = File.basename(app_path, File.extname(app_path))
50
+ ipa_name = File.join(path, "Products", "#{app_name}.ipa")
51
+ puts "Compressing #{app_path}"
52
+ if File.exists?(ipa_name)
53
+ File.unlink(ipa_name)
54
+ end
55
+
56
+ Zip::ZipFile.open(ipa_name, Zip::ZipFile::CREATE) do |zip|
57
+ Dir["#{File.join(path, "Products", app_path)}/**/*"].each do |entry|
58
+ e_name = entry.gsub(/#{File.join(path, "Products", app_path)}\//, '')
59
+ e_name = "Payload/#{app_name}.app/#{e_name}"
60
+ zip.add e_name, entry
61
+ end
62
+ end
63
+
64
+ ipa_name
65
+ end
66
+
67
+ def create_dsym(path)
68
+ puts "Creating Zipped dSYM from path #{path}..."
69
+
70
+ # Check for missing plist
71
+ raise "Archive info.plist is missing" unless File.exists?(File.join(path, "Info.plist"))
72
+ pl = Plist::parse_xml(File.join(path, "Info.plist"))
73
+ raise "Invalid XCArchive version" unless pl['ArchiveVersion'] == 1
74
+
75
+ app_path = pl['ApplicationProperties']['ApplicationPath']
76
+ app_name = File.basename(app_path)
77
+ dsym_name = File.join(path, "dSYMs", "#{app_name}.dSYM.zip")
78
+
79
+ if File.exists?(dsym_name)
80
+ File.unlink(dsym_name)
81
+ end
82
+
83
+ Zip::ZipFile.open(dsym_name, Zip::ZipFile::CREATE) do |zip|
84
+ dsym_path = File.join(path, "dSYMs")
85
+ puts "Path #{dsym_path}"
86
+ Dir["#{File.join(dsym_path, "#{app_name}.dSYM")}/**/*"].each do |entry|
87
+ e_name = entry.gsub(/#{dsym_path}\//, '')
88
+ zip.add e_name, entry
89
+ end
90
+ end
91
+
92
+ dsym_name
93
+ end
94
+ end
95
+ end
96
+ end