Preserve folder structure Cocoa Pods

Well I have achieved to create my own folders with subspec.

You can create a subspec with this line:

s.subspec 'folder name' do |ss|
    ss.source_files = 'files'
    ss.frameworks = 'frameworks'
end

The ss.frameworks is not mandatory.

You can see the complete answer from the CocoaPods mail list:

https://groups.google.com/forum/#!topic/cocoapods/0kV8r2xnqA8

Thanks mcitrrus

I preferred to follow the AFNetworking pod spec:

https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking.podspec


If you work with development pods a lot then the default project structure that cocoapods creates has numerous problems:

  • If you don't have at least one file at the root of your source_files / resources etc then the root directory(s) doesn't get an equivalent group in the project.

  • The location of groups point to the root of your pod directory (and not necessarily where your source files are). This means you cannot just right click the group and "Add Files" because it put files in the wrong location.

  • The order of groups and files differs between modules because things are sorted by name and your pods obviously have different names that may or may not appear before Frameworks / Pods / Dependencies / Support Files.


I was looking for a solution that addresses all of the above and have finally come up with the following:

Prerequisites

I setup my pods with a directory structure as follows (example shows pod named SomeLib)

Example/
   SomeLib-Example/...
   SomeLib-Example.xcodeproject

fix_project_structure (this is an empty text file)

SomeLib.podspec

Sources/
   FolderA/
      ClassA.swift
   FolderB/
      ClassA.swift

Tests/
   fix_project_structure (another empty text file)
   FolderA/
      ClassATests.swift
   FolderB/
      ClassBTests.swift

Step 1 - Have Groups Mirror Directory Hierarchy

In your podspec file we utilitise the empty fix_project_structure that lives in the root to fix the group structure...

  s.source_files = 'Sources/**/*.{swift}', 'fix_project_structure'
  s.resource_bundles = {
    s.name => ['Sources/**/*.{xcassets,json,storyboard,xib,xcdatamodeld}', 'fix_project_structure']
  }

  s.test_spec 'Tests' do |test_spec|
    test_spec.source_files = 'Tests/**/*', 'Tests/fix_project_structure'
  end  

Step 2 - Reorder and Fix-Up Group Locations

This is actually an optional step (see comment)

Add the following post_integrate step to your Podfile...

post_integrate do |installer|

  # Fix up the Development Pods so they are easier to work with.
  # The following changes are made to any pod that contains a `fix_project_structure` file
  #  - Removes the (now redundant) `fix_project_structure` file
  #  - Moves the root {project_name} group to the top
  #  - Moves the {project_name}/Sources group to the top
  #  - Moves the {project_name}/Tests group below {project_name}/Sources
  #  - Repoints the {project_name}/Tests group so it reflects its location on disc
  # Note this script makes no functional changes to the pod so you should be able to comment out 
  #   all of this script and have things continue to work just fine
  installer.generated_projects.each do |project|

    fix_files = project.files.select { |file| File.basename(file.path) == "fix_project_structure" }
    project_name = "#{File.basename(project.path, '.xcodeproj')}"
    next if fix_files.nil? || fix_files.empty? || project_name.nil?

    puts "#{project_name} -> #{project.path}"
    puts "  `fix_project_structure` file(s) FOUND"
    puts "    Removing `fix_project_structure` file(s) from project entirely"
    fix_files.each { |fix_file| fix_file.remove_from_project }

    project_group = project.groups.find.find { |group| group.to_s == project_name }
    next if project_group.nil?

    puts "  `#{project_name}` group FOUND"
    puts "    Moving `#{project_name}` group to top"
    project.main_group.children.delete(project_group)
    project.main_group.children.insert(0, project_group)

    sources_group = project_group.groups.find.find { |subgroup| subgroup.to_s == 'Sources' }
    if sources_group.nil? != true
      puts "    `#{project_name}/Sources` group FOUND"
      puts "      Moving `#{project_name}/Sources` group to top"
      project_group.children.delete(sources_group)
      project_group.children.insert(0, sources_group)

      tests_group = project_group.groups.find.find { |subgroup| subgroup.to_s == 'Tests' }
      if tests_group.nil? != true
        puts "    `#{project_name}/Test` group FOUND"

        puts "      Moving `#{project_name}/Test` group below `#{project_name}/Sources`"
        project_group.children.delete(tests_group)
        project_group.children.insert(1, tests_group)

        puts "      Adjusting `#{project_name}/Test` group and immediate children location"
        tests_group.set_path("#{tests_group.real_path}/Tests")
        tests_group.children.each do |tests_child|
          tests_child_path_before = tests_child.path
          tests_child.set_path("#{tests_child.real_path.to_s.gsub('/Tests/Tests/', '/Tests/')}")
          #puts "      '#{tests_child.path.to_s}' (previously '#{tests_child_path_before}')"
        end
      end
    end

    project.save

  end

end