swiftproj 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ca0cd16af2367356e9386880e476899e81eeb4d0
4
+ data.tar.gz: 53e703ed9fa2ed2b9e8a93366ed39ff4342044eb
5
+ SHA512:
6
+ metadata.gz: 64047d85ef1b8b4ca348d3573fb4fd84b68616bf718dafba4a8fe884b603112e297965ce9a8e08fd92680f489bd6bccf2d6998f60dc5e07919def117162e4a25
7
+ data.tar.gz: 0ba356f9bbd16297fc32e28e5b199601e86b5ebdb5ad17fb917707ee697e5993fc26ad260e4f82f8d887e9e01ed64b7e67ec01cb696231456cf95b596f108f9c
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Suyeol Jeon (xoul.kr)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Swiftproj
2
+
3
+ [![Gem](https://img.shields.io/gem/v/swiftproj.svg)](https://rubygems.org/gems/swiftproj)
4
+ [![Build Status](https://travis-ci.org/devxoul/Swiftproj.svg?branch=master)](https://travis-ci.org/devxoul/Swiftproj)
5
+
6
+ A command-line tool for managing Xcode project with Swift Package Manager. I wrote this to make it easy to deploy to Carthage in a Swift Package Manager only project.
7
+
8
+ ## Basic Usage
9
+
10
+ ```console
11
+ $ swiftproj help
12
+ version Displays the current version of swiftproj
13
+ help Displays this help message
14
+ configure-scheme Configures a scheme to have buildable targets only
15
+ add-systemframework Adds a system framework to an existing target
16
+ remove-framework Removes a framework from a target
17
+ generate-xcconfig Generates a Xcode project file
18
+ generate-xcodeproj Generates a xcconfig file from podspec file
19
+ ```
20
+
21
+ ## Example
22
+
23
+ This is an example of generating Xcodeproj file and archiving for Carthage release.
24
+
25
+ ```console
26
+ $ swiftproj generate-xcconfig --podspec URLNavigator.podspec
27
+ $ swiftproj generate-xcodeproj --xcconfig-overrides Config.xcconfig
28
+ $ swiftproj add-system-framework \
29
+ --project URLNavigator.xcodeproj \
30
+ --target QuickSpecBase \
31
+ --framework Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework
32
+ $ swiftproj configure-scheme \
33
+ --project URLNavigator.xcodeproj \
34
+ --scheme URLNavigator-Package \
35
+ --targets URLNavigator,URLMatcher
36
+ $ carthage build --no-skip-current
37
+ $ carthage archive URLNavigator,URLMatcher
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ ```console
43
+ gem install swiftproj
44
+ ```
45
+
46
+ ## License
47
+
48
+ Swiftproj is under MIT license. See the [LICENSE](LICENSE) for more info.
data/bin/swiftproj ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "swiftproj"
4
+ require "xcodeproj"
5
+
6
+ ui = $stdout
7
+ shell = Swiftproj::Shell.new
8
+ file = File
9
+ core = Swiftproj::Core.new(
10
+ :ui => ui,
11
+ :shell => shell,
12
+ :file => file,
13
+ )
14
+ command = Swiftproj::Command.new(
15
+ :core => core,
16
+ :ui => ui,
17
+ :file => file,
18
+ :project_class => Xcodeproj::Project,
19
+ :scheme_class => Xcodeproj::XCScheme,
20
+ )
21
+ command.run(ARGV)
data/lib/swiftproj.rb ADDED
@@ -0,0 +1,17 @@
1
+ module Swiftproj
2
+ require "colored2"
3
+
4
+ require "swiftproj/error"
5
+ require "swiftproj/pod"
6
+ require "swiftproj/version"
7
+ require "swiftproj/xcodehelper"
8
+
9
+ autoload :Command, "swiftproj/commands/command"
10
+ autoload :Core, "swiftproj/core"
11
+ autoload :Shell, "swiftproj/shell"
12
+
13
+ commands_path = File.expand_path("../swiftproj/commands/*.rb", __FILE__)
14
+ Dir.glob(commands_path).each do |file|
15
+ require file
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ require "swiftproj"
2
+
3
+ module Swiftproj
4
+ class AddSystemFrameworkCommand < Command
5
+ def self.description()
6
+ return "Adds a system framework to an existing target"
7
+ end
8
+
9
+ def self.options()
10
+ return {
11
+ "--project" => "A xcodeproj path (e.g. ReactorKit.xcodeproj)",
12
+ "--target" => "A target name",
13
+ "--framework" => "A framework path to be added (e.g. Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework)",
14
+ }
15
+ end
16
+
17
+ def run(options)
18
+ project_path = options["--project"]
19
+ target_name = options["--target"]
20
+ framework_path = options["--framework"]
21
+
22
+ if project_path.nil?
23
+ raise Swiftproj::MissingArgumentError.new("--project")
24
+ end
25
+ if target_name.nil?
26
+ raise Swiftproj::MissingArgumentError.new("--target")
27
+ end
28
+ if framework_path.nil?
29
+ raise Swiftproj::MissingArgumentError.new("--framework")
30
+ end
31
+
32
+ begin
33
+ project = @project_class.open(project_path)
34
+ rescue
35
+ raise Swiftproj::NoSuchFileError.new(project_path)
36
+ end
37
+
38
+ @core.add_system_framework(project, target_name, framework_path)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,88 @@
1
+ module Swiftproj
2
+ class Command
3
+ def initialize(core:, ui:, file:, project_class:, scheme_class:)
4
+ @core = core
5
+ @ui = ui
6
+ @file = file
7
+ @project_class = project_class
8
+ @scheme_class = scheme_class
9
+ end
10
+
11
+ def run(argv)
12
+ begin
13
+ command_name = argv[0] || 'help'
14
+ command = self.get_command(command_name)
15
+ options = self.parse_options(argv[1..-1])
16
+ if options.include?("--help") or options.include?("-h")
17
+ @ui.puts(command.class.help_message)
18
+ else
19
+ command.run(options)
20
+ end
21
+ rescue Exception => e
22
+ @ui.puts("[!] #{e.message}".red)
23
+ end
24
+ end
25
+
26
+ def get_command(command_name)
27
+ return self.command_class(command_name).new(
28
+ :core => @core,
29
+ :ui => @ui,
30
+ :file => @file,
31
+ :project_class => @project_class,
32
+ :scheme_class => @scheme_class,
33
+ )
34
+ end
35
+
36
+ def command_class(command_name)
37
+ name = "#{command_name}-command".split("-").map { |s| s.capitalize }.join
38
+ begin
39
+ return Swiftproj.const_get(name)
40
+ rescue
41
+ raise Swiftproj::UnknownCommandError
42
+ end
43
+ end
44
+
45
+ def parse_options(argv)
46
+ options = Hash.new
47
+ return options if argv.nil?
48
+
49
+ current_key = nil
50
+ for arg in argv
51
+ if arg.start_with? "-"
52
+ current_key = arg
53
+ options[current_key] = nil
54
+ elsif not current_key.nil?
55
+ options[current_key] = arg
56
+ current_key = nil
57
+ end
58
+ end
59
+ return options
60
+ end
61
+
62
+ def self.command_name()
63
+ command_name = self.name \
64
+ .split("::").last \
65
+ .gsub(/Command$/, "")
66
+ .gsub(/([a-z]+)([A-Z])([a-z]+)/, '\1-\2\3')\
67
+ .downcase
68
+ if not command_name.nil? and command_name.empty?
69
+ return nil
70
+ end
71
+ return command_name
72
+ end
73
+
74
+ def self.description()
75
+ return ""
76
+ end
77
+
78
+ def self.options()
79
+ return {}
80
+ end
81
+
82
+ def self.help_message()
83
+ return self.options
84
+ .map { |name, description| " " + name.blue.ljust(30) + description }
85
+ .join("\n")
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,43 @@
1
+ require "swiftproj"
2
+
3
+ module Swiftproj
4
+ class ConfigureSchemeCommand < Command
5
+ def self.description()
6
+ return "Configures a scheme to have buildable targets only"
7
+ end
8
+
9
+ def self.options()
10
+ return {
11
+ "--project" => "A xcodeproj path (e.g. ReactorKit.xcodeproj)",
12
+ "--scheme" => "A scheme name",
13
+ "--buildable-targets" => "Names for buildable target, seprated by comma (e.g. URLNavigator,URLMatcher)",
14
+ }
15
+ end
16
+
17
+ def run(options)
18
+ project_path = options["--project"]
19
+ scheme_name = options["--scheme"]
20
+ buildable_target_names = options["--buildable-targets"]
21
+
22
+ if project_path.nil?
23
+ raise Swiftproj::MissingArgumentError.new("--project")
24
+ end
25
+ if scheme_name.nil?
26
+ raise Swiftproj::MissingArgumentError.new("--scheme")
27
+ end
28
+ if buildable_target_names.nil?
29
+ raise Swiftproj::MissingArgumentError.new("--buildable-targets")
30
+ end
31
+
32
+ path = "#{project_path}/xcshareddata/xcschemes/#{scheme_name}.xcscheme"
33
+ begin
34
+ scheme = @scheme_class.new(path)
35
+ rescue
36
+ raise Swiftproj::NoSuchFileError.new(project_path)
37
+ end
38
+
39
+ target_names = buildable_target_names.split(",")
40
+ @core.configure_scheme_with_buildable_targets(scheme, target_names)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ module Swiftproj
2
+ class GenerateXcconfigCommand < Command
3
+ def self.description()
4
+ return "Generates a Xcode project file"
5
+ end
6
+
7
+ def self.options()
8
+ return {
9
+ "--podspec" => "A path for podspec file",
10
+ }
11
+ end
12
+
13
+ def run(options)
14
+ podspec_path = options["--podspec"]
15
+ if podspec_path.nil?
16
+ raise Swiftproj::MissingArgumentError.new("--podspec")
17
+ end
18
+
19
+ begin
20
+ podspec_content = @file.open(podspec_path).read
21
+ rescue
22
+ raise Swiftproj::NoSuchFileError.new(podspec_path)
23
+ end
24
+
25
+ podspec = Pod::Spec.from_podspec(podspec_content)
26
+ @core.generate_xcconfig(podspec)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ module Swiftproj
2
+ class GenerateXcodeprojCommand < Command
3
+ def self.description()
4
+ return "Generates a xcconfig file from podspec file"
5
+ end
6
+
7
+ def run(options)
8
+ argv = []
9
+ for key, value in options
10
+ argv.push(key)
11
+ argv.push(value) unless value.nil?
12
+ end
13
+ @core.generate_xcodeproj(argv)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module Swiftproj
2
+ class HelpCommand < Command
3
+ def self.description()
4
+ return "Displays this help message"
5
+ end
6
+
7
+ def run(options)
8
+ message = Swiftproj.constants
9
+ .map { |symbol| symbol.to_s }
10
+ .select { |name| name != "Command" and name.end_with?("Command") }
11
+ .map { |name| Swiftproj.const_get(name) }
12
+ .map { |cls|
13
+ " " + cls.command_name.ljust(22).green + cls.description
14
+ }
15
+ .join("\n")
16
+ @ui.puts(message)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ require "swiftproj"
2
+
3
+ module Swiftproj
4
+ class RemoveFrameworkCommand < Command
5
+ def self.description()
6
+ return "Removes a framework from a target"
7
+ end
8
+
9
+ def self.options()
10
+ return {
11
+ "--project" => "A xcodeproj path (e.g. ReactorKit.xcodeproj)",
12
+ "--target" => "A target name",
13
+ "--framework" => "A framework name to be removed (e.g. XCTest.framework)",
14
+ }
15
+ end
16
+
17
+ def run(options)
18
+ project_path = options["--project"]
19
+ target_name = options["--target"]
20
+ framework_name = options["--framework"]
21
+
22
+ if project_path.nil?
23
+ raise Swiftproj::MissingArgumentError.new("--project")
24
+ end
25
+ if target_name.nil?
26
+ raise Swiftproj::MissingArgumentError.new("--target")
27
+ end
28
+ if framework_name.nil?
29
+ raise Swiftproj::MissingArgumentError.new("--framework")
30
+ end
31
+
32
+ begin
33
+ project = @project_class.open(project_path)
34
+ rescue
35
+ raise Swiftproj::NoSuchFileError.new(project_path)
36
+ end
37
+
38
+ @core.remove_framework(project, target_name, framework_name)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ module Swiftproj
2
+ class VersionCommand < Command
3
+ def self.description()
4
+ return "Displays the current version of swiftproj"
5
+ end
6
+
7
+ def run(options)
8
+ @ui.puts Swiftproj::VERSION
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,82 @@
1
+ module Swiftproj
2
+ class Core
3
+ def initialize(ui:, shell:, file:)
4
+ @ui = ui
5
+ @shell = shell
6
+ @file = file
7
+ end
8
+
9
+ def generate_xcodeproj(argv=nil)
10
+ command = "swift package generate-xcodeproj"
11
+ if argv
12
+ command += " " + argv.join(" ")
13
+ end
14
+ @shell.run(command)
15
+ end
16
+
17
+ def generate_xcconfig(podspec)
18
+ config = "CURRENT_PROJECT_VERSION = #{podspec.version}\n"
19
+ if target = podspec.ios.deployment_target
20
+ config += "IPHONEOS_DEPLOYMENT_TARGET = #{target}\n"
21
+ end
22
+ if target = podspec.osx.deployment_target
23
+ config += "MACOSX_DEPLOYMENT_TARGET = #{target}\n"
24
+ end
25
+ if target = podspec.tvos.deployment_target
26
+ config += "TVOS_DEPLOYMENT_TARGET = #{target}\n"
27
+ end
28
+ if target = podspec.watchos.deployment_target
29
+ config += "WATCHOS_DEPLOYMENT_TARGET = #{target}\n"
30
+ end
31
+ @file.write("Config.xcconfig", config)
32
+ end
33
+
34
+ def add_system_framework(project, target_name, framework_path)
35
+ target = project.targets.find { |t| t.name == target_name }
36
+ if target.nil?
37
+ raise Swiftproj::NoSuchTargetError.new
38
+ end
39
+
40
+ build_phase = target.frameworks_build_phase
41
+ if build_phase.nil?
42
+ raise Swiftproj::NoFrameworksBuildPhaseError.new
43
+ end
44
+
45
+ file = project.new_file(framework_path)
46
+ build_phase.add_file_reference(file)
47
+ project.save
48
+ end
49
+
50
+ def remove_framework(project, target_name, framework_name)
51
+ target = project.targets.find { |t| t.name == target_name }
52
+ if target.nil?
53
+ raise Swiftproj::NoSuchTargetError.new
54
+ end
55
+
56
+ build_phase = target.frameworks_build_phase
57
+ if build_phase.nil?
58
+ raise Swiftproj::NoFrameworksBuildPhaseError.new
59
+ end
60
+
61
+ file = build_phase.files_references.find { |f| f.path == framework_name }
62
+ if file.nil?
63
+ raise Swiftproj::NoFrameworkError.new
64
+ end
65
+
66
+ build_phase.remove_file_reference(file)
67
+ project.save
68
+ end
69
+
70
+ def configure_scheme_with_buildable_targets(scheme, buildable_target_names)
71
+ action = Xcodeproj::XCScheme::BuildAction.new
72
+ for entry in scheme.build_action.entries
73
+ blueprint_name = entry.buildable_references[0].blueprint_name
74
+ if buildable_target_names.include? blueprint_name
75
+ action.add_entry(entry)
76
+ end
77
+ end
78
+ scheme.build_action = action
79
+ scheme.save!
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,39 @@
1
+ module Swiftproj
2
+ class Error < RuntimeError
3
+ end
4
+
5
+ class MissingPodspecVersionError < Error
6
+ end
7
+
8
+ class NoSuchTargetError < Error
9
+ end
10
+
11
+ class NoFrameworksBuildPhaseError < Error
12
+ end
13
+
14
+ class NoFrameworkError < Error
15
+ end
16
+
17
+ class MissingArgumentError < Error
18
+ def initialize(argument_name)
19
+ @argument_name = argument_name
20
+ end
21
+
22
+ def message()
23
+ return "Required argument is missing: #{@argument_name}"
24
+ end
25
+ end
26
+
27
+ class UnknownCommandError < Error
28
+ end
29
+
30
+ class NoSuchFileError < Error
31
+ def initialize(path)
32
+ @path = path
33
+ end
34
+
35
+ def message()
36
+ return "No such file: #{@path}"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,49 @@
1
+ module Pod
2
+ class Spec
3
+ attr_accessor :version
4
+ attr_accessor :ios
5
+ attr_accessor :osx
6
+ attr_accessor :tvos
7
+ attr_accessor :watchos
8
+
9
+ def self.from_podspec(content)
10
+ pod = eval(content)
11
+ if pod.version.nil?
12
+ raise Swiftproj::MissingPodspecVersionError.new
13
+ end
14
+ return pod
15
+ end
16
+
17
+ def initialize()
18
+ @ios = OS.new
19
+ @osx = OS.new
20
+ @tvos = OS.new
21
+ @watchos = OS.new
22
+ yield self if block_given?
23
+ end
24
+
25
+ def method_missing(*args)
26
+ # do nothing
27
+ end
28
+
29
+ def ==(spec)
30
+ return false unless self.class == spec.class
31
+ return false unless self.version == spec.version
32
+ return false unless self.ios == spec.ios
33
+ return false unless self.osx == spec.osx
34
+ return false unless self.tvos == spec.tvos
35
+ return false unless self.watchos == spec.watchos
36
+ return true
37
+ end
38
+ end
39
+
40
+ class OS
41
+ attr_accessor :deployment_target
42
+
43
+ def ==(os)
44
+ return false unless self.class == os.class
45
+ return false unless self.deployment_target == os.deployment_target
46
+ return true
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ module Swiftproj
2
+ class Shell
3
+ def run(command)
4
+ return `#{command}`
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Swiftproj
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ require "xcodeproj"
2
+
3
+ module Xcodeproj
4
+ class XCScheme
5
+ class BuildableReference
6
+ def blueprint_name()
7
+ return @xml_element.attributes["BlueprintName"]
8
+ end
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: swiftproj
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Suyeol Jeon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: xcodeproj
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colored2
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ description:
42
+ email: devxoul@gmail.com
43
+ executables:
44
+ - swiftproj
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - LICENSE
49
+ - README.md
50
+ - bin/swiftproj
51
+ - lib/swiftproj.rb
52
+ - lib/swiftproj/commands/add_system_framework_command.rb
53
+ - lib/swiftproj/commands/command.rb
54
+ - lib/swiftproj/commands/configure_scheme_command.rb
55
+ - lib/swiftproj/commands/generate_xcconfig_command.rb
56
+ - lib/swiftproj/commands/generate_xcodeproj_command.rb
57
+ - lib/swiftproj/commands/help_command.rb
58
+ - lib/swiftproj/commands/remove_framework_command.rb
59
+ - lib/swiftproj/commands/version_command.rb
60
+ - lib/swiftproj/core.rb
61
+ - lib/swiftproj/error.rb
62
+ - lib/swiftproj/pod.rb
63
+ - lib/swiftproj/shell.rb
64
+ - lib/swiftproj/version.rb
65
+ - lib/swiftproj/xcodehelper.rb
66
+ homepage: https://github.com/devxoul/Swiftproj
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.3.1
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.5.1
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: A command-line tool for managing Xcode project with Swift Package Manager
90
+ test_files: []