Adding files via Applescript to an Xcode project target - xcode

I want to automatically add files to an Xcode project that is created from scratch (through another IDE) as a post-build step. Our project is set up to call an applescript that makes the appropriate file references in the project, but every attempt to add the file references to the project fails.
The core problem seems to be this error:
Xcode got an error: file reference id "DCDCC17E13819A8E004B4E75" of Xcode 3 group id "D82DCFB50E8000A5005D6AD8" of project "TestProject" of workspace document "project.xcworkspace" doesn’t understand the add message.
on this line:
add fileRef to first target of testProject
Where fileRef is the variable set to the newly-created file reference, and testProject is the variable set to the project containing the fileRef.
Here is the code:
on run argv
-- Get the folder containing items to be added to the project
tell application "Finder"
set thisScript to path to me
set projectFolder to get folder of thisScript as string
set sourceFolder to projectFolder & "FilesToAdd:"
end tell
-- Get all the files that will be added to Xcode
tell application "System Events"
set filesToAddList to the name of every disk item of (sourceFolder as alias)
end tell
tell application "Xcode"
-- Open the project using posix-style paths
open ((POSIX path of projectFolder) & "TestProject.xcodeproj")
-- Give Xcode some time to open the project before we start giving it commands
delay 1
set testProject to project "TestProject"
tell testProject
set sourceGroup to group "Sources"
tell sourceGroup
-- Iterate over all files in the list
repeat with i in filesToAddList
set fileName to (contents of i)
-- Get the file path using Unix-style pathing, since that is the kind that Xcode needs
set filePath to (POSIX path of sourceFolder) & fileName
-- Don't add duplicate file references
if filePath is not in path of file references in sourceGroup then
-- Add a new file reference to the project
set fileRef to make new file reference with properties {name:fileName, full path:filePath, path type:absolute, path:filePath, file encoding:macos roman}
-- Add the file reference to the build target
add fileRef to first target of testProject
end if
end repeat
end tell -- end group tell
end tell -- end project tell
end tell -- end app tell
end run
I've looked up other examples of adding files to targets, and it seems like this is the cleanest and concise way of doing it, and it seems to have worked for other people in the past. Is there a different way that file references are supposed to be added to targets?
For reference, I'm running OSX 10.6.7 and Xcode 4.0.2.

So I emailed Apple about this problem, and it turns out to be a bug. I've submitted a bug report, so hopefully this issue will get fixed soon.

Change this:
-- Add the file reference to the build target
add fileRef to first target of testProject
To this:
-- Add the file reference to the build target
tell application "Xcode"
add fileRef to first target of testProject
end tell

Related

How do I access a resource file in Xcode?

To access the resource file namefile from a program:
I ostensibly just need to check the box "target membership" to identify it as a resource file:
but this box is disabled.
What am I missing?
The helloworld target in your project is configured as a command-line tool (the square black icon that looks like a Terminal indicates this). Those compile to a single, standalone file thus Xcode cannot embed a resource file with it (which is why it's disabled).
You need to build a "Cocoa Application" target if you want to be able to include resource files. You can start a new project using the Cocoa Application template or manually add a target to your current project. You'll probably find it easier to start with a new project.
Add resource files to a command line tool
Add the file to the "Copy Files" section of your project's Build Phases:
Make sure to set Destination to "Resources", clear Subpath, and untick Copy only when installing.
Then whenever you build, Xcode will copy the file into your app's build directory, right next to the executable:
That's a screenshot of the ~/Library/Developer/Xcode/DerivedData/[your project]/Build/Products/Debug folder.
This method also works when you archive your app.
Note: if you want the file to be in some subfolder relative to the executable, e.g. res/images/, set the Subpath to that path.

Create separate ClickOnce installs that can be installed together by changing assembly name with MSBUILD

I am using an MSBUILD script to create a publish, it looks something like this:
msbuild "<Project>.vbproj"
/t:Publish
/p:Configuration=Release
/p:ProductName="<Application Name> - <Region Name>"
/p:PublishDir="<Region Specific>"
So far this is working properly.
Is it possible to use MSBUILD to create multiple publishes to different locations that can be installed together? I know that ClickOnce by default doesn't let you install an application from a different location if the application is the same (I believe it determines this by using the assembly name).
I reviewed this thread here:
Multiple ClickOnce installations with different Deployment Identity, but same Application Identity
And because of it, I modified my script to do this:
msbuild "<Project>.vbproj"
/t:Publish
/p:Configuration=Release
/p:ProductName="<Application Name> - <Region Name>"
/p:PublishDir="<Region Specific Unc>"
/p:AssemblyName="<Application Name>_<Region Name>"
However I get a massive amount of errors (like 1300+) but I'm not sure what's going on. But if I change the assembly name in Visual Studios and build it everything is perfectly fine.
Any thoughts?
What happens is that the property AssemblyName is being overriden in all projects msbuild builds in the chain of dependency of your main project. That is causing that many compilation errors. When you change the assemblyName via visual studio you are changing only the main project, which makes it able to build correctly. In one of my projects what i did was add a property on the main .vbproj file called OverridenAssemblyName and set AssemblyName = OverridenAssemblyName when OverridenAssemblyName is not null. That way you can set the AssemblyName only for the project to publish keeping the others intact.
EDIT:
Let's imagine a scenario where you have 2 projects. Project A, which is the project to publish, and Project B, which is referenced by project A. Inside the .vbproj files you have tags like this <AssemblyName>YourProjectName</AssemblyName>. So, in Project A file you would have <AssemblyName>Project A</AssemblyName>, and <AssemblyName>Project B</AssemblyName>in Project B.
That tag is what defines the name of the assembly that is created for the project during the build.
When you pass /p:AssemblyName="<Application Name>_<Region Name>" in your msbuild command line you are overwriting the tag AssemblyName for each project in the build process. And since that property is what defines the assembly name of the project, all projects are having their assemblies generated with the same name. That, probably is the cause of your problem.
A possible solution is to do the following:
Add this to your main project (Project to be published)
<PropertyGroup Condition="$(PublishAssemblyName) != ''">
<AssemblyName>$(PublishAssemblyName)</AssemblyName>
</PropertyGroup>
Change your command line to this:
msbuild "<Project>.vbproj"
/t:Publish
/p:Configuration=Release
/p:ProductName="<Application Name> - <Region Name>"
/p:PublishDir="<Region Specific Unc>"
/p:PublishAssemblyName="<Application Name>_<Region Name>"
I hope that helps you.
I was only able to be successful by doing the msbuild/publish once, then write a separate "deploy" program to change and re-sign the manifests as they moved to each environment. It will deploy to QA giving it a new name and config file. Then later "deploy" again to production, giving it a new name and config file at that time as well.
The process requires renaming to remove the .deploy extension, replacing the config file, change the app manifest, change the deployment manifest, (also in my case, update the .xlsx file because I was doing an vsto excel add-in), then resign app manifest, restore the .deploy extension, resign the deployment manifest, and finally copy the results out to the deploy location.
This results in a deploy to QA that when "click-once'd" creates an "Application-QA" in add/remove programs, and a production deploy that when "click-once'd" creates an "Application-PROD". The two can run concurrently because the assembly name and "solutionId" guid have been updated to be different in each environment.
Below is some code on how to change the app and deployment manifests to give them unique names in each environment. If you decide on this approach and would like code for resigning as well I can help.
Private Function UpdateAppManifestBasedOnTarget(caller As IReleaseExecutionCaller, appName As String, appManifestFileInfo As IO.FileInfo) As String
Log.Write(Me.Name, String.Format("update the app manifest based on the target environment..."))
Dim appManifestXML As New Xml.XmlDocument()
Dim appManifestNamespaces As New Xml.XmlNamespaceManager(appManifestXML.NameTable)
appManifestNamespaces.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1")
appManifestNamespaces.AddNamespace("vstav3", "urn:schemas-microsoft-com:vsta.v3")
appManifestNamespaces.AddNamespace("vstov4", "urn:schemas-microsoft-com:vsto.v4")
appManifestXML.Load(appManifestFileInfo.FullName)
'assemblyIdentity
Dim assemblyNode = appManifestXML.SelectSingleNode("/asmv1:assembly/asmv1:assemblyIdentity", appManifestNamespaces)
assemblyNode.Attributes("name").Value = appName & "-" & caller.Release.EnvironmentCode & ".dll"
'description
Dim descNode = appManifestXML.SelectSingleNode("/asmv1:assembly/asmv1:description", appManifestNamespaces)
descNode.InnerXml = appName & "-" & caller.Release.EnvironmentCode
'soluionid guid
Dim custNode = appManifestXML.SelectSingleNode("/asmv1:assembly/vstav3:addIn/vstav3:application/vstov4:customizations/vstov4:customization/vstov4:document", appManifestNamespaces)
Dim currentGUID = custNode.Attributes("solutionId").Value
Dim newGuid As String = String.Format("{0:x8}{1}", caller.Release.EnvironmentCode.ToLower.GetHashCode(), currentGUID.Substring(8))
custNode.Attributes("solutionId").Value = newGuid
appManifestXML.Save(appManifestFileInfo.FullName)
Return newGuid
End Function
Private Sub UpdateDeploymentManifestBasedOnTarget(caller As IReleaseExecutionCaller, appName As String, vstoFileInfo As IO.FileInfo)
Log.Write(Me.Name, String.Format("update the deployment manifest based on the target environment..."))
Dim vstoXML As New Xml.XmlDocument
Dim vstoManifestNamespaces As New Xml.XmlNamespaceManager(vstoXML.NameTable)
vstoManifestNamespaces.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1")
vstoManifestNamespaces.AddNamespace("asmv2", "urn:schemas-microsoft-com:asm.v2")
vstoXML.Load(vstoFileInfo.FullName)
'assemblyIdentity
Dim assemblyNode = vstoXML.SelectSingleNode("/asmv1:assembly/asmv1:assemblyIdentity", vstoManifestNamespaces)
assemblyNode.Attributes("name").Value = appName & "-" & caller.Release.EnvironmentCode & ".vsto"
'description
Dim descNode = vstoXML.SelectSingleNode("/asmv1:assembly/asmv1:description", vstoManifestNamespaces)
descNode.Attributes("asmv2:product").Value = appName & "-" & caller.Release.EnvironmentCode
'dependancy assemblyIdentity
Dim depAssmblyIdentityNode = vstoXML.SelectSingleNode("/asmv1:assembly/asmv2:dependency/asmv2:dependentAssembly/asmv2:assemblyIdentity", vstoManifestNamespaces)
depAssmblyIdentityNode.Attributes("name").Value = appName & "-" & caller.Release.EnvironmentCode & ".dll"
vstoXML.Save(vstoFileInfo.FullName)
End Sub

How do you generate a Info.plist in Xcode since it is not able to find out?

How do you generate an Info.plist in Xcode because I am getting the following error when I build my project?
error: could not read data from '../dists/xcode/Info.plist': The file “Info.plist” couldn’t be opened because there is no such file.
What should I do?
Thanks!
Sounds like your Info.plist file is merely lost.
Search through your project to see if there is any file with the name "Info.plist", or has "Info.plist" as part of the name (e.g. "TopNotchCoderProjectInfo.plist").
Once you find it, you can either reset your project settings to use the correct Info.plist file -- the path to this specific file can be entered into the Project settings:
Also, make certain the plist file exists in the list of files and folders in your project (and that it isn't "red", which is Xcode's way of telling you it's missing).

unable to copy release folder to desktop using AppleScript

I tried this script to copy release folder of one of my Xcode projects to desktop:
tell application "Finder"
set targetFolder to folder "release" of folder "build" of folder "8_15pm" of folder "26th_March" of folder "XYZ" of startup disk
set destinationFolder to folder "Desktop" of folder "miraaj" of folder "Users" of startup disk
copy targetFolder to destinationFolder
end tell
I was expecting that I will obtain a folder named as release on my desktop but I did not get any :(
Can anyone suggest me where I am wrong or some better way to do this??
Thanks,
Miraaj
change copy to duplicate

How do I set the Active SDK in xcode using AppleScript?

I've managed to set the active target, executable and the build configuration of my project using AppleScript but I can't work out how to set the Active SDK.
Any ideas?
I found the answer. I needed to set the build setting SDKROOT to the path that points to the simulator SDK.
set SDK to "/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.2.1.sdk/"
open file templateProj
set tabReaderProj to project "MyProj"
tell tabReaderProj
set the active target to the target named "MyTarget"
set value of build setting "SDKROOT" of every build configuration of the active target to SDK
end tell

Resources