Permalink
Browse files

Implemented documentation set Info.plist generation.

  • Loading branch information...
1 parent b78cb9b commit 3434f62745b4b33c1403860199da26fed5e1b66e @tomaz committed Nov 29, 2010
@@ -16,6 +16,8 @@ - (NSString *)relativePathPrefixFromObject:(GBModelBase *)source toObject:(GBMod
- (NSString *)htmlReferenceForObjectFromIndex:(GBModelBase *)object;
- (NSString *)htmlReferenceForTopLevelObject:(GBModelBase *)object fromTopLevelObject:(GBModelBase *)source;
- (NSString *)htmlReferenceForMember:(GBModelBase *)member prefixedWith:(NSString *)prefix;
+@property (readonly) NSDateFormatter *yearDateFormatter;
+@property (readonly) NSDateFormatter *yearToDayDateFormatter;
@end
@@ -34,6 +36,19 @@ - (id)init {
if (self) {
self.projectName = @"PROJECT";
self.projectCompany = @"COMPANY";
+ self.docsetBundleIdentifier = @"com.company.project";
+ self.docsetBundleName = @"$PROJECT Documentation";
+ self.docsetCertificateIssuer = @"";
+ self.docsetCertificateSigner = @"";
+ self.docsetDescription = @"";
+ self.docsetFallbackURL = @"";
+ self.docsetFeedName = @"";
+ self.docsetFeedURL = @"";
+ self.docsetMinimumXcodeVersion = @"3.0";
+ self.docsetPlatformFamily = @"macosx";
+ self.docsetPublisherIdentifier = @"com.company.documentation";
+ self.docsetPublisherName = @"COMPANY";
+ self.docsetCopyrightMessage = @"© $YEAR $COMPANY. All rights reserved.";
self.outputPath = @"~/Downloads/examples/AppledocHtml";
self.templatesPath = @"~/Dropbox/Xcode/Projects/Tools/appledoc/Project/Templates";
self.ignoredPaths = [NSMutableSet set];
@@ -122,6 +137,34 @@ - (NSString *)htmlExtension {
return @"html";
}
+#pragma mark Date and time helpers
+
+- (NSString *)yearStringFromDate:(NSDate *)date {
+ return [self.yearDateFormatter stringFromDate:date];
+}
+
+- (NSString *)yearToDayStringFromDate:(NSDate *)date {
+ return [self.yearToDayDateFormatter stringFromDate:date];
+}
+
+- (NSDateFormatter *)yearDateFormatter {
+ static NSDateFormatter *result = nil;
+ if (!result) {
+ result = [[NSDateFormatter alloc] init];
+ [result setDateFormat:@"yyyy"];
+ }
+ return result;
+}
+
+- (NSDateFormatter *)yearToDayDateFormatter {
+ static NSDateFormatter *result = nil;
+ if (!result) {
+ result = [[NSDateFormatter alloc] init];
+ [result setDateFormat:@"yyyy-MM-dd"];
+ }
+ return result;
+}
+
#pragma mark Paths helper methods
- (NSString *)outputPathForObject:(id)object withExtension:(NSString *)extension {
@@ -19,7 +19,7 @@
@protocol GBApplicationSettingsProviding
///---------------------------------------------------------------------------------------
-/// @name Common values handling
+/// @name Project values handling
///---------------------------------------------------------------------------------------
/** Human readable name of the project. */
@@ -28,6 +28,59 @@
/** Human readable name of the project company. */
@property (copy) NSString *projectCompany;
+///---------------------------------------------------------------------------------------
+/// @name Documentation set handling
+///---------------------------------------------------------------------------------------
+
+/** Documentation set bundle identifier. */
+@property (copy) NSString *docsetBundleIdentifier;
+
+/** Documentation set bundle name. */
+@property (copy) NSString *docsetBundleName;
+
+/** Documentation set certificate issuer. */
+@property (copy) NSString *docsetCertificateIssuer;
+
+/** Documentation set certificate signer. */
+@property (copy) NSString *docsetCertificateSigner;
+
+/** Documentation set description. */
+@property (copy) NSString *docsetDescription;
+
+/** Documentation set fallback URL. */
+@property (copy) NSString *docsetFallbackURL;
+
+/** Documentation set feed name. */
+@property (copy) NSString *docsetFeedName;
+
+/** Documentation set feed URL. */
+@property (copy) NSString *docsetFeedURL;
+
+/** Documentation set minimum Xcode version. */
+@property (copy) NSString *docsetMinimumXcodeVersion;
+
+/** Documentation set platform family. */
+@property (copy) NSString *docsetPlatformFamily;
+
+/** Documentation set publisher identifier. */
+@property (copy) NSString *docsetPublisherIdentifier;
+
+/** Documentation set publisher name. */
+@property (copy) NSString *docsetPublisherName;
+
+/** Documentation set human readble copyright message. */
+@property (copy) NSString *docsetCopyrightMessage;
+
+///---------------------------------------------------------------------------------------
+/// @name Date and time handling
+///---------------------------------------------------------------------------------------
+
+/** Returns string representing the year of the given date. */
+- (NSString *)yearStringFromDate:(NSDate *)date;
+
+/** Returns string representing year-month-day of the given date. */
+- (NSString *)yearToDayStringFromDate:(NSDate *)date;
+
///---------------------------------------------------------------------------------------
/// @name Paths handling
///---------------------------------------------------------------------------------------
View
@@ -0,0 +1,24 @@
+//
+// NSError+GBError.h
+// appledoc
+//
+// Created by Tomaz Kragelj on 29.11.10.
+// Copyright 2010 Gentle Bytes. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/** Adds helper methods to `NSError` for more organized code.
+ */
+@interface NSError (GBError)
+
+/** Creates a new `NSError` with appledoc domain and given information.
+
+ @param code Error code.
+ @param description Error localized description.
+ @param reason Error localized failure reason.
+ @return Returns autoreleased `NSError` with the given data.
+ */
++ (NSError *)errorWithCode:(NSInteger)code description:(NSString *)description reason:(NSString *)reason;
+
+@end
View
@@ -0,0 +1,23 @@
+//
+// NSError+GBError.m
+// appledoc
+//
+// Created by Tomaz Kragelj on 29.11.10.
+// Copyright 2010 Gentle Bytes. All rights reserved.
+//
+
+#import "NSError+GBError.h"
+
+@implementation NSError (GBError)
+
++ (NSError *)errorWithCode:(NSInteger)code description:(NSString *)description reason:(NSString *)reason {
+ NSMutableDictionary *info = nil;
+ if ([description length] > 0 || [reason length] > 0) {
+ info = [NSMutableDictionary dictionaryWithCapacity:2];
+ if ([description length] > 0) [info setObject:description forKey:NSLocalizedDescriptionKey];
+ if ([reason length] > 0) [info setObject:reason forKey:NSLocalizedFailureReasonErrorKey];
+ }
+ return [self errorWithDomain:@"appledoc" code:code userInfo:info];
+}
+
+@end
@@ -6,11 +6,15 @@
// Copyright 2010 Gentle Bytes. All rights reserved.
//
+#import "GBApplicationSettingsProvider.h"
+#import "GBTemplateHandler.h"
#import "GBDocSetOutputGenerator.h"
@interface GBDocSetOutputGenerator ()
- (BOOL)moveSourceFilesToDocuments:(NSError **)error;
+- (BOOL)processInfoPlist:(NSError **)error;
+- (NSString *)replacePlaceholdersInString:(NSString *)string;
@end
@@ -24,39 +28,78 @@ - (BOOL)generateOutputWithStore:(id<GBStoreProviding>)store error:(NSError **)er
NSParameterAssert(self.previousGenerator != nil);
if (![super generateOutputWithStore:store error:error]) return NO;
if (![self moveSourceFilesToDocuments:error]) return NO;
+ if (![self processInfoPlist:error]) return NO;
return YES;
}
- (BOOL)moveSourceFilesToDocuments:(NSError **)error {
- // Prepare all paths. Note that we determine the exact subdirectory by searching for documents-template and using it's subdirectory as the guide.
- NSString *sourceFilesPath = [self.previousGenerator.outputUserPath stringByStandardizingPath];
- NSString *documentsPath = nil;
- for (NSString *template in [self.templateFiles allKeys]) {
- if ([template hasSuffix:@"documents-template"]) {
- documentsPath = [template stringByDeletingLastPathComponent];
- break;
- }
- }
+ GBLogInfo(@"Moving HTML files to DocSet bundle...");
- // If documents template wasn't found, exit.
+ // Prepare all paths. Note that we determine the exact subdirectory by searching for documents-template and using it's subdirectory as the guide. If documents template wasn't found, exit.
+ NSString *sourceFilesPath = [self.previousGenerator.outputUserPath stringByStandardizingPath];
+ NSString *documentsPath = [self templateFileKeyEndingWith:@"documents-template"];
if (!documentsPath) {
- if (error) {
- NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
- @"Documents template is missing!", NSLocalizedDescriptionKey,
- @"documents-template file is required to determine location for Documents path in DocSet bundle!", NSLocalizedFailureReasonErrorKey, nil];
- *error = [NSError errorWithDomain:@"appledoc" code:1 userInfo:info];
- }
+ if (error) *error = [NSError errorWithCode:1 description:@"Documents template is missing!" reason:@"documents-template file is required to determine location for Documents path in DocSet bundle!"];
GBLogWarn(@"Failed finding documents-template in '%@'!", self.templateUserPath);
return NO;
}
// First step is to move all files generated by previous generator as the Documents subfolder of docset structure.
+ documentsPath = [documentsPath stringByDeletingLastPathComponent];
NSString *destPath = [self.outputUserPath stringByAppendingPathComponent:documentsPath];
NSString *movePath = [destPath stringByAppendingPathComponent:@"Documents"];
if (![self.fileManager moveItemAtPath:sourceFilesPath toPath:[movePath stringByStandardizingPath] error:error]) {
GBLogWarn(@"Failed moving files from '%@' to '%@'!", self.previousGenerator.outputUserPath, movePath);
return NO;
}
+ return YES;
+}
+
+- (BOOL)processInfoPlist:(NSError **)error {
+ GBLogInfo(@"Writting DocSet Info.plist...");
+ NSString *templatePath = [self templateFileKeyEndingWith:@"info-template.plist"];
+ if (!templatePath) {
+ if (error) *error = [NSError errorWithCode:2 description:@"Info.plist template is missing!" reason:@"info-template.plist file is required to specify information about DocSet!"];
+ GBLogWarn(@"Failed finding info-template.plist in '%@'!", self.templateUserPath);
+ return NO;
+ }
+
+ // Prepare template variables and replace all placeholders with actual values.
+ NSMutableDictionary *vars = [NSMutableDictionary dictionaryWithCapacity:20];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetBundleIdentifier] forKey:@"bundleIdentifier"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetBundleName] forKey:@"bundleName"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetCertificateIssuer] forKey:@"certificateIssuer"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetCertificateSigner] forKey:@"certificateSigner"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetDescription] forKey:@"description"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetFallbackURL] forKey:@"fallbackURL"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetFeedName] forKey:@"feedName"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetFeedURL] forKey:@"feedURL"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetMinimumXcodeVersion] forKey:@"minimumXcodeVersion"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetPlatformFamily] forKey:@"platformFamily"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetPublisherIdentifier] forKey:@"publisherIdentifier"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetPublisherName] forKey:@"publisherName"];
+ [vars setObject:[self replacePlaceholdersInString:self.settings.docsetCopyrightMessage] forKey:@"copyrightMessage"];
+
+ // Run the template and save the results as Info.plist.
+ GBTemplateHandler *handler = [self.templateFiles objectForKey:templatePath];
+ NSString *output = [handler renderObject:vars];
+ NSString *path = [[templatePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"Info.plist"];
+ NSString *filename = [self.outputUserPath stringByAppendingPathComponent:path];
+ if (![self writeString:output toFile:[filename stringByStandardizingPath] error:error]) {
+ GBLogWarn(@"Failed writting Info.plist to '%@'!", filename);
+ return NO;
+ }
+ return YES;
+}
+
+#pragma mark Helper methods
+
+- (NSString *)replacePlaceholdersInString:(NSString *)string {
+ string = [string stringByReplacingOccurrencesOfString:@"$PROJECT" withString:self.settings.projectName];
+ string = [string stringByReplacingOccurrencesOfString:@"$COMPANY" withString:self.settings.projectCompany];
+ string = [string stringByReplacingOccurrencesOfString:@"$YEAR" withString:[self.settings yearStringFromDate:[NSDate date]]];
+ string = [string stringByReplacingOccurrencesOfString:@"$UPDATEDATE" withString:[self.settings yearToDayStringFromDate:[NSDate date]]];
+ return string;
}
#pragma mark Overriden methods
View
@@ -65,15 +65,16 @@ - (void)runGeneratorStepsWithStore:(id<GBStoreProviding>)store {
__block GBOutputGenerator *previous = nil;
[self.outputGenerators enumerateObjectsUsingBlock:^(GBOutputGenerator *generator, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
- GBLogVerbose(@"Step %ld/%ld: Running %@...", idx, stepsCount, [generator className]);
+ NSUInteger index = idx + 1;
+ GBLogVerbose(@"Step %ld/%ld: Running %@...", index, stepsCount, [generator className]);
generator.previousGenerator = previous;
if (![generator copyTemplateFilesToOutputPath:&error]) {
- GBLogNSError(error, @"Step %ld/%ld failed: %@ failed copying template files to output, aborting!", idx, stepsCount, [generator className]);
+ GBLogNSError(error, @"Step %ld/%ld failed: %@ failed copying template files to output, aborting!", index, stepsCount, [generator className]);
*stop = YES;
return;
}
if (![generator generateOutputWithStore:store error:&error]) {
- GBLogNSError(error, @"Step %ld/%ld failed: %@ failed generaing output, aborting!", idx, stepsCount, [generator className]);
+ GBLogNSError(error, @"Step %ld/%ld failed: %@ failed generaing output, aborting!", index, stepsCount, [generator className]);
*stop = YES;
return;
}
@@ -20,8 +20,6 @@ @interface GBHTMLTemplateVariablesProvider ()
- (NSString *)hrefForObject:(id)object fromObject:(id)source;
- (NSDictionary *)arrayDescriptorForArray:(NSArray *)array;
- (void)addFooterVarsToDictionary:(NSMutableDictionary *)dict;
-@property (readonly) NSDateFormatter *yearDateFormatter;
-@property (readonly) NSDateFormatter *yearToDayDateFormatter;
@property (retain) id<GBApplicationSettingsProviding> settings;
@property (retain) id<GBStoreProviding> store;
@@ -171,26 +169,8 @@ - (NSDictionary *)arrayDescriptorForArray:(NSArray *)array {
- (void)addFooterVarsToDictionary:(NSMutableDictionary *)dict {
[dict setObject:self.settings.projectCompany forKey:@"copyrightHolder"];
- [dict setObject:[self.yearDateFormatter stringFromDate:[NSDate date]] forKey:@"copyrightDate"];
- [dict setObject:[self.yearToDayDateFormatter stringFromDate:[NSDate date]] forKey:@"lastUpdatedDate"];
-}
-
-- (NSDateFormatter *)yearDateFormatter {
- static NSDateFormatter *result = nil;
- if (!result) {
- result = [[NSDateFormatter alloc] init];
- [result setDateFormat:@"yyyy"];
- }
- return result;
-}
-
-- (NSDateFormatter *)yearToDayDateFormatter {
- static NSDateFormatter *result = nil;
- if (!result) {
- result = [[NSDateFormatter alloc] init];
- [result setDateFormat:@"yyyy-MM-dd"];
- }
- return result;
+ [dict setObject:[self.settings yearStringFromDate:[NSDate date]] forKey:@"copyrightDate"];
+ [dict setObject:[self.settings yearToDayStringFromDate:[NSDate date]] forKey:@"lastUpdatedDate"];
}
#pragma mark Properties
@@ -86,13 +86,24 @@
/// @name Subclass parameters and helpers
///---------------------------------------------------------------------------------------
+/** Searches `templateFiles` dictionary for a key ending with the given suffix and returns the whole key if found.
+
+ If the key is not found, `nil` is returned. This method is useful for finding keys for which we only know partial name (ussually the name of the file, but not the path to it).
+
+ @param suffix Template file suffix to search for.
+ @return Returns full key if found, `nil` otherwise.
+ @see templateFiles
+ */
+- (NSString *)templateFileKeyEndingWith:(NSString *)suffix;
+
/** The dictionary of all template files detected within `copyTemplateFilesToOutputPath:`.
Each object has a key of template file name and relative path from `templateUserPath`. The keys are mapped to `GBTemplateHandler` instances associated with the template.
This is intended to be used within subclasses only. Dictionary contents are automatically updated and should not be changed by subclasses.
@see copyTemplateFilesToOutputPath:
+ @see templateFileKeyEndingWith:
*/
@property (readonly) NSMutableDictionary *templateFiles;
@@ -125,6 +125,13 @@ - (BOOL)isPathRepresentingIgnoredFile:(NSString *)path {
#pragma mark Helper methods
+- (NSString *)templateFileKeyEndingWith:(NSString *)suffix {
+ for (NSString *template in [self.templateFiles allKeys]) {
+ if ([template hasSuffix:suffix]) return template;
+ }
+ return nil;
+}
+
- (BOOL)writeString:(NSString *)string toFile:(NSString *)path error:(NSError **)error {
NSString *standardized = [path stringByStandardizingPath];
NSString *directory = [standardized stringByDeletingLastPathComponent];
@@ -11,7 +11,7 @@
DocSetFeedName = "{{feedName}}";
DocSetFeedURL = "{{feedURL}}";
"DocSetMinimumXcodeVersion" = "{{minimumXcodeVersion}}";
- DocSetPlatformFamily = macosx;
+ DocSetPlatformFamily = "{{platformFamily}}";
"DocSetPublisherIdentifier" = "{{publisherIdentifier}}";
DocSetPublisherName = "{{publisherName}}";
"NSHumanReadableCopyright" = "{{copyrightMessage}}";
Oops, something went wrong.

0 comments on commit 3434f62

Please sign in to comment.