/core/externals/update-engine/Samples/EngineRunner/main.m

http://macfuse.googlecode.com/ · Objective C · 251 lines · 65 code · 27 blank · 159 comment · 8 complexity · 552aefec270e7a405f775afde6f1a177 MD5 · raw file

  1. // Copyright 2008 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /*
  15. Welcome to EngineRunner, an Update Engine command-line tool that lets
  16. you create and edit tickets and also run updates. You can poke around
  17. the code to see one way of using Update Engine, or you can just use it
  18. as a tool for manipulating ticket stores and updating software.
  19. The comments assume that you're familiar with Update Engine's moving
  20. pieces, especially tickets and existence checkers.
  21. _How to use EngineRunner_
  22. EngineRunner, when run without arguments, will give you a list of commands
  23. that it supports:
  24. $ EngineRunner
  25. EngineRunner supports these commands:
  26. add : Add a new ticket to a ticket store
  27. change : Change attributes of a ticket
  28. delete : Delete a ticket from the store
  29. dryrun : See if an update is needed, but don't install it
  30. dryrunticket : See available updates in a ticket store but don't
  31. install any
  32. list : Lists all of the tickets in a ticket store
  33. run : Update a single product
  34. runticket : Update all of the products in a ticket store
  35. Run 'EngineRunner commandName -help' for help on a particular command
  36. Supply the command name, and "-help", to get information about a particular
  37. command:
  38. $ EngineRunner change -help
  39. change : Change attributes of a ticket
  40. Required arguments:
  41. -productid : Product ID to change
  42. -store : Path to the ticket store
  43. Optional arguments:
  44. -url : New server URL
  45. -version : New product version
  46. -xcpath : New existence checker path
  47. To run an update, use 'run':
  48. $ EngineRunner run
  49. -productid com.greeble.hoover
  50. -version 1.2
  51. -url http://example.com/updateInfo
  52. finished update of com.greeble.hoover: Success
  53. To see if an an update would happen, use 'dryrun':
  54. $ EngineRunner dryrun
  55. -productid com.greeble.hoover
  56. -version 1.2
  57. -url http://example.com/updateInfo
  58. Products that would update:
  59. com.greeble.hoover
  60. If you have several products you're managing, you might want to use
  61. a ticket store to consolidate all of the update information in one place.
  62. To add a ticket to a store, use the add command (all on one line):
  63. $ EngineRunner add
  64. -store /tmp/store.tix
  65. -productid com.greeble.hoover
  66. -version 1.2
  67. -url http://example.com/updateInfo
  68. -xcpath /Applications/Greebleator.app
  69. To see what tickets you have in the store, use the list command:
  70. $ EngineRunner list -store /tmp/store.tix
  71. 1 tickets at /tmp/store.tix
  72. Ticket 0:
  73. com.greeble.hoover version 1.2
  74. exists? NO, with existence checker <KSPathExistenceChecker:0x317d60 path=/Applications/Greebleator.app>
  75. server URL http://example.com/updateInfo
  76. The "NO" after "exists?" is the actual return value of the existence checker.
  77. In this case, there is no /Applications/Greebleator.app.
  78. To see what products need an update (without actually running an update),
  79. use 'dryrunticket':
  80. $ EngineRunner dryrunticket -store /tmp/store.tix
  81. No products to update
  82. $ EngineRunner dryrunticket -store /some/other/ticket/store.tix
  83. Products that would update:
  84. com.google.greeble
  85. com.google.bork
  86. To actually run an update, use 'runticket':
  87. $ EngineRunner runticket -store /some/other/ticket/store.tix
  88. finished update of com.google.greeble: Success
  89. finished update of com.google.bork: Success
  90. Or supply a productID to just update one product:
  91. $ EngineRunner runticket -store /some/other/ticket/store.tix \
  92. -productid com.google.bork
  93. finished update of com.google.bork: Success
  94. _Logging and Output_
  95. EngineRunner uses the GTMLogger ring buffer for controlling update
  96. engine output. GTMLogger calls are accumulated into a ring buffer and
  97. not displayed unless an error happens (where "error" is defined in
  98. something logging a message at the kGTMLoggerLevelError), in which
  99. case previously logged messages get dumped to
  100. ~/Library/Logs/EngineRunner.log. If no errors happen, nothing is
  101. logged.
  102. _EngineRunner Architecture_
  103. There are command classes for each of the actions that EngineRunner
  104. can perform. Each class provides its own documentation, its own set
  105. of required and optional arguments, and a run method. An
  106. ERCommandRunner will make sure required arguments are present and then
  107. run the approriate command. To add your own commands, subclass
  108. ERCommand and add it to the command runner.
  109. */
  110. #import <Foundation/Foundation.h>
  111. // GTM utility classes.
  112. #import "GTMLogger.h"
  113. #import "GTMLoggerRingBufferWriter.h"
  114. #import "GTMNSString+FindFolder.h"
  115. #import "GTMPath.h"
  116. // Command runner.
  117. #import "ERCommandRunner.h"
  118. // Command classes.
  119. #import "ERAddTicketCommand.h"
  120. #import "ERChangeTicketCommand.h"
  121. #import "ERDeleteTicketCommand.h"
  122. #import "ERDryRunCommand.h"
  123. #import "ERDryRunTicketCommand.h"
  124. #import "ERListTicketsCommand.h"
  125. #import "ERRunUpdateCommand.h"
  126. #import "ERRunUpdateTicketCommand.h"
  127. #import "ERSelfUpdateCommand.h"
  128. // Spool GTMLogger output (which is what Update Engine uses for its
  129. // chatter) to a ring buffer. If an error happens, dump the ring
  130. // buffer to ~/Library/Logs/EngineRunner.log.
  131. //
  132. static void SetupLoggerOutput(void);
  133. // And so it begins...
  134. //
  135. int main(int argc, const char *argv[]) {
  136. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  137. SetupLoggerOutput();
  138. ERCommandRunner *runner = [[[ERCommandRunner alloc] init] autorelease];
  139. // Don't want a partcular command in your EngineRunner? Just axe it
  140. // from here.
  141. [runner registerCommand:[ERListTicketsCommand command]];
  142. [runner registerCommand:[ERDeleteTicketCommand command]];
  143. [runner registerCommand:[ERChangeTicketCommand command]];
  144. [runner registerCommand:[ERAddTicketCommand command]];
  145. [runner registerCommand:[ERRunUpdateCommand command]];
  146. [runner registerCommand:[ERRunUpdateTicketCommand command]];
  147. [runner registerCommand:[ERDryRunCommand command]];
  148. [runner registerCommand:[ERDryRunTicketCommand command]];
  149. [runner registerCommand:[ERSelfUpdateCommand command]];
  150. // First see if the user neglected to give us any arguments, an obvious
  151. // cry for help.
  152. if (argc == 1) {
  153. [runner printUsage];
  154. return EXIT_SUCCESS;
  155. }
  156. NSString *commandName = [NSString stringWithUTF8String:argv[1]];
  157. // See if they've asked for help on a particular command.
  158. if (argc == 3) {
  159. if (strstr(argv[2], "-help") != NULL) {
  160. [runner printUsageForCommandName:commandName];
  161. return EXIT_SUCCESS;
  162. }
  163. }
  164. // Actually run the command.
  165. int result = [runner runCommandNamed:commandName];
  166. if (result == kERCommandNotFound) {
  167. [runner printUsage];
  168. return EXIT_FAILURE;
  169. }
  170. [pool release];
  171. return result;
  172. } // main
  173. static void SetupLoggerOutput(void) {
  174. // Keep the last 10,000 messages
  175. const int kLogBufferSize = 10000;
  176. // Build the ~/Library path, creating if necessary.
  177. NSString *library =
  178. [NSString gtm_stringWithPathForFolder:kDomainLibraryFolderType
  179. inDomain:kUserDomain
  180. doCreate:YES];
  181. // Make the Logs directory (if it's not there alraedy) and create
  182. // the EngineRunner.log file, both with appropriate permissions.
  183. GTMPath *log = [[[GTMPath pathWithFullPath:library]
  184. createDirectoryName:@"Logs" mode:0700]
  185. createFileName:@"EngineRunner.log" mode:0644];
  186. // Open the log file for appending.
  187. NSString *logPath = [log fullPath];
  188. NSFileHandle *logFile = [NSFileHandle fileHandleForLoggingAtPath:logPath
  189. mode:0644];
  190. // Make the ring buffer and have it use the |logFile| just created.
  191. GTMLoggerRingBufferWriter *rbw =
  192. [GTMLoggerRingBufferWriter ringBufferWriterWithCapacity:kLogBufferSize
  193. writer:logFile];
  194. // Now all default GTMLogger output will get spooled to the buffer.
  195. [[GTMLogger sharedLogger] setWriter:rbw];
  196. } // SetupLoggerOutput