Skip to content
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- Add support for Swift Packages and Xcode 16 synchronized folders
- Add new optional variable nammed "project_type" which accepts 2 values: "xcode" and "filesystem". When missing ccios use "xcode" by default.
- When "project_type" is set to "filesystem" ccios will not try to update a pbxproj and will only generate files.
- When "project_type" is set to "filesystem" multi target definition is no longer supported for generated files.
- When generating files for an filesystem project, the target name in the header is either: the target defined in the template variables, the target defined in `.ccios.yml`, or it will try to guess the name when using SPM by searching the target name inside the standard naming scheme of: "Sources/<target_name>/".

## [5.1.0]

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ PATH
ccios (5.1.0)
activesupport (> 4)
mustache (~> 1.0)
xcodeproj (~> 1.4)
xcodeproj (~> 1.27)

GEM
remote: https://rubygems.org/
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ templates_collection: ccios/templates

# Global overrides of variables [Optional]
variables:
project_type: xcode
project: Project.xcodeproj
target: SomeDefaultTarget

Expand Down Expand Up @@ -221,6 +222,9 @@ parameters:
# List of templates variables that is used to generate files in an xcode project. [Optional]
# Those variables can be overridden in config file, see section "Variable hierarchy" for more informations.
variables:
# Type of project "filesystem" or "xcode", will be considered as "xcode" if not specified. [Optional]
# You want to use "filesystem" if you want to generate files for an SPM project, or if your Xcode project uses the new synchronized group from Xcode 16.
project_type: filesystem
# The name of the xcode project. "*.xcodeproj" will use the first it finds. [required]
project: "*.xcodeproj"
# The base path used to generate an element. This variable must be defined once here, or on each elements below.
Expand Down Expand Up @@ -297,3 +301,16 @@ Element will use variables in this order (first in this list is used): (For file
- Config Template variables
- Default templates variables
- Config Global variables

# How to develop

1. install the gem locally using
```bash
make install
```
2. Run use the locally installed ccios gem on your project
```bash
ccios presenter MyNewPresenterStack
```

Note: ensure that you use the same ruby version when building, installing and running this local version of ccios.
2 changes: 1 addition & 1 deletion ccios.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Gem::Specification.new do |s|
s.homepage = 'http://rubygems.org/gems/hola'
s.license = 'MIT'
s.add_dependency 'activesupport', '> 4'
s.add_dependency 'xcodeproj', '~> 1.4'
s.add_dependency 'xcodeproj', '~> 1.27'
s.add_dependency "mustache", "~> 1.0"

s.add_development_dependency 'rake', '~> 13.2'
Expand Down
37 changes: 17 additions & 20 deletions lib/ccios/file_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,6 @@
require 'logger'
require 'xcodeproj'

class Xcodeproj::Project::Object::PBXGroup

def pf_new_group(associate_path_to_group:, name:, path:)
# When using "Group with folder" we only provide a path
# When using "Group without folder" we only provide a name
new_group(
associate_path_to_group ? nil : name,
associate_path_to_group ? path : nil
)
end
end

class Xcodeproj::Project

def project_name_from_path
Expand All @@ -37,10 +25,18 @@ def templater_options(targets, project)
full_username: git_username,
date: DateTime.now.strftime("%d/%m/%Y"),
}
if targets.count == 1
defaults["project_name"] = targets[0].display_name
if project.nil?
if targets.count == 1
defaults["project_name"] = targets[0]
else
raise "A file outside an xcode project cannot require multiple targets"
end
else
defaults["project_name"] = project.project_name_from_path
if targets.count == 1
defaults["project_name"] = targets[0].display_name
else
defaults["project_name"] = project.project_name_from_path
end
end
defaults
end
Expand Down Expand Up @@ -69,10 +65,7 @@ def create_file_using_template_path(template_path, generated_filename, group, ta
file.puts(file_content)

file.close
file_ref = group.new_reference(file_path)
targets.each do |target|
target.add_file_references([file_ref])
end
group.register_file_to_targets(file_path, targets)
end

def print_file_content_using_template(filename, template_path, context)
Expand All @@ -83,8 +76,12 @@ def print_file_content_using_template(filename, template_path, context)
logger.info file_content
end

def create_empty_directory(group)
def create_empty_directory_for_group(group)
dirname = group.real_path
create_empty_directory(dirname)
end

def create_empty_directory(dirname)
FileUtils.mkdir_p dirname unless File.directory?(dirname)

git_keep_path = File.join(dirname, ".gitkeep")
Expand Down
81 changes: 52 additions & 29 deletions lib/ccios/file_template_definition.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require_relative 'code_templater'
require_relative 'file_creator'
require_relative 'pbxproj_parser'
require_relative 'xcode_group_representation'

class FileTemplateDefinition
def initialize(file_template_definition_hash)
Expand Down Expand Up @@ -33,20 +33,34 @@ def validate(parser, project, context, template_definition, config)
base_path = merged_variables["base_path"]
raise "Missing base_path variable" if base_path.nil?

base_group = project[base_path]
raise "Base path \"#{base_path}\" is missing" if base_group.nil?

target_name = merged_variables["target"]
if target_name.is_a?(String) || target_name.nil?
target = parser.target_for(project, target_name)
raise "Unable to find target \"#{target_name}\"" if target.nil?
elsif target_name.is_a?(Array)
target_name.each do |target_name|
if project.nil?
if target_name.is_a?(String)
target = target_name
elsif target_name.nil?
guessed_name = guess_target_name_from_path(base_path)
raise "Unable to guess the target from the base path \"#{base_path}\", please specify the target in your config file" if guessed_name.nil?
target = guessed_name
elsif target_name.is_a?(Array)
raise "A template generating files in an filesystem project type cannot specify multiple targets"
else
raise "Invalid target in template #{@name}"
end
else
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
raise "Base path \"#{base_path}\" is missing" if base_group.nil?

if target_name.is_a?(String) || target_name.nil?
target = parser.target_for(project, target_name)
raise "Unable to find target \"#{target_name}\"" if target.nil?
elsif target_name.is_a?(Array)
target_name.each do |target_name|
target = parser.target_for(project, target_name)
raise "Unable to find target \"#{target_name}\"" if target.nil?
end
else
raise "Invalid target in template #{@name}"
end
else
raise "Invalid target in template #{@name}"
end

end
Expand All @@ -55,32 +69,30 @@ def generate(parser, project, context, template_definition, config)
merged_variables = config.variables_for_template_element(template_definition, @name, @variables)

base_path = merged_variables["base_path"]
base_group = project[base_path]
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
file_path = CodeTemplater.new.render_string(@path, context)

intermediates_groups = file_path.split("/")[0...-1]
generated_filename = file_path.split("/")[-1]

group = base_group
associate_path_to_group = !base_group.path.nil?

intermediates_groups.each do |group_name|
new_group_path = File.join(group.real_path, group_name)
existing_group = group.groups.find { |g| g.display_name == group_name }
group = existing_group || group.pf_new_group(
associate_path_to_group: associate_path_to_group,
name: group_name,
path: new_group_path
)
end
group = base_group.create_groups_if_needed_for_intermediate_groups(intermediates_groups)

target_name = merged_variables["target"]

targets = []
if target_name.is_a?(String) || target_name.nil?
targets = [parser.target_for(project, target_name)]
elsif target_name.is_a?(Array)
targets = target_name.map { |name| parser.target_for(project, name) }
if project.nil?
if target_name.is_a?(String)
targets = [target_name]
elsif target_name.nil?
guessed_name = guess_target_name_from_path(base_path)
targets = [guessed_name]
end
else
if target_name.is_a?(String) || target_name.nil?
targets = [parser.target_for(project, target_name)]
elsif target_name.is_a?(Array)
targets = target_name.map { |name| parser.target_for(project, name) }
end
end

FileCreator.new.create_file_using_template_path(
Expand All @@ -92,4 +104,15 @@ def generate(parser, project, context, template_definition, config)
context
)
end
end

private def guess_target_name_from_path(path)
# SPM standard format
parts = path.split(File::SEPARATOR)
sources_index = parts.index("Sources")
if sources_index && sources_index + 1 < parts.length
return parts[sources_index + 1]
else
return nil
end
end
end
25 changes: 6 additions & 19 deletions lib/ccios/group_template_definition.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require_relative 'code_templater'
require_relative 'file_creator'
require_relative 'pbxproj_parser'

class GroupTemplateDefinition
def initialize(group_template_definition_hash)
Expand All @@ -22,33 +21,21 @@ def validate(parser, project, context, template_definition, config)
base_path = merged_variables["base_path"]
raise "Missing base_path variable" if base_path.nil?

base_group = project[base_path]
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
raise "Base path \"#{base_path}\" is missing" if base_group.nil?
end

def generate(parser, project, context, template_definition, config)
merged_variables = config.variables_for_template_element(template_definition, @name, @variables)

base_path = merged_variables["base_path"]
base_group = project[base_path]
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
group_path = CodeTemplater.new.render_string(@path, context)

group_path = group_path.split("/")

group = base_group
associate_path_to_group = !base_group.path.nil?

group_path.each do |group_name|
new_group_path = File.join(group.real_path, group_name)
existing_group = group.groups.find { |g| g.display_name == group_name }
group = existing_group || group.pf_new_group(
associate_path_to_group: associate_path_to_group,
name: group_name,
path: new_group_path
)
end
group_path_components = group_path.split("/")
group = base_group.create_groups_if_needed_for_intermediate_groups(group_path_components)

file_creator = FileCreator.new
file_creator.create_empty_directory(group)
file_creator.create_empty_directory_for_group(group)
end
end
end
2 changes: 1 addition & 1 deletion lib/ccios/pbxproj_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ def target_for(project, target_name)
project.targets.find { |t| t.name == target_name }
end
end
end
end
26 changes: 20 additions & 6 deletions lib/ccios/template_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,17 @@ def validate(parser, options, config)
raise "Error: invalid template name" unless @name.is_a? String

merged_variables = config.variables_for_template(self)
project_path = merged_variables["project"]

project = parser.project_for(project_path)
raise "Error: Unable to find project \"#{project_path}\"" if project.nil?
project_type = merged_variables["project_type"] || "xcode"
case project_type
when "xcode"
project_path = merged_variables["project"]
project = parser.project_for(project_path)
raise "Error: Unable to find project \"#{project_path}\"" if project.nil?
when "filesystem"
project = nil
else
raise "Invalid project_type given \"#{project_type}\", only \"xcode\" and \"fiilesystem\" are supported"
end

@template_file_source.each do |file_template_name, path|
raise "Missing template source file for \"#{file_template_name}\"" unless File.exist?(self.template_source_file(file_template_name))
Expand Down Expand Up @@ -93,9 +100,16 @@ def generate(parser, options, config)
options = agrument_transformed_options(options)

merged_variables = config.variables_for_template(self)
project_path = merged_variables["project"]

project = parser.project_for project_path
project_type = merged_variables["project_type"] || "xcode"
case project_type
when "xcode"
project_path = merged_variables["project"]
project = parser.project_for project_path
when "filesystem"
project = nil

end

@generated_elements.each do |element|
element.generate(parser, project, options, self, config)
Expand Down
Loading