PageRenderTime 79ms CodeModel.GetById 32ms app.highlight 43ms RepoModel.GetById 2ms app.codeStats 0ms

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

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