tags:

views:

1602

answers:

9

We are trying to make a project template, but the documentation on this is spotty or non-existent.

Doing some reverse-engineering on some template files, we have come up with the following. However, it doen't actually work!

First of all, we have figured out that project templates should be installed inside:

~/Library/Application Support/Developer/Shared/Xcode/Project Templates

We have made project and installed it here, and this part works - we see this show up in the "User Templates" section of the Xcode "New Project" chooser.

The project folder contains the following files. As you can see, I want the file names to be subsituted (that part works) but as you will see, I also want the contents of the files to be substituted; this doesn't happen.

  • ___PROJECTNAME___.xcodeproj
  • ___PROJECTNAMEASIDENTIFIER____Prefix.pch
  • ___PROJECTNAMEASIDENTIFIER___.icns
  • ___PROJECTNAMEASIDENTIFIER___Delegate.h
  • ___PROJECTNAMEASIDENTIFIER___Delegate.m
  • ___PROJECTNAMEASIDENTIFIER___Template.html
  • Debug.xcconfig
  • en.lproj
  • Info.plist
  • Release.xcconfig

I have put in two special files into the ___PROJECTNAME___.xcodeproj package:

  • TemplateInfo.plist
  • TemplateIcon.icns - the icon to show up in the New Project window

If I create a new project (called "Foo & Bar" as a stress test) using this template, these are the files it creates:

  • Debug.xcconfig
  • en.lproj
  • Foo & Bar.xcodeproj
  • Foo___Bar_Prefix.pch
  • Foo___Bar.icns
  • Foo___BarDelegate.h
  • Foo___BarDelegate.m
  • Foo___BarTemplate.html
  • Info.plist
  • Release.xcconfig

So far so good!

But looking in the file contents, I get things like this. Here is the contents of Foo___BarDelegate.m:

//
//  «PROJECTNAMEASIDENTIFIER»Delegate.m
//  «PROJECTNAME»
//
//  Created by «FULLUSERNAME» on «DATE».
//  Copyright «ORGANIZATIONNAME» «YEAR» . All rights reserved.
//

#import "«PROJECTNAMEASIDENTIFIER»Delegate.h"


@implementation «PROJECTNAMEASIDENTIFIER»Delegate

@end

The apparent issue is that somehow I'm doing the TemplateInfo.plist wrong. But then again, notice how not only are my special items not being substitued, but the standard items don't even get replaced! So maybe it's a deeper issue.

But with a problematic TemplateInfo.plist being my best hypothesis, I present a couple of variations I have tried. Neither work.

Either:

{
    FilesToMacroExpand = (
        "\_\_\_PROJECTNAMEASIDENTIFIER\_\_\_\_Prefix.pch",
        "en.lproj/InfoPlist.strings",
        "\_\_\_PROJECTNAMEASIDENTIFIER\_\_\_\_Prefix.pch",
        "\_\_\_PROJECTNAMEASIDENTIFIER\_\_\_.icns",
        "\_\_\_PROJECTNAMEASIDENTIFIER\_\_\_Delegate.h",
        "\_\_\_PROJECTNAMEASIDENTIFIER\_\_\_Delegate.m",
        "\_\_\_PROJECTNAMEASIDENTIFIER\_\_\_Template.html",
        "Info.plist"
    );
    Description = "This project builds a cocoa-based \"element\" plugin for Sandvox.";
}

or:

{
    FilesToMacroExpand = (
        "«PROJECTNAMEASIDENTIFIER»\_Prefix.pch",
        "en.lproj/InfoPlist.strings",
        "«PROJECTNAMEASIDENTIFIER»\_Prefix.pch",
        "«PROJECTNAMEASIDENTIFIER».icns",
        "«PROJECTNAMEASIDENTIFIER»Delegate.h",
        "«PROJECTNAMEASIDENTIFIER»Delegate.m",
        "«PROJECTNAMEASIDENTIFIER»Template.html",
        "Info.plist"
    );
    Description = "This project builds a cocoa-based \"element\" plugin for Sandvox.";
}

Update: I've also tried adding the "FilesToRename" key, even though the ___ seems to be automatically causing renaming to happen. This is the plist contents with that in, in XML format (since some people were worried about that UTF-8 nature of things -- yes, it's a valid plist):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
<plist version="1.0">
<dict>
    <key>Description</key>
    <string>This project builds a cocoa-based "element" plugin for Sandvox.</string>
    <key>FilesToMacroExpand</key>
    <array>
        <string>«PROJECTNAMEASIDENTIFIER»_Prefix.pch</string>
        <string>en.lproj/InfoPlist.strings</string>
        <string>«PROJECTNAMEASIDENTIFIER».icns</string>
        <string>«PROJECTNAMEASIDENTIFIER»Delegate.h</string>
        <string>«PROJECTNAMEASIDENTIFIER»Delegate.m</string>
        <string>«PROJECTNAMEASIDENTIFIER»Template.html</string>
        <string>Info.plist</string>
    </array>
    <key>FilesToRename</key>
    <dict>
        <key>___PROJECTNAMEASIDENTIFIER___.icns</key>
        <string>«PROJECTNAMEASIDENTIFIER».icns</string>
        <key>___PROJECTNAMEASIDENTIFIER___Delegate.h</key>
        <string>«PROJECTNAMEASIDENTIFIER»Delegate.h</string>
        <key>___PROJECTNAMEASIDENTIFIER___Delegate.m</key>
        <string>«PROJECTNAMEASIDENTIFIER»Delegate.m</string>
        <key>___PROJECTNAMEASIDENTIFIER___Template.html</key>
        <string>«PROJECTNAMEASIDENTIFIER»Template.html</string>
        <key>___PROJECTNAMEASIDENTIFIER____Prefix.pch</key>
        <string>«PROJECTNAMEASIDENTIFIER»_Prefix.pch</string>
        <key>___PROJECTNAME___.xcodeproj</key>
        <string>«PROJECTNAME».xcodeproj</string>
    </dict>
</dict>
</plist>
+4  A: 

You likely want to use a "FilesToRename" section. The following is from the PyObjC Cocoa Document Based Application template. It works fine.

    <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
<plist version="1.0">
<dict>
        <key>Description</key>
        <string>This project builds a Cocoa-based application written in Python that uses the NSDocument architecture.</string>
        <key>FilesToMacroExpand</key>
        <array>
                <string>«PROJECTNAME»_Prefix.pch</string>
                <string>Info.plist</string>
                <string>English.lproj/InfoPlist.strings</string>
                <string>English.lproj/MainMenu.xib</string>
                <string>English.lproj/«PROJECTNAMEASIDENTIFIER»Document.xib</string>
                <string>main.py</string>
                <string>«PROJECTNAMEASIDENTIFIER»Document.py</string>
                <string>main.m</string>
        </array>
        <key>FilesToRename</key>
        <dict>
                <key>CocoaAppDocument.py</key>
                <string>«PROJECTNAMEASIDENTIFIER»Document.py</string>
                <key>CocoaDocApp_Prefix.pch</key>
                <string>«PROJECTNAMEASIDENTIFIER»_Prefix.pch</string>
                <key>English.lproj/CocoaAppDocument.xib</key>
                <string>English.lproj/«PROJECTNAMEASIDENTIFIER»Document.xib</string>
        </dict>
</dict>
</plist>
bbum
My files seem to be getting renamed automatically; I think it's the contents inside that are not being handled.
danwood
A: 

Went to write my answer, then saw that bbum posted everything I was going to say :)

A: 

First thoughts: have you tried using Apple's "Property List Editor" to edit your plist(s)???

/Developer/Applications/Utilities/Property\ List\ Editor.app

That should make sure that you save the plist files in the correct format.

Choice of file encoding matters. Plist files typically have an encoding of UTF-8. If you save as ASCII, the double-angle quotes will not be encoded correctly.

I, personally, have only ever gone as far as defining __MyCompanyName__ inside the Xcode plist in ~/Library/Preferences

What I write below is not from personal experience, but rather from a book on my desk:

Tips:

TemplateInfo.plist should have 3 properties:

  • Description
  • FilesToRename
  • FilesToMacroExpand

FilesToRename is a dictionary of key/value pairs. Each pair contains the name of the original file in the project and the name it should be renamed to.

FilesToMacroExpand: the names in the list are the files in the new project, not the template, so if you are renaming files, use the name the file was changed to (this itself will involve template macros).

Choice of file encoding matters. Plist files typically have an encoding of UTF-8. If you save as ASCII, the double-angle quotes will not be encoded correctly.

Look at the system console log. Some problems during template processing/loading are logged there.

Study the Xcode templates that come pre-installed.

Also worth mentioning:


The FilesToRename property renames files in the project folder. It does not alter or fix any of the project references to the files. To do that, you have to manually insert template macros into the project.pbxproj file.

que que
+3  A: 

Another resource is Jesse Grosjean's XcodeTemplateFactory. It's free and open source and may save you future headaches.

rentzsch
+2  A: 

There are two styles of templates, distinguished by the template macro delimiters: old-style uses MacRoman guillamots in a UTF-8 file, and the new style uses triple underbars throughout. You can't mix and match. The new style is for 3.1 and later only, and you must use the triple underbars in the file names to be substituted as well.

cdespinosa
+1  A: 

Further to Chris' answer ("There are two styles of templates..."), you can find examples of the new style in the templates for another platform...

The following excerpt shows examples of a few typical substitution variables using triple underbars; if you use these in place of the guillamot-based variables in your Foo___BarDelegate.m, it should work.

//
//  ___PROJECTNAMEASIDENTIFIER___AppDelegate.m
//  ___PROJECTNAME___
//
//  Created by ___FULLUSERNAME___ on ___DATE___.
//  Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
//

#import "___PROJECTNAMEASIDENTIFIER___AppDelegate.h"

@implementation ___PROJECTNAMEASIDENTIFIER___AppDelegate
mmalc
+1  A: 

Chris E. gave me the answer over twitter

http://twitter.com/cdespinosa/statuses/950259607

It worked!

danwood
That's the same answer as he gave here (and I elaborated on in my answer)...
mmalc
A: 

why are you missing those "<<" like symbols ? thats the reason why xcode is not recognizing and replacing template tags..

Puneet Madaan
A: 

I was just bangin my head on same problem!

For me, adding files in plist works, I changed html file with php file and it is parsed. But now it does parse only few first items from list. Old html file is still: «PROJECTNAME» Like this program does not count how many items there is in a list...

But where is the place in code, where it doesn't do that... ?

theAS3guru