890 lines
27 KiB
C#
890 lines
27 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace UnityEditor.XCodeEditor
|
|
{
|
|
public partial class XCProject : System.IDisposable
|
|
{
|
|
private PBXDictionary _datastore;
|
|
public PBXDictionary _objects;
|
|
//private PBXDictionary _configurations;
|
|
|
|
private PBXGroup _rootGroup;
|
|
//private string _defaultConfigurationName;
|
|
private string _rootObjectKey;
|
|
|
|
public string projectRootPath { get; private set; }
|
|
private FileInfo projectFileInfo;
|
|
|
|
public string filePath { get; private set; }
|
|
//private string sourcePathRoot;
|
|
private bool modified = false;
|
|
|
|
#region Data
|
|
|
|
// Objects
|
|
private PBXSortedDictionary<PBXBuildFile> _buildFiles;
|
|
private PBXSortedDictionary<PBXGroup> _groups;
|
|
private PBXSortedDictionary<PBXFileReference> _fileReferences;
|
|
private PBXDictionary<PBXNativeTarget> _nativeTargets;
|
|
|
|
private PBXDictionary<PBXFrameworksBuildPhase> _frameworkBuildPhases;
|
|
private PBXDictionary<PBXResourcesBuildPhase> _resourcesBuildPhases;
|
|
private PBXDictionary<PBXShellScriptBuildPhase> _shellScriptBuildPhases;
|
|
private PBXDictionary<PBXSourcesBuildPhase> _sourcesBuildPhases;
|
|
private PBXDictionary<PBXCopyFilesBuildPhase> _copyBuildPhases;
|
|
|
|
private PBXDictionary<PBXVariantGroup> _variantGroups;
|
|
private PBXDictionary<XCBuildConfiguration> _buildConfigurations;
|
|
private PBXSortedDictionary<XCConfigurationList> _configurationLists;
|
|
|
|
private PBXProject _project;
|
|
|
|
#endregion
|
|
|
|
|
|
#region Constructor
|
|
|
|
public XCProject()
|
|
{
|
|
|
|
}
|
|
|
|
public XCProject( string filePath ) : this()
|
|
{
|
|
|
|
if( !System.IO.Directory.Exists( filePath ) ) {
|
|
Debug.LogWarning( "XCode project path does not exist: " + filePath );
|
|
return;
|
|
}
|
|
|
|
if( filePath.EndsWith( ".xcodeproj" ) ) {
|
|
Debug.Log( "Opening project " + filePath );
|
|
this.projectRootPath = Path.GetDirectoryName( filePath );
|
|
this.filePath = filePath;
|
|
} else {
|
|
Debug.Log( "Looking for xcodeproj files in " + filePath );
|
|
string[] projects = System.IO.Directory.GetDirectories( filePath, "*.xcodeproj" );
|
|
if( projects.Length == 0 ) {
|
|
Debug.LogWarning( "Error: missing xcodeproj file" );
|
|
return;
|
|
}
|
|
|
|
this.projectRootPath = filePath;
|
|
//if the path is relative to the project, we need to make it absolute
|
|
if (!System.IO.Path.IsPathRooted(projectRootPath))
|
|
projectRootPath = Application.dataPath.Replace("Assets", "") + projectRootPath;
|
|
//Debug.Log ("projectRootPath adjusted to " + projectRootPath);
|
|
this.filePath = projects[ 0 ];
|
|
}
|
|
|
|
projectFileInfo = new FileInfo( Path.Combine( this.filePath, "project.pbxproj" ) );
|
|
string contents = projectFileInfo.OpenText().ReadToEnd();
|
|
|
|
PBXParser parser = new PBXParser();
|
|
_datastore = parser.Decode( contents );
|
|
if( _datastore == null ) {
|
|
throw new System.Exception( "Project file not found at file path " + filePath );
|
|
}
|
|
|
|
if( !_datastore.ContainsKey( "objects" ) ) {
|
|
Debug.Log( "Errore " + _datastore.Count );
|
|
return;
|
|
}
|
|
|
|
_objects = (PBXDictionary)_datastore["objects"];
|
|
modified = false;
|
|
|
|
_rootObjectKey = (string)_datastore["rootObject"];
|
|
if( !string.IsNullOrEmpty( _rootObjectKey ) ) {
|
|
_project = new PBXProject( _rootObjectKey, (PBXDictionary)_objects[ _rootObjectKey ] );
|
|
_rootGroup = new PBXGroup( _rootObjectKey, (PBXDictionary)_objects[ _project.mainGroupID ] );
|
|
}
|
|
else {
|
|
Debug.LogWarning( "error: project has no root object" );
|
|
_project = null;
|
|
_rootGroup = null;
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Properties
|
|
|
|
public PBXProject project {
|
|
get {
|
|
return _project;
|
|
}
|
|
}
|
|
|
|
public PBXGroup rootGroup {
|
|
get {
|
|
return _rootGroup;
|
|
}
|
|
}
|
|
|
|
public PBXSortedDictionary<PBXBuildFile> buildFiles {
|
|
get {
|
|
if( _buildFiles == null ) {
|
|
_buildFiles = new PBXSortedDictionary<PBXBuildFile>( _objects );
|
|
}
|
|
return _buildFiles;
|
|
}
|
|
}
|
|
|
|
public PBXSortedDictionary<PBXGroup> groups {
|
|
get {
|
|
if( _groups == null ) {
|
|
_groups = new PBXSortedDictionary<PBXGroup>( _objects );
|
|
}
|
|
return _groups;
|
|
}
|
|
}
|
|
|
|
public PBXSortedDictionary<PBXFileReference> fileReferences {
|
|
get {
|
|
if( _fileReferences == null ) {
|
|
_fileReferences = new PBXSortedDictionary<PBXFileReference>( _objects );
|
|
}
|
|
return _fileReferences;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<PBXVariantGroup> variantGroups {
|
|
get {
|
|
if( _variantGroups == null ) {
|
|
_variantGroups = new PBXDictionary<PBXVariantGroup>( _objects );
|
|
}
|
|
return _variantGroups;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<PBXNativeTarget> nativeTargets {
|
|
get {
|
|
if( _nativeTargets == null ) {
|
|
_nativeTargets = new PBXDictionary<PBXNativeTarget>( _objects );
|
|
}
|
|
return _nativeTargets;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<XCBuildConfiguration> buildConfigurations {
|
|
get {
|
|
if( _buildConfigurations == null ) {
|
|
_buildConfigurations = new PBXDictionary<XCBuildConfiguration>( _objects );
|
|
}
|
|
return _buildConfigurations;
|
|
}
|
|
}
|
|
|
|
public PBXSortedDictionary<XCConfigurationList> configurationLists {
|
|
get {
|
|
if( _configurationLists == null ) {
|
|
_configurationLists = new PBXSortedDictionary<XCConfigurationList>( _objects );
|
|
}
|
|
return _configurationLists;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<PBXFrameworksBuildPhase> frameworkBuildPhases {
|
|
get {
|
|
if( _frameworkBuildPhases == null ) {
|
|
_frameworkBuildPhases = new PBXDictionary<PBXFrameworksBuildPhase>( _objects );
|
|
}
|
|
return _frameworkBuildPhases;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<PBXResourcesBuildPhase> resourcesBuildPhases {
|
|
get {
|
|
if( _resourcesBuildPhases == null ) {
|
|
_resourcesBuildPhases = new PBXDictionary<PBXResourcesBuildPhase>( _objects );
|
|
}
|
|
return _resourcesBuildPhases;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<PBXShellScriptBuildPhase> shellScriptBuildPhases {
|
|
get {
|
|
if( _shellScriptBuildPhases == null ) {
|
|
_shellScriptBuildPhases = new PBXDictionary<PBXShellScriptBuildPhase>( _objects );
|
|
}
|
|
return _shellScriptBuildPhases;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<PBXSourcesBuildPhase> sourcesBuildPhases {
|
|
get {
|
|
if( _sourcesBuildPhases == null ) {
|
|
_sourcesBuildPhases = new PBXDictionary<PBXSourcesBuildPhase>( _objects );
|
|
}
|
|
return _sourcesBuildPhases;
|
|
}
|
|
}
|
|
|
|
public PBXDictionary<PBXCopyFilesBuildPhase> copyBuildPhases {
|
|
get {
|
|
if( _copyBuildPhases == null ) {
|
|
_copyBuildPhases = new PBXDictionary<PBXCopyFilesBuildPhase>( _objects );
|
|
}
|
|
return _copyBuildPhases;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region PBXMOD
|
|
|
|
public bool AddOtherCFlags( string flag )
|
|
{
|
|
return AddOtherCFlags( new PBXList( flag ) );
|
|
}
|
|
|
|
public bool AddOtherCFlags( PBXList flags )
|
|
{
|
|
foreach( KeyValuePair<string, XCBuildConfiguration> buildConfig in buildConfigurations ) {
|
|
buildConfig.Value.AddOtherCFlags( flags );
|
|
}
|
|
modified = true;
|
|
return modified;
|
|
}
|
|
|
|
public bool AddOtherLinkerFlagsWithForceLoad(string absoluteFilePath){
|
|
if (!File.Exists(absoluteFilePath)) {
|
|
return false;
|
|
}
|
|
|
|
AddOtherLinkerFlags ("-force_load");
|
|
System.Uri fileURI = new System.Uri( absoluteFilePath );
|
|
System.Uri rootURI = new System.Uri( ( projectRootPath + "/." ) );
|
|
string relativeFilePath = rootURI.MakeRelativeUri( fileURI ).ToString();
|
|
|
|
return AddOtherLinkerFlags (relativeFilePath);
|
|
}
|
|
|
|
public bool AddOtherLinkerFlags( string flag )
|
|
{
|
|
return AddOtherLinkerFlags( new PBXList( flag ) );
|
|
}
|
|
|
|
public bool AddOtherLinkerFlags( PBXList flags )
|
|
{
|
|
foreach( KeyValuePair<string, XCBuildConfiguration> buildConfig in buildConfigurations ) {
|
|
buildConfig.Value.AddOtherLinkerFlags( flags );
|
|
}
|
|
modified = true;
|
|
return modified;
|
|
}
|
|
|
|
public bool overwriteBuildSetting( string settingName, string newValue, string buildConfigName = "all") {
|
|
Debug.Log("overwriteBuildSetting " + settingName + " " + newValue + " " + buildConfigName);
|
|
foreach( KeyValuePair<string, XCBuildConfiguration> buildConfig in buildConfigurations ) {
|
|
//Debug.Log ("build config " + buildConfig);
|
|
XCBuildConfiguration b = buildConfig.Value;
|
|
if ( (string)b.data["name"] == buildConfigName || (string)buildConfigName == "all") {
|
|
//Debug.Log ("found " + b.data["name"] + " config");
|
|
buildConfig.Value.overwriteBuildSetting(settingName, newValue);
|
|
modified = true;
|
|
} else {
|
|
//Debug.LogWarning ("skipping " + buildConfigName + " config " + (string)b.data["name"]);
|
|
}
|
|
}
|
|
return modified;
|
|
}
|
|
|
|
public bool AddHeaderSearchPaths( string path )
|
|
{
|
|
return AddHeaderSearchPaths( new PBXList( path ) );
|
|
}
|
|
|
|
public bool AddHeaderSearchPaths( PBXList paths )
|
|
{
|
|
Debug.Log ("AddHeaderSearchPaths " + paths);
|
|
foreach( KeyValuePair<string, XCBuildConfiguration> buildConfig in buildConfigurations ) {
|
|
buildConfig.Value.AddHeaderSearchPaths( paths );
|
|
}
|
|
modified = true;
|
|
return modified;
|
|
}
|
|
|
|
public bool AddLibrarySearchPaths( string path )
|
|
{
|
|
return AddLibrarySearchPaths( new PBXList( path ) );
|
|
}
|
|
|
|
public bool AddLibrarySearchPaths( PBXList paths )
|
|
{
|
|
Debug.Log ("AddLibrarySearchPaths " + paths);
|
|
foreach( KeyValuePair<string, XCBuildConfiguration> buildConfig in buildConfigurations ) {
|
|
buildConfig.Value.AddLibrarySearchPaths( paths );
|
|
}
|
|
modified = true;
|
|
return modified;
|
|
}
|
|
|
|
public bool AddFrameworkSearchPaths( string path )
|
|
{
|
|
return AddFrameworkSearchPaths( new PBXList( path ) );
|
|
}
|
|
|
|
public bool AddFrameworkSearchPaths( PBXList paths )
|
|
{
|
|
foreach( KeyValuePair<string, XCBuildConfiguration> buildConfig in buildConfigurations ) {
|
|
buildConfig.Value.AddFrameworkSearchPaths( paths );
|
|
}
|
|
modified = true;
|
|
return modified;
|
|
}
|
|
|
|
public object GetObject( string guid )
|
|
{
|
|
return _objects[guid];
|
|
}
|
|
|
|
public PBXDictionary AddFile( string filePath, PBXGroup parent = null, string tree = "SOURCE_ROOT", bool createBuildFiles = true, bool weak = false )
|
|
{
|
|
//Debug.Log("AddFile " + filePath + ", " + parent + ", " + tree + ", " + (createBuildFiles? "TRUE":"FALSE") + ", " + (weak? "TRUE":"FALSE") );
|
|
|
|
PBXDictionary results = new PBXDictionary();
|
|
if (filePath == null) {
|
|
Debug.LogError ("AddFile called with null filePath");
|
|
return results;
|
|
}
|
|
|
|
string absPath = string.Empty;
|
|
|
|
if( Path.IsPathRooted( filePath ) ) {
|
|
Debug.Log( "Path is Rooted" );
|
|
absPath = filePath;
|
|
}
|
|
else if( tree.CompareTo( "SDKROOT" ) != 0) {
|
|
absPath = Path.Combine( Application.dataPath, filePath );
|
|
}
|
|
|
|
if( !( File.Exists( absPath ) || Directory.Exists( absPath ) ) && tree.CompareTo( "SDKROOT" ) != 0 ) {
|
|
Debug.Log( "Missing file: " + filePath );
|
|
return results;
|
|
}
|
|
else if( tree.CompareTo( "SOURCE_ROOT" ) == 0 ) {
|
|
Debug.Log( "Source Root File" );
|
|
System.Uri fileURI = new System.Uri( absPath );
|
|
System.Uri rootURI = new System.Uri( ( projectRootPath + "/." ) );
|
|
filePath = rootURI.MakeRelativeUri( fileURI ).ToString();
|
|
}
|
|
else if( tree.CompareTo("GROUP") == 0) {
|
|
Debug.Log( "Group File" );
|
|
filePath = System.IO.Path.GetFileName( filePath );
|
|
}
|
|
|
|
if( parent == null ) {
|
|
parent = _rootGroup;
|
|
}
|
|
|
|
//Check if there is already a file
|
|
PBXFileReference fileReference = GetFile( System.IO.Path.GetFileName( filePath ) );
|
|
if( fileReference != null ) {
|
|
Debug.Log("File already exists: " + filePath); //not a warning, because this is normal for most builds!
|
|
return null;
|
|
}
|
|
|
|
fileReference = new PBXFileReference( filePath, (TreeEnum)System.Enum.Parse( typeof(TreeEnum), tree ) );
|
|
parent.AddChild( fileReference );
|
|
fileReferences.Add( fileReference );
|
|
results.Add( fileReference.guid, fileReference );
|
|
|
|
//Create a build file for reference
|
|
if( !string.IsNullOrEmpty( fileReference.buildPhase ) && createBuildFiles ) {
|
|
|
|
switch( fileReference.buildPhase ) {
|
|
case "PBXFrameworksBuildPhase":
|
|
foreach( KeyValuePair<string, PBXFrameworksBuildPhase> currentObject in frameworkBuildPhases ) {
|
|
BuildAddFile(fileReference,currentObject,weak);
|
|
}
|
|
if ( !string.IsNullOrEmpty( absPath ) && ( tree.CompareTo( "SOURCE_ROOT" ) == 0 )) {
|
|
string libraryPath = Path.Combine( "$(SRCROOT)", Path.GetDirectoryName( filePath ) );
|
|
if (File.Exists(absPath)) {
|
|
this.AddLibrarySearchPaths( new PBXList( libraryPath ) );
|
|
} else {
|
|
this.AddFrameworkSearchPaths( new PBXList( libraryPath ) );
|
|
}
|
|
|
|
}
|
|
break;
|
|
case "PBXResourcesBuildPhase":
|
|
foreach( KeyValuePair<string, PBXResourcesBuildPhase> currentObject in resourcesBuildPhases ) {
|
|
Debug.Log( "Adding Resources Build File" );
|
|
BuildAddFile(fileReference,currentObject,weak);
|
|
}
|
|
break;
|
|
case "PBXShellScriptBuildPhase":
|
|
foreach( KeyValuePair<string, PBXShellScriptBuildPhase> currentObject in shellScriptBuildPhases ) {
|
|
Debug.Log( "Adding Script Build File" );
|
|
BuildAddFile(fileReference,currentObject,weak);
|
|
}
|
|
break;
|
|
case "PBXSourcesBuildPhase":
|
|
foreach( KeyValuePair<string, PBXSourcesBuildPhase> currentObject in sourcesBuildPhases ) {
|
|
Debug.Log( "Adding Source Build File" );
|
|
BuildAddFile(fileReference,currentObject,weak);
|
|
}
|
|
break;
|
|
case "PBXCopyFilesBuildPhase":
|
|
foreach( KeyValuePair<string, PBXCopyFilesBuildPhase> currentObject in copyBuildPhases ) {
|
|
Debug.Log( "Adding Copy Files Build Phase" );
|
|
BuildAddFile(fileReference,currentObject,weak);
|
|
}
|
|
break;
|
|
case null:
|
|
Debug.LogWarning( "File Not Supported: " + filePath );
|
|
break;
|
|
default:
|
|
Debug.LogWarning( "File Not Supported." );
|
|
return null;
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
public PBXNativeTarget GetNativeTarget( string name )
|
|
{
|
|
PBXNativeTarget naviTarget = null;
|
|
foreach( KeyValuePair<string, PBXNativeTarget> currentObject in nativeTargets ) {
|
|
string targetName = (string)currentObject.Value.data["name"];
|
|
if (targetName == name) {
|
|
naviTarget = currentObject.Value;
|
|
break;
|
|
}
|
|
}
|
|
return naviTarget;
|
|
}
|
|
|
|
public int GetBuildActionMask()
|
|
{
|
|
int buildActionMask = 0;
|
|
foreach( var currentObject in copyBuildPhases )
|
|
{
|
|
buildActionMask = (int)currentObject.Value.data["buildActionMask"];
|
|
break;
|
|
}
|
|
return buildActionMask;
|
|
}
|
|
|
|
public PBXCopyFilesBuildPhase AddEmbedFrameworkBuildPhase()
|
|
{
|
|
PBXCopyFilesBuildPhase phase = null;
|
|
|
|
PBXNativeTarget naviTarget = GetNativeTarget("Unity-iPhone");
|
|
if (naviTarget == null)
|
|
{
|
|
Debug.Log("Not found Correct NativeTarget.");
|
|
return phase;
|
|
}
|
|
|
|
//check if embed framework buildPhase exist
|
|
foreach( var currentObject in copyBuildPhases )
|
|
{
|
|
object nameObj = null;
|
|
if (currentObject.Value.data.TryGetValue("name", out nameObj))
|
|
{
|
|
string name = (string)nameObj;
|
|
if (name == "Embed Frameworks")
|
|
return currentObject.Value;
|
|
}
|
|
}
|
|
|
|
int buildActionMask = this.GetBuildActionMask();
|
|
phase = new PBXCopyFilesBuildPhase(buildActionMask);
|
|
var buildPhases = (ArrayList)naviTarget.data["buildPhases"];
|
|
buildPhases.Add(phase.guid);//add build phase
|
|
copyBuildPhases.Add(phase);
|
|
return phase;
|
|
}
|
|
|
|
public void AddEmbedFramework( string fileName)
|
|
{
|
|
Debug.Log( "Add Embed Framework: " + fileName );
|
|
|
|
//Check if there is already a file
|
|
PBXFileReference fileReference = GetFile( System.IO.Path.GetFileName( fileName ) );
|
|
if( fileReference == null ) {
|
|
Debug.Log("Embed Framework must added already: " + fileName);
|
|
return;
|
|
}
|
|
|
|
var embedPhase = this.AddEmbedFrameworkBuildPhase();
|
|
if (embedPhase == null)
|
|
{
|
|
Debug.Log("AddEmbedFrameworkBuildPhase Failed.");
|
|
return;
|
|
}
|
|
|
|
//create a build file
|
|
PBXBuildFile buildFile = new PBXBuildFile( fileReference );
|
|
buildFile.AddCodeSignOnCopy();
|
|
buildFiles.Add( buildFile );
|
|
|
|
embedPhase.AddBuildFile(buildFile);
|
|
}
|
|
|
|
private void BuildAddFile (PBXFileReference fileReference, KeyValuePair<string, PBXFrameworksBuildPhase> currentObject,bool weak)
|
|
{
|
|
PBXBuildFile buildFile = new PBXBuildFile( fileReference, weak );
|
|
buildFiles.Add( buildFile );
|
|
currentObject.Value.AddBuildFile( buildFile );
|
|
}
|
|
private void BuildAddFile (PBXFileReference fileReference, KeyValuePair<string, PBXResourcesBuildPhase> currentObject,bool weak)
|
|
{
|
|
PBXBuildFile buildFile = new PBXBuildFile( fileReference, weak );
|
|
buildFiles.Add( buildFile );
|
|
currentObject.Value.AddBuildFile( buildFile );
|
|
}
|
|
private void BuildAddFile (PBXFileReference fileReference, KeyValuePair<string, PBXShellScriptBuildPhase> currentObject,bool weak)
|
|
{
|
|
PBXBuildFile buildFile = new PBXBuildFile( fileReference, weak );
|
|
buildFiles.Add( buildFile );
|
|
currentObject.Value.AddBuildFile( buildFile );
|
|
}
|
|
private void BuildAddFile (PBXFileReference fileReference, KeyValuePair<string, PBXSourcesBuildPhase> currentObject,bool weak)
|
|
{
|
|
PBXBuildFile buildFile = new PBXBuildFile( fileReference, weak );
|
|
buildFiles.Add( buildFile );
|
|
currentObject.Value.AddBuildFile( buildFile );
|
|
}
|
|
private void BuildAddFile (PBXFileReference fileReference, KeyValuePair<string, PBXCopyFilesBuildPhase> currentObject,bool weak)
|
|
{
|
|
PBXBuildFile buildFile = new PBXBuildFile( fileReference, weak );
|
|
buildFiles.Add( buildFile );
|
|
currentObject.Value.AddBuildFile( buildFile );
|
|
}
|
|
|
|
public bool AddFolder( string folderPath, PBXGroup parent = null, string[] exclude = null, bool recursive = true, bool createBuildFile = true )
|
|
{
|
|
Debug.Log("Folder PATH: "+folderPath);
|
|
if( !Directory.Exists( folderPath ) ){
|
|
Debug.Log("Directory doesn't exist?");
|
|
return false;
|
|
}
|
|
|
|
if (folderPath.EndsWith(".lproj")){
|
|
Debug.Log("Ended with .lproj");
|
|
return AddLocFolder(folderPath, parent, exclude, createBuildFile);
|
|
}
|
|
|
|
DirectoryInfo sourceDirectoryInfo = new DirectoryInfo( folderPath );
|
|
|
|
if( exclude == null ){
|
|
Debug.Log("Exclude was null");
|
|
exclude = new string[] {};
|
|
}
|
|
|
|
if( parent == null ){
|
|
Debug.Log("Parent was null");
|
|
parent = rootGroup;
|
|
}
|
|
|
|
// Create group
|
|
PBXGroup newGroup = GetGroup( sourceDirectoryInfo.Name, null /*relative path*/, parent );
|
|
Debug.Log("New Group created");
|
|
|
|
foreach( string directory in Directory.GetDirectories( folderPath ) ) {
|
|
Debug.Log( "DIR: " + directory );
|
|
if( directory.EndsWith( ".bundle" ) ) {
|
|
// Treat it like a file and copy even if not recursive
|
|
// TODO also for .xcdatamodeld?
|
|
Debug.LogWarning( "This is a special folder: " + directory );
|
|
AddFile( directory, newGroup, "SOURCE_ROOT", createBuildFile );
|
|
continue;
|
|
}
|
|
|
|
if( recursive ) {
|
|
Debug.Log( "recursive" );
|
|
AddFolder( directory, newGroup, exclude, recursive, createBuildFile );
|
|
}
|
|
}
|
|
|
|
// Adding files.
|
|
string regexExclude = string.Format( @"{0}", string.Join( "|", exclude ) );
|
|
foreach( string file in Directory.GetFiles( folderPath ) ) {
|
|
if( Regex.IsMatch( file, regexExclude ) ) {
|
|
continue;
|
|
}
|
|
Debug.Log("Adding Files for Folder");
|
|
AddFile( file, newGroup, "SOURCE_ROOT", createBuildFile );
|
|
}
|
|
|
|
modified = true;
|
|
return modified;
|
|
}
|
|
|
|
// We support neither recursing into nor bundles contained inside loc folders
|
|
public bool AddLocFolder( string folderPath, PBXGroup parent = null, string[] exclude = null, bool createBuildFile = true)
|
|
{
|
|
DirectoryInfo sourceDirectoryInfo = new DirectoryInfo( folderPath );
|
|
|
|
if( exclude == null )
|
|
exclude = new string[] {};
|
|
|
|
if( parent == null )
|
|
parent = rootGroup;
|
|
|
|
// Create group as needed
|
|
System.Uri projectFolderURI = new System.Uri( projectFileInfo.DirectoryName );
|
|
System.Uri locFolderURI = new System.Uri( folderPath );
|
|
var relativePath = projectFolderURI.MakeRelativeUri( locFolderURI ).ToString();
|
|
PBXGroup newGroup = GetGroup( sourceDirectoryInfo.Name, relativePath, parent );
|
|
|
|
// Add loc region to project
|
|
string nom = sourceDirectoryInfo.Name;
|
|
string region = nom.Substring(0, nom.Length - ".lproj".Length);
|
|
project.AddRegion(region);
|
|
|
|
// Adding files.
|
|
string regexExclude = string.Format( @"{0}", string.Join( "|", exclude ) );
|
|
foreach( string file in Directory.GetFiles( folderPath ) ) {
|
|
if( Regex.IsMatch( file, regexExclude ) ) {
|
|
continue;
|
|
}
|
|
|
|
// Add a variant group for the language as well
|
|
var variant = new PBXVariantGroup(System.IO.Path.GetFileName( file ), null, "GROUP");
|
|
variantGroups.Add(variant);
|
|
|
|
// The group gets a reference to the variant, not to the file itself
|
|
newGroup.AddChild(variant);
|
|
|
|
AddFile( file, variant, "GROUP", createBuildFile );
|
|
}
|
|
|
|
modified = true;
|
|
return modified;
|
|
}
|
|
#endregion
|
|
|
|
#region Getters
|
|
public PBXFileReference GetFile( string name )
|
|
{
|
|
if( string.IsNullOrEmpty( name ) ) {
|
|
return null;
|
|
}
|
|
|
|
foreach( KeyValuePair<string, PBXFileReference> current in fileReferences ) {
|
|
if( !string.IsNullOrEmpty( current.Value.name ) && current.Value.name.CompareTo( name ) == 0 ) {
|
|
return current.Value;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public PBXGroup GetGroup( string name, string path = null, PBXGroup parent = null )
|
|
{
|
|
if( string.IsNullOrEmpty( name ) )
|
|
return null;
|
|
|
|
if( parent == null ) parent = rootGroup;
|
|
|
|
foreach( KeyValuePair<string, PBXGroup> current in groups ) {
|
|
if( string.IsNullOrEmpty( current.Value.name ) ) {
|
|
if( current.Value.path.CompareTo( name ) == 0 && parent.HasChild( current.Key ) ) {
|
|
return current.Value;
|
|
}
|
|
} else if( current.Value.name.CompareTo( name ) == 0 && parent.HasChild( current.Key ) ) {
|
|
return current.Value;
|
|
}
|
|
}
|
|
|
|
PBXGroup result = new PBXGroup( name, path );
|
|
groups.Add( result );
|
|
parent.AddChild( result );
|
|
|
|
modified = true;
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Mods
|
|
public void ApplyMod( string pbxmod )
|
|
{
|
|
XCMod mod = new XCMod( pbxmod );
|
|
foreach(var lib in mod.libs){
|
|
Debug.Log("Library: "+lib);
|
|
}
|
|
ApplyMod( mod );
|
|
}
|
|
|
|
public void ApplyMod( XCMod mod )
|
|
{
|
|
PBXGroup modGroup = this.GetGroup( mod.group );
|
|
|
|
Debug.Log( "Adding libraries..." );
|
|
|
|
foreach( XCModFile libRef in mod.libs ) {
|
|
string completeLibPath = System.IO.Path.Combine( "usr/lib", libRef.filePath );
|
|
Debug.Log ("Adding library " + completeLibPath);
|
|
this.AddFile( completeLibPath, modGroup, "SDKROOT", true, libRef.isWeak );
|
|
}
|
|
|
|
Debug.Log( "Adding frameworks..." );
|
|
PBXGroup frameworkGroup = this.GetGroup( "Frameworks" );
|
|
foreach( string framework in mod.frameworks ) {
|
|
string[] filename = framework.Split( ':' );
|
|
bool isWeak = ( filename.Length > 1 ) ? true : false;
|
|
string completePath = System.IO.Path.Combine( "System/Library/Frameworks", filename[0] );
|
|
this.AddFile( completePath, frameworkGroup, "SDKROOT", true, isWeak );
|
|
}
|
|
|
|
Debug.Log( "Adding files..." );
|
|
foreach( string filePath in mod.files ) {
|
|
string absoluteFilePath = System.IO.Path.Combine( mod.path, filePath );
|
|
|
|
this.AddFile( absoluteFilePath, modGroup );
|
|
}
|
|
|
|
Debug.Log( "Adding embed binaries..." );
|
|
if (mod.embed_binaries != null)
|
|
{
|
|
//1. Add LD_RUNPATH_SEARCH_PATHS for embed framework
|
|
this.overwriteBuildSetting("LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks", "Release");
|
|
this.overwriteBuildSetting("LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks", "Debug");
|
|
|
|
foreach( string binary in mod.embed_binaries ) {
|
|
string absoluteFilePath = System.IO.Path.Combine( mod.path, binary );
|
|
this.AddEmbedFramework(absoluteFilePath);
|
|
}
|
|
}
|
|
|
|
Debug.Log( "Adding folders..." );
|
|
foreach( string folderPath in mod.folders ) {
|
|
string absoluteFolderPath = System.IO.Path.Combine( Application.dataPath, folderPath );
|
|
Debug.Log ("Adding folder " + absoluteFolderPath);
|
|
this.AddFolder( absoluteFolderPath, modGroup, (string[])mod.excludes.ToArray( typeof(string) ) );
|
|
}
|
|
|
|
Debug.Log( "Adding headerpaths..." );
|
|
foreach( string headerpath in mod.headerpaths ) {
|
|
if (headerpath.Contains("$(inherited)")) {
|
|
Debug.Log ("not prepending a path to " + headerpath);
|
|
this.AddHeaderSearchPaths( headerpath );
|
|
} else {
|
|
string absoluteHeaderPath = System.IO.Path.Combine( mod.path, headerpath );
|
|
this.AddHeaderSearchPaths( absoluteHeaderPath );
|
|
}
|
|
}
|
|
|
|
Debug.Log( "Adding compiler flags..." );
|
|
foreach( string flag in mod.compiler_flags ) {
|
|
this.AddOtherCFlags( flag );
|
|
}
|
|
|
|
Debug.Log( "Adding linker flags..." );
|
|
foreach( string flag in mod.linker_flags ) {
|
|
this.AddOtherLinkerFlags( flag );
|
|
}
|
|
|
|
Debug.Log ("Adding plist items...");
|
|
string plistPath = this.projectRootPath + "/Info.plist";
|
|
XCPlist plist = new XCPlist (plistPath);
|
|
plist.Process(mod.plist);
|
|
|
|
this.Consolidate();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Savings
|
|
public void Consolidate()
|
|
{
|
|
PBXDictionary consolidated = new PBXDictionary();
|
|
consolidated.Append<PBXBuildFile>( this.buildFiles );//sort!
|
|
consolidated.Append<PBXCopyFilesBuildPhase>( this.copyBuildPhases );
|
|
consolidated.Append<PBXFileReference>( this.fileReferences );//sort!
|
|
consolidated.Append<PBXFrameworksBuildPhase>( this.frameworkBuildPhases );
|
|
consolidated.Append<PBXGroup>( this.groups );//sort!
|
|
consolidated.Append<PBXNativeTarget>( this.nativeTargets );
|
|
consolidated.Add( project.guid, project.data );//TODO this should be named PBXProject?
|
|
consolidated.Append<PBXResourcesBuildPhase>( this.resourcesBuildPhases );
|
|
consolidated.Append<PBXShellScriptBuildPhase>( this.shellScriptBuildPhases );
|
|
consolidated.Append<PBXSourcesBuildPhase>( this.sourcesBuildPhases );
|
|
consolidated.Append<PBXVariantGroup>( this.variantGroups );
|
|
consolidated.Append<XCBuildConfiguration>( this.buildConfigurations );
|
|
consolidated.Append<XCConfigurationList>( this.configurationLists );
|
|
_objects = consolidated;
|
|
consolidated = null;
|
|
}
|
|
|
|
public void Backup()
|
|
{
|
|
string backupPath = Path.Combine( this.filePath, "project.backup.pbxproj" );
|
|
|
|
// Delete previous backup file
|
|
if( File.Exists( backupPath ) )
|
|
File.Delete( backupPath );
|
|
|
|
// Backup original pbxproj file first
|
|
File.Copy( System.IO.Path.Combine( this.filePath, "project.pbxproj" ), backupPath );
|
|
}
|
|
|
|
private void DeleteExisting(string path)
|
|
{
|
|
// Delete old project file
|
|
if( File.Exists( path ))
|
|
File.Delete( path );
|
|
}
|
|
|
|
private void CreateNewProject(PBXDictionary result, string path)
|
|
{
|
|
PBXParser parser = new PBXParser();
|
|
StreamWriter saveFile = File.CreateText( path );
|
|
saveFile.Write( parser.Encode( result, true ) );
|
|
saveFile.Close();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves a project after editing.
|
|
/// </summary>
|
|
public void Save()
|
|
{
|
|
PBXDictionary result = new PBXDictionary();
|
|
result.Add( "archiveVersion", 1 );
|
|
result.Add( "classes", new PBXDictionary() );
|
|
result.Add( "objectVersion", 46 );
|
|
|
|
Consolidate();
|
|
result.Add( "objects", _objects );
|
|
|
|
result.Add( "rootObject", _rootObjectKey );
|
|
|
|
string projectPath = Path.Combine( this.filePath, "project.pbxproj" );
|
|
|
|
// Delete old project file, in case of an IOException 'Sharing violation on path Error'
|
|
DeleteExisting(projectPath);
|
|
|
|
// Parse result object directly into file
|
|
CreateNewProject(result,projectPath);
|
|
}
|
|
|
|
/**
|
|
* Raw project data.
|
|
*/
|
|
public Dictionary<string, object> objects {
|
|
get {
|
|
return null;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
public void Dispose()
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|