ymdp 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/Rakefile +1 -0
  2. data/VERSION +1 -1
  3. data/lib/ymdp/application.rb +22 -0
  4. data/lib/ymdp/application_view.rb +312 -0
  5. data/lib/ymdp/base.rb +119 -0
  6. data/lib/ymdp/commands/build.rb +0 -6
  7. data/lib/ymdp/compiler/base.rb +12 -10
  8. data/lib/ymdp/compiler/domains.rb +8 -34
  9. data/lib/ymdp/compiler/template.rb +58 -85
  10. data/lib/ymdp/configuration/config.rb +70 -28
  11. data/lib/ymdp/configuration/constants.rb +17 -3
  12. data/lib/ymdp/processor/form_post.rb +5 -1
  13. data/lib/ymdp/support/file.rb +29 -11
  14. data/lib/ymdp/tasks/keys.rake +13 -13
  15. data/lib/ymdp/tasks/ymdp.rake +4 -4
  16. data/spec/application_spec.rb +29 -0
  17. data/spec/application_view_spec.rb +5 -0
  18. data/spec/compiler_spec.rb +3 -3
  19. data/spec/compiler_template_spec.rb +26 -54
  20. data/spec/data/app/views/layouts/application.html.haml +2 -0
  21. data/spec/data/config/config.yml +1 -0
  22. data/spec/data/config/constants.rb +3 -7
  23. data/spec/data/script/destroy +2 -2
  24. data/spec/data/script/langs +1 -3
  25. data/spec/default_settings.rb +42 -0
  26. data/spec/domains_spec.rb +3 -22
  27. data/spec/spec_helper.rb +3 -0
  28. data/spec/stubs.rb +11 -0
  29. data/spec/ymdp_base_spec.rb +125 -0
  30. data/test.rb +46 -0
  31. data/ymdp.gemspec +15 -65
  32. metadata +14 -64
  33. data/lib/new_application/.base +0 -11
  34. data/lib/new_application/Gemfile +0 -13
  35. data/lib/new_application/Rakefile +0 -3
  36. data/lib/new_application/app/.gitignore +0 -1
  37. data/lib/new_application/app/assets/images/lightbox/lightbox_bg.png +0 -0
  38. data/lib/new_application/app/assets/javascripts/OpenMailIntl.js +0 -291
  39. data/lib/new_application/app/assets/javascripts/controls.js +0 -965
  40. data/lib/new_application/app/assets/javascripts/date.js +0 -104
  41. data/lib/new_application/app/assets/javascripts/dragdrop.js +0 -974
  42. data/lib/new_application/app/assets/javascripts/effects.js +0 -1123
  43. data/lib/new_application/app/assets/javascripts/lowpro.js +0 -320
  44. data/lib/new_application/app/assets/javascripts/prototype.js +0 -4874
  45. data/lib/new_application/app/assets/javascripts/scriptaculous.js +0 -68
  46. data/lib/new_application/app/assets/yrb/en-US/application_en-US.pres +0 -7
  47. data/lib/new_application/app/helpers/application_helper.rb +0 -3
  48. data/lib/new_application/app/javascripts/application.js +0 -580
  49. data/lib/new_application/app/javascripts/debug.js +0 -138
  50. data/lib/new_application/app/javascripts/flash.js +0 -96
  51. data/lib/new_application/app/javascripts/header.js +0 -13
  52. data/lib/new_application/app/javascripts/help.js +0 -76
  53. data/lib/new_application/app/javascripts/i18n.js +0 -235
  54. data/lib/new_application/app/javascripts/launcher.js +0 -159
  55. data/lib/new_application/app/javascripts/logger.js +0 -61
  56. data/lib/new_application/app/javascripts/tag_helper.js +0 -178
  57. data/lib/new_application/app/stylesheets/application.css +0 -0
  58. data/lib/new_application/app/stylesheets/ie.css +0 -0
  59. data/lib/new_application/app/stylesheets/ie6.css +0 -0
  60. data/lib/new_application/app/stylesheets/ie7.css +0 -0
  61. data/lib/new_application/app/stylesheets/ie8.css +0 -0
  62. data/lib/new_application/app/stylesheets/lightbox.css +0 -30
  63. data/lib/new_application/app/stylesheets/non_ie.css +0 -0
  64. data/lib/new_application/app/views/layouts/application.html.haml +0 -35
  65. data/lib/new_application/app/views/shared/_error.html.haml +0 -8
  66. data/lib/new_application/app/views/shared/_flash.html.haml +0 -2
  67. data/lib/new_application/app/views/shared/_javascripts.html.haml +0 -22
  68. data/lib/new_application/app/views/shared/_loading.html.haml +0 -13
  69. data/lib/new_application/app/views/shared/_stylesheets.html.haml +0 -23
  70. data/lib/new_application/config/categories.yml +0 -6
  71. data/lib/new_application/config/config.yml.example +0 -30
  72. data/lib/new_application/config/constants.rb +0 -54
  73. data/lib/new_application/config/servers.yml.example +0 -9
  74. data/lib/new_application/lib/init.rb +0 -13
  75. data/lib/new_application/lib/tasks/environment.rake +0 -4
  76. data/lib/new_application/lib/tasks/keys.rake +0 -3
  77. data/lib/new_application/lib/tasks/setup.rake +0 -13
  78. data/lib/new_application/lib/tasks/ymdp.rake +0 -4
  79. data/lib/new_application/script/build +0 -9
  80. data/lib/new_application/script/config +0 -13
  81. data/lib/new_application/script/destroy +0 -18
  82. data/lib/new_application/script/generate +0 -4
  83. data/lib/new_application/script/gitrm +0 -17
  84. data/lib/new_application/script/growl +0 -6
  85. data/lib/new_application/script/images +0 -48
  86. data/lib/new_application/script/jslint.js +0 -5072
  87. data/lib/new_application/script/langs +0 -31
  88. data/lib/new_application/script/translate +0 -5
  89. data/lib/new_application/script/ymdt +0 -1895
  90. data/lib/new_application/script/ymdt.old +0 -1890
  91. data/lib/new_application/script/yuicompressor-2.4.2.jar +0 -0
  92. data/lib/new_application/ymdp +0 -8
  93. data/lib/ymdp/processor/processor.rb +0 -132
  94. data/lib/ymdp/ymdp.rb +0 -208
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'lib/init'
4
-
5
- YMDP_ROOT = "."
6
-
7
- include YMDP::Base
8
-
9
- def keys(lang)
10
- path = "#{YMDP_ROOT}/servers/my/assets/yrb/keys_#{lang}.json"
11
- json = ""
12
- if File.exists?(path)
13
- File.open(path, "r") do |f|
14
- json = f.read
15
- end
16
- end
17
- <<-OUTPUT
18
- Organizes low priority messages -- newsletters, coupons, promotions, receipts, etc into folders, which prioritizes email from real people in your Inbox, and summarizes it all in a digest so you don't miss anything important.
19
- OUTPUT
20
- JSON.parse(json)
21
- end
22
-
23
- supported_languages.each do |lang|
24
- puts <<-OUTPUT
25
- <intl_strings intl="#{lang}">
26
- <name>#{keys(lang)["ORGANIZER"]}</name>
27
- <description>#{keys(lang)["DESCRIPTION"]}</description>
28
- </intl_strings>
29
-
30
- OUTPUT
31
- end
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- @view = ARGV[0]
4
-
5
- system "./script/generate keys #{@view}"
@@ -1,1895 +0,0 @@
1
- #!/usr/bin/env php
2
- <?php
3
-
4
-
5
-
6
-
7
- //YMDT::fixup helper
8
- //Replaces all asset URLs in a file with the current versions.
9
- class AssetURL_Fixer
10
- {
11
- function __construct($mapAssetURLsByPath)
12
- {
13
- $this->mapAssetURLsByPath = $mapAssetURLsByPath;
14
- $this->changedFilePaths = array();
15
-
16
- //horrible hack to reverse engineer the 'appid_version' part of
17
- //asset URL for use when run() can't find full URL.
18
- $this->urlPrefix = null;
19
- foreach($this->mapAssetURLsByPath as $path=>$url){
20
- $urlParts = explode('/', $url);
21
- $this->urlPrefix = '/om/assets/' . $urlParts[3] . '/';
22
- break;
23
- }
24
- }
25
-
26
- function run($filepath)
27
- {
28
- $contents = file_get_contents($filepath);
29
- verify($contents !== FALSE,
30
- "Couldn't read " . $filepath);
31
- echo 'Fixing up ' . $filepath . ":\n";
32
- //Asset part of URL terminates in whitespace, ', ", ), ?, or &
33
- $results = preg_replace_callback('|/om/assets/.+?_\d+?/([^\'\\s">\)&\?]+)|',
34
- array($this, 'callback'),
35
- $contents);
36
- verify($results !== NULL, "Couldn't do fixup of " . $filepath);
37
- if($results != $contents){
38
- verify(file_put_contents($filepath, $results) !== FALSE);
39
- $this->changedFilePaths[] = $filepath;
40
- }
41
- else
42
- echo "\t(nothing to do)\n";
43
- }
44
-
45
- function callback($matches)
46
- {
47
- $fileURL = $matches[0];
48
- $relativePath = $matches[1];
49
- $key = "assets/$relativePath";
50
-
51
- /// Until we're willing to restrict partners from using programatically-constructed
52
- /// asset URLs (like pingg does for colored dot icons), can't make whole-URL validation
53
- /// failures an error, just a warning. For these, we'll stick to just fixing up the URL
54
- /// prefix and hope that it's referencing a legal asset.
55
-
56
- if(array_key_exists($key, $this->mapAssetURLsByPath)){
57
- $replacement = $this->mapAssetURLsByPath[$key];
58
- }
59
- else if($this->urlPrefix){
60
- echo "\t*Warning* can't find correct URL for " . $fileURL . "\n" .
61
- "\t\tMight not be a legal asset, will work off URL prefix\n";
62
- verify(count($this->mapAssetURLsByPath),
63
- "\t\tCan't even do that, app has no assets.");
64
- $replacement = preg_replace('|/om/assets/.+?_.+?/|', $this->urlPrefix, $fileURL);
65
- // echo "prefix is " . $this->urlPrefix . ",fileURL $fileURL , replacement $replacement\n";
66
- }
67
- else{
68
- echo "\t*Warning* can't find correct URL for " . $fileURL . "\n" .
69
- "\tThis app has no assets!";
70
- $replacement = $fileURL;
71
- }
72
-
73
- if($replacement !== $fileURL){
74
- echo "\treplacing " . $fileURL . "\n";
75
- echo "\t---> $replacement \n";
76
- return $replacement;
77
- }
78
- return $fileURL;
79
- }
80
- }
81
-
82
-
83
-
84
- //File-system utility functions. Mostly for dealing with ymdt local app working
85
- //directories.
86
-
87
- class FileSys
88
- {
89
- const APPID_FNAME = '.appid';
90
-
91
- //just like realpath, but no backslashes, not even on Windows
92
- static function realpath($path)
93
- {
94
- return str_replace('\\', '/', realpath($path));
95
- }
96
-
97
- //$paths is an array of (possibly relative) paths / patterns.
98
- //Expand directories to their file paths.
99
- //Allows globs.
100
- //All paths will be absolute.
101
- //Ignores root readme.txt
102
- static function expandPaths($paths)
103
- {
104
- $more_paths = array();
105
- foreach($paths as $ndx => $path){
106
- if(!is_dir($path))
107
- continue;
108
- unset($paths[$ndx]);
109
- $expanded = glob(FileSys::realpath($path) . '/*', GLOB_MARK);
110
- if(!empty($expanded))
111
- $more_paths = array_merge($more_paths, $expanded);
112
- }
113
-
114
- if(empty($more_paths))
115
- return array_map(array('FileSys', 'realpath'), $paths);
116
-
117
- return self::expandPaths(array_merge($paths, $more_paths));
118
- }
119
-
120
- static function filterMetaFiles($paths, $basepath)
121
- {
122
- $newpaths = array();
123
- $metas = array($basepath.'/'.self::APPID_FNAME,
124
- $basepath.'/readme.txt');
125
-
126
- foreach($paths as $p){
127
- if(in_array($p, $metas))
128
- continue;
129
- if($p[0] == '.')
130
- continue;
131
- if($p[strlen($p)-1] == '~')
132
- continue; //emacs backup files
133
- $newpaths[] = $p;
134
- }
135
-
136
- return $newpaths;
137
- }
138
-
139
- static function filterNonTextPaths($paths)
140
- {
141
- $txt_extensions = array('htm', 'html', 'js', 'css', 'txt');
142
- $results = array();
143
- foreach($paths as $p){
144
- if(in_array(pathinfo($p, PATHINFO_EXTENSION), $txt_extensions))
145
- $results[] = $p;
146
- }
147
- return $results;
148
- }
149
-
150
- static function layout($appdir)
151
- {
152
- global $HELP_README;
153
-
154
- $subdirs = array($appdir.'/views', $appdir.'/assets');
155
- foreach($subdirs as $s){
156
- verify(file_exists($s) || self::mkdir($s));
157
- }
158
-
159
- $readme = $appdir.'/readme.txt';
160
- verify(file_put_contents($readme, $HELP_README),
161
- "Couldn't write $readme");
162
- }
163
-
164
- static function mkdir($path)
165
- {
166
- if(is_dir($path))
167
- return;
168
- return mkdir($path, 0755, true);
169
- }
170
-
171
- static function modTime($path)
172
- {
173
- $stat = stat($path);
174
- return $stat['mtime'];
175
- }
176
-
177
- static function nameFromConfFile($appdir)
178
- {
179
- $confFname = $appdir . '/config.xml';
180
- $xml = simplexml_load_file($confFname);
181
- verify(is_a($xml, 'SimpleXMLElement'),
182
- "Couldn't read XML conf from $confFname");
183
- return $xml->name;
184
- }
185
-
186
- //returns array(appid, basepath, subpath)
187
- //basepath is absolute path to app root, i.e. the dir that contains .appid
188
- //subpath is the path (file/dir/pattern) relative to basepath
189
- //filename is the filename (or terminating glob / null if dir)
190
- function parsePath($path)
191
- {
192
- $newpath = FileSys::realpath($path);
193
- if(!$newpath){
194
- $newpath = FileSys::realpath(dirname($path)) . '/' . basename($path);
195
- //really only support globs in filenames, no higher up the path
196
- verify($newpath, "unsupported glob in dirname $path ?");
197
- }
198
- $path = $newpath;
199
-
200
- //Keep on going up the path until we find the magic .appid file
201
- $base = $path;
202
- if(!is_dir($base))
203
- $base = dirname($base);
204
-
205
- while(true){
206
- $appid_path = $base . '/' . self::APPID_FNAME;
207
-
208
- if(file_exists($appid_path)){
209
- $appid = file_get_contents($appid_path);
210
- verify($appid != '', 'Empty .appid file?');
211
- $subpath = substr($path, strlen($base)+1);
212
-
213
- return array($appid, $base, $subpath);
214
- }
215
- if($base == '.' || $base == '/' || $base == '')
216
- break;
217
- $base = dirname($base);
218
- }
219
- verify(false, "Couldn't find .appid along $path");
220
- }
221
- };
222
-
223
-
224
-
225
- /* vim: set expandtab tabstop=4 shiftwidth=4: */
226
- // +----------------------------------------------------------------------+
227
- // | PHP Version 5 |
228
- // +----------------------------------------------------------------------+
229
- // | Copyright (c) 1997-2004 The PHP Group |
230
- // +----------------------------------------------------------------------+
231
- // | This source file is subject to version 3.0 of the PHP license, |
232
- // | that is bundled with this package in the file LICENSE, and is |
233
- // | available through the world-wide-web at the following url: |
234
- // | http://www.php.net/license/3_0.txt. |
235
- // | If you did not receive a copy of the PHP license and are unable to |
236
- // | obtain it through the world-wide-web, please send a note to |
237
- // | license@php.net so we can mail you a copy immediately. |
238
- // +----------------------------------------------------------------------+
239
- // | Author: Andrei Zmievski <andrei@php.net> |
240
- // +----------------------------------------------------------------------+
241
- //
242
- // $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $
243
-
244
-
245
- /**
246
- * Command-line options parsing class.
247
- *
248
- * @author Andrei Zmievski <andrei@php.net>
249
- *
250
- */
251
- class Console_Getopt {
252
- /**
253
- * Parses the command-line options.
254
- *
255
- * The first parameter to this function should be the list of command-line
256
- * arguments without the leading reference to the running program.
257
- *
258
- * The second parameter is a string of allowed short options. Each of the
259
- * option letters can be followed by a colon ':' to specify that the option
260
- * requires an argument, or a double colon '::' to specify that the option
261
- * takes an optional argument.
262
- *
263
- * The third argument is an optional array of allowed long options. The
264
- * leading '--' should not be included in the option name. Options that
265
- * require an argument should be followed by '=', and options that take an
266
- * option argument should be followed by '=='.
267
- *
268
- * The return value is an array of two elements: the list of parsed
269
- * options and the list of non-option command-line arguments. Each entry in
270
- * the list of parsed options is a pair of elements - the first one
271
- * specifies the option, and the second one specifies the option argument,
272
- * if there was one.
273
- *
274
- * Long and short options can be mixed.
275
- *
276
- * Most of the semantics of this function are based on GNU getopt_long().
277
- *
278
- * @param array $args an array of command-line arguments
279
- * @param string $short_options specifies the list of allowed short options
280
- * @param array $long_options specifies the list of allowed long options
281
- *
282
- * @return array two-element array containing the list of parsed options and
283
- * the non-option arguments
284
- *
285
- * @access public
286
- *
287
- */
288
- function getopt2($args, $short_options, $long_options = null)
289
- {
290
- return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
291
- }
292
-
293
- /**
294
- * This function expects $args to start with the script name (POSIX-style).
295
- * Preserved for backwards compatibility.
296
- * @see getopt2()
297
- */
298
- function getopt($args, $short_options, $long_options = null)
299
- {
300
- return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
301
- }
302
-
303
- /**
304
- * The actual implementation of the argument parsing code.
305
- */
306
- function doGetopt($version, $args, $short_options, $long_options = null)
307
- {
308
- // in case you pass directly readPHPArgv() as the first arg
309
- // if (PEAR::isError($args)) {
310
- // return $args;
311
- // }
312
- if (empty($args)) {
313
- return array(array(), array());
314
- }
315
- $opts = array();
316
- $non_opts = array();
317
-
318
- settype($args, 'array');
319
-
320
- if ($long_options) {
321
- sort($long_options);
322
- }
323
-
324
- /*
325
- * Preserve backwards compatibility with callers that relied on
326
- * erroneous POSIX fix.
327
- */
328
- if ($version < 2) {
329
- if (isset($args[0]{0}) && $args[0]{0} != '-') {
330
- array_shift($args);
331
- }
332
- }
333
-
334
- reset($args);
335
- while (list($i, $arg) = each($args)) {
336
-
337
- /* The special element '--' means explicit end of
338
- options. Treat the rest of the arguments as non-options
339
- and end the loop. */
340
- if ($arg == '--') {
341
- $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
342
- break;
343
- }
344
-
345
- if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
346
- $non_opts[] = $arg;
347
- // = array_merge($non_opts, array_slice($args, $i));
348
- // break;
349
- } elseif (strlen($arg) > 1 && $arg{1} == '-') {
350
- $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
351
- // if (PEAR::isError($error))
352
- // return $error;
353
- } elseif ($arg == '-') {
354
- // - is stdin
355
- $non_opts = array_merge($non_opts, array_slice($args, $i));
356
- break;
357
- } else {
358
- $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
359
- // if (PEAR::isError($error))
360
- // return $error;
361
- }
362
- }
363
-
364
- return array($opts, $non_opts);
365
- }
366
-
367
- /**
368
- * @access private
369
- *
370
- */
371
- function _parseShortOption($arg, $short_options, &$opts, &$args)
372
- {
373
- for ($i = 0; $i < strlen($arg); $i++) {
374
- $opt = $arg{$i};
375
- $opt_arg = null;
376
-
377
- /* Try to find the short option in the specifier string. */
378
- if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
379
- {
380
- return verify(false, "Console_Getopt: unrecognized option -- $opt");
381
- }
382
-
383
- if (strlen($spec) > 1 && $spec{1} == ':') {
384
- if (strlen($spec) > 2 && $spec{2} == ':') {
385
- if ($i + 1 < strlen($arg)) {
386
- /* Option takes an optional argument. Use the remainder of
387
- the arg string if there is anything left. */
388
- //$opts[] = array($opt, substr($arg, $i + 1));
389
- $opts[$opt] = substr($arg, $i + 1);
390
- break;
391
- }
392
- } else {
393
- /* Option requires an argument. Use the remainder of the arg
394
- string if there is anything left. */
395
- if ($i + 1 < strlen($arg)) {
396
- // $opts[] = array($opt, substr($arg, $i + 1));
397
- $opts[$opt] = substr($arg, $i + 1);
398
- break;
399
- } else if (list(, $opt_arg) = each($args)) {
400
- /* Else use the next argument. */;
401
- if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
402
- verify(false, "Console_Getopt: option requires an argument -- $opt");
403
- }
404
- } else {
405
- return verify(false, "Console_Getopt: option requires an argument -- $opt");
406
- }
407
- }
408
- }
409
-
410
- // $opts[] = array($opt, $opt_arg);
411
- $opts[$opt] = $opt_arg;
412
- }
413
- }
414
-
415
- /**
416
- * @access private
417
- *
418
- */
419
- function _isShortOpt($arg)
420
- {
421
- return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]);
422
- }
423
-
424
- /**
425
- * @access private
426
- *
427
- */
428
- function _isLongOpt($arg)
429
- {
430
- return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
431
- preg_match('/[a-zA-Z]+$/', substr($arg, 2));
432
- }
433
-
434
- /**
435
- * @access private
436
- *
437
- */
438
- function _parseLongOption($arg, $long_options, &$opts, &$args)
439
- {
440
- @list($opt, $opt_arg) = explode('=', $arg, 2);
441
- $opt_len = strlen($opt);
442
-
443
- for ($i = 0; $i < count($long_options); $i++) {
444
- $long_opt = $long_options[$i];
445
- $opt_start = substr($long_opt, 0, $opt_len);
446
- $long_opt_name = str_replace('=', '', $long_opt);
447
-
448
- /* Option doesn't match. Go on to the next one. */
449
- if ($long_opt_name != $opt) {
450
- continue;
451
- }
452
-
453
- $opt_rest = substr($long_opt, $opt_len);
454
-
455
- /* Check that the options uniquely matches one of the allowed
456
- options. */
457
- if ($i + 1 < count($long_options)) {
458
- $next_option_rest = substr($long_options[$i + 1], $opt_len);
459
- } else {
460
- $next_option_rest = '';
461
- }
462
- if ($opt_rest != '' && $opt{0} != '=' &&
463
- $i + 1 < count($long_options) &&
464
- $opt == substr($long_options[$i+1], 0, $opt_len) &&
465
- $next_option_rest != '' &&
466
- $next_option_rest{0} != '=') {
467
- return verify(false, "Console_Getopt: option --$opt is ambiguous");
468
- }
469
-
470
- if (substr($long_opt, -1) == '=') {
471
- if (substr($long_opt, -2) != '==') {
472
- /* Long option requires an argument.
473
- Take the next argument if one wasn't specified. */;
474
- if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
475
- return verify(false, "Console_Getopt: option --$opt requires an argument");
476
- }
477
- if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
478
- return verify(false, "Console_Getopt: option requires an argument --$opt");
479
- }
480
- }
481
- } else if ($opt_arg) {
482
- return verify(false, "Console_Getopt: option --$opt doesn't allow an argument");
483
- }
484
-
485
- $opts[] = array('--' . $opt, $opt_arg);
486
- return;
487
- }
488
-
489
- return verify(false, "Console_Getopt: unrecognized option --$opt");
490
- }
491
-
492
- /**
493
- * Safely read the $argv PHP array across different PHP configurations.
494
- * Will take care on register_globals and register_argc_argv ini directives
495
- *
496
- * @access public
497
- * @return mixed the $argv PHP array or PEAR error if not registered
498
- */
499
- function readPHPArgv()
500
- {
501
- global $argv;
502
- if (!is_array($argv)) {
503
- if (!@is_array($_SERVER['argv'])) {
504
- if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
505
- return verify(false,
506
- "Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
507
- }
508
- return $GLOBALS['HTTP_SERVER_VARS']['argv'];
509
- }
510
- return $_SERVER['argv'];
511
- }
512
- return $argv;
513
- }
514
-
515
- }
516
-
517
-
518
-
519
-
520
-
521
- $HELP_README = <<<EOT
522
- This dir contains files to make a Yahoo! Mail Application.
523
-
524
- Run ymdt to get an overview on how to exchange these files with a Yahoo!
525
- Mail development server.
526
-
527
- What's here to start with, for a minimal app?
528
-
529
- config.xml: app's config XML
530
-
531
- auth.xml: app's authentication XML
532
-
533
- readme.txt: this file, ignored by Yahoo! tools
534
-
535
- .appid: metadata for use by Yahoo! tools. Do not modify.
536
-
537
- views/: subdirectory where you may add view html files
538
-
539
- assets/: subdirectory where you may add non-view assets
540
- it may contain other subdirectories
541
-
542
- Portable Network Graphics files you could add at this directory's top-level:
543
-
544
- icon.png: a 16x16 pixel image for use as an icon
545
-
546
- thumbnail.png: a 64x64 pixel image for use in an app gallery
547
-
548
- full.png: a 300x250 pixel image for preview / help display purposes
549
-
550
- EOT;
551
-
552
- $HELP_USAGE = <<<EOT
553
- Usage:
554
-
555
- ymdt <command> [flags] [command arguments]
556
-
557
- Type 'ymdt help <command>' for help on a specific command.
558
-
559
- Available commands:
560
- apps lists all of the user's apps
561
- create creates a new app
562
- destroy delete the entire app
563
- del deletes one of an app's files
564
- dev develop-o-matic mode
565
- fixup rewrite app's views and text assets so that asset URLs are correct
566
- get get latest of an app's file(s) from dev server
567
- help get help on a specific command
568
- ls list all of an app's file(s) and their URLs
569
- publish publish an app
570
- put upload apps file(s) to dev server
571
- tester list, invite, or delete testers
572
- EOT;
573
-
574
- $HELP_COMMON_OPTIONS = <<<EOT
575
- Global Options:
576
-
577
- -h<host>
578
- Override default Yahoo! Mail developer hostname.
579
- (Default is YMDT_HOST environment variable or 'developer.mail.yahoo.com')
580
-
581
- -u<user>
582
- Specify user ID. If this option is omitted, the user ID is either
583
- figured from cookies or by prompting the user.
584
-
585
- After authentication, a token is normally cached in a cookie file in your
586
- home directory. It does not contain your password. This time-sensitive
587
- token will be reused on subsequent invocations to avoid logging on. Use
588
- the -d flag to avoid writing that file and force login on every invocation.
589
-
590
- -d
591
- Don't save auth token to file.
592
-
593
- -p<password>
594
- You're better off not using this option and letting the program offer you a
595
- masked prompt for password entry.
596
-
597
- -k
598
- Disables SSL host verification, use if the host you're connecting to is
599
- using self-signed SSL certs.
600
-
601
- EOT;
602
-
603
- $HELP_APPS = <<<EOT
604
- usage: apps
605
-
606
- Lists all of the logged-on user's apps.
607
-
608
- Each app is reported as a line beginning with the appid, followed by a tab and
609
- then the app name.
610
-
611
- EOT;
612
-
613
- $HELP_CREATE = <<<EOT
614
- usage: create <path>
615
-
616
- Create an app on the development server, with a local working copy kept
617
- in <path>.
618
-
619
- If <path> doesn't already contain an app, a minimal app will be created.
620
-
621
- If <path> already contains an app, a new app will be created based on
622
- the app files in <path>, and <path> will be converted to a valid working
623
- directory for the newly-created app.
624
-
625
- In either case, the app name will be set to '<path>', but you can modify it
626
- to be different from '<path>' by editing the app's config.xml.
627
-
628
- For a description of the files comprising an app, see <path>/readme.txt.
629
-
630
- Options:
631
- -A<pub_appid>:<priv_appid>
632
- -A<pub_appid>:
633
- -A:<priv_appid>
634
- Usually, the server allocates a globally-unique appid for both the public
635
- and private (development) versions of the app. This option allows admins
636
- to explicitly specify a public appid, private appid, or both. Fails if
637
- any of the specified appids already exist or if the logged-on user doesn't
638
- have admin rights. Note the magic ':', it must be there even if you're
639
- not specifying both appids.
640
-
641
- Examples:
642
- create a new app in directory ~/apps/llama:
643
- ymdt create ~/apps/llama
644
-
645
- create a new app in directory ~/apps/lindy with pub appid 123 and
646
- private appid 456:
647
- ymdt -A123:456 create ~/apps/lindy
648
-
649
- create a new app in directory ~/apps/lindy with autogenerated
650
- public appid and private appid 456:
651
- ymdt -A:456 create ~/apps/lindy
652
-
653
- create a new app in directory ~/apps/lindy with public appid 123 and
654
- an autogenerated private appid:
655
- ymdt -A123: create ~/apps/lindy
656
-
657
- EOT;
658
-
659
- $HELP_DEL = <<<EOT
660
- usage: del <path>
661
-
662
- Delete one of an app's files.
663
-
664
- <path> must be to a single file in an app's local working directory.
665
-
666
- Examples:
667
- delete asset 'lark.jpg' for app in directory ./birds:
668
- ymdt del ./birds/assets/lark.jpg
669
-
670
- EOT;
671
-
672
- $HELP_DEV = <<<EOT
673
- usage: dev <path>
674
-
675
- Enter dev-o-matic mode. <path> must be to the root of an app's local working
676
- directory. Will do a get of app, then continuously watch for local changes and
677
- update the server.
678
-
679
- EOT;
680
-
681
- $HELP_DESTROY = <<<EOT
682
- usage: destroy [<path>]
683
-
684
- Destroy an application. Must specify the path or the -a flag.
685
-
686
- -a<appid>
687
- <appid> is the application's private appid.
688
-
689
- -z
690
- Admin option. Really, really delete it from the development server.
691
-
692
- EOT;
693
-
694
- $HELP_FIXUP = <<<EOT
695
- usage: fixup <path>
696
-
697
- When your app is published, the in-development version of your app is copied to
698
- the public version of your app, which is visible to the world. The first time
699
- after publication that you upload (put) assets to the development server, the
700
- asset URLs change. Use this command to fixup up all of the asset URLs in your
701
- view HTML and your text assets.
702
-
703
- Recommended best practice: after your app is published (by an admin), run fixup,
704
- but backup your personal source first. (Your app is in source control, right?)
705
-
706
- Options:
707
- -z
708
- Suppress autoput. Normally, fixup executes these steps:
709
- 1) Uploads all of your app's files to the development server.
710
- 2) Fetches the latest asset URLs from the server.
711
- 3) Rewrites views and text type assets to use the latest asset URLs.
712
- 4) Uploads any files modified in step 3.
713
- Using the -z option suppresses steps 1 and 4. This is handy if you want
714
- to avoid step 1 when you know the assets have already been uploaded once
715
- since the last publish or if you want to manually review the results of 3
716
- before uploading files to the development server.
717
-
718
- -n
719
- Use the application name from the app's conf.xml to lookup the app's
720
- private appid on the server and modify the .appid file in your local
721
- working copy. See: put -n.
722
-
723
- -s
724
- Sync. Same as for put.
725
- EOT;
726
-
727
- $HELP_GET = <<<EOT
728
- usage: get <path>
729
-
730
- Get latest of an app's file(s) from dev server. Normally, <path> is to the root
731
- or some subpath of the app's local working copy. Wildcards (?*) allowed below
732
- app root, but only if <path> is quoted.
733
-
734
- Options:
735
- -a<appid>
736
- Get an app that exists on the server, but for which you don't yet have
737
- a working copy. In this case, <path> must be to an empty directory.
738
-
739
- -s
740
- Sync: Do the get, but also delete any local files below <path> that
741
- aren't present on the server.
742
-
743
- -y
744
- Autoyes: don't prompt user to confirm local deletes, use with care!
745
-
746
- Examples:
747
- get latest of all files for app 045fa65e3, using directory duck as the
748
- local working directory:
749
- ymdt -a045fa65e3 get duck
750
-
751
- get latest of all files for app in directory ./scrooge:
752
- ymdt get ./scrooge
753
-
754
- get latest of all assets for app in directory ./mcduck:
755
- ymdt get ./mcduck/assets
756
-
757
- get latest of config for app in directory ./ham:
758
- ymdt get ./ham/config.xml
759
-
760
- get latest of .js files in ./ham/assets
761
- ymdt get './ham/assets/*.js'
762
-
763
- EOT;
764
-
765
- $HELP_HELP = <<<EOT
766
- usage: help <command>
767
-
768
- Give help for a particular command.
769
-
770
- For general usage, run ymdt without any arguments.
771
-
772
- EOT;
773
-
774
- $HELP_LS = <<<EOT
775
- usage: ls <path>
776
-
777
- List server-side files and their URLs. Handy for figuring out how to reference
778
- your assets from views or other assets.
779
-
780
- <path> must minimally be an app's working directory, in which case all of the
781
- files comprising the app will be listed. <path> may also specify a particular
782
- subdir or file inside the app's working directory. Wildcards (*?) allowed below
783
- app's working directory root.
784
-
785
- Examples:
786
- list all assets for app in directory ~/apps/pigeon:
787
- ymdt ls ~/apps/pigeon/assets
788
-
789
- list all .jpg assets for app in directory ~/apps/zebra:
790
- ymdt ls '~/apps/zebra/assets/*.jpg'
791
- # note quotes to avoid shell expansion
792
-
793
- EOT;
794
-
795
- $HELP_PUBLISH = <<<EOT
796
- usage: publish [<path>]
797
-
798
- Update the publically-visible version of your app on the development server to
799
- be the same as the latest uploaded private (in-development) version of an app.
800
- <path> is the root of the private version's local working copy. It is only used
801
- to figure out the right appid. The public app update is peformed only using the
802
- private app files already uploaded to the server.
803
-
804
- Requires admin rights.
805
-
806
- You must use the -a option if you omit <path>.
807
-
808
- Options:
809
- -a<appid>
810
- Specify the private appid of the app you'd like to publish.
811
-
812
- -z
813
- Suppress asset URL validation.
814
-
815
- EOT;
816
-
817
- $HELP_PUT = <<<EOT
818
- usage: put <path>
819
-
820
- Upload files from local app working copy to the server. <path> is the root or
821
- some subpath of the app's local working copy. Wildcards (?*) allowed below app
822
- root, but only if <path> is quoted.
823
-
824
- Options:
825
- -a<appid>
826
- Explicitly specify the appid of the destination app on the server.
827
- Normally the .appid in the root directory of the app's local working
828
- copy determines what app is modified on the server. Since you may
829
- only modify the private (in-development) version of your app, <appid>
830
- must be a private appid. Changes .appid in your app's working dir
831
- as well.
832
-
833
- -n
834
- Use the application name from the app's conf.xml to lookup the app's
835
- private appid on the server and modify the .appid file in your local
836
- working copy. For situations where you created the local working copy
837
- by doing a get -a with a public appid or if you've done a get -h from
838
- a different server. Revises the .appid so that future puts will apply
839
- to the private app on the correct server.
840
-
841
- -s
842
- Sync: Do the put, but also delete any files on the server that aren't
843
- present in the local working copy.
844
-
845
- -y
846
- Autoyes: don't prompt user to confirm server deletes, use with care!
847
-
848
- Examples:
849
- upload all files for app in directory ./mcduck:
850
- ymdt put ./mcduck
851
-
852
- upload all assets for app in directory ./phish:
853
- ymdt put ./phish/assets
854
-
855
- upload latest of .js files in ./ham/assets
856
- ymdt put './ham/assets/*.js'
857
-
858
- EOT;
859
-
860
- $HELP_TESTER = <<<EOT
861
- usage: tester <ls|invite|del> [tester email address or yid]
862
-
863
- tester ls will display your tester list.
864
-
865
- invite <tester email address> will invite someone to be a tester.
866
-
867
- del <tester Yahoo! ID> will delete an existing tester.
868
-
869
- EOT;
870
-
871
- $HELP_UPGRADE = <<<EOT
872
- usage: upgrade
873
-
874
- Download the latest version of ymdt and replace the running script with it.
875
-
876
- EOT;
877
-
878
-
879
-
880
-
881
- //Functions for logging onto Bouncer and Yahoo!
882
- class Login
883
- {
884
- static function isWindows()
885
- {
886
- //better way to do this?
887
- if(getenv('HOME'))
888
- return false;
889
- return true;
890
- }
891
-
892
- static function getHomeDir()
893
- {
894
- $home = getenv('HOME');
895
- return $home ? $home : getenv('HOMEPATH'); //windows
896
- }
897
-
898
- static function promptUserInput($prompt = 'username:', $echo = true)
899
- {
900
- printf($prompt);
901
- $stty = '';
902
- if(!$echo){
903
- $stty = `stty -g`;
904
- system("stty -echo");
905
- }
906
- $input = trim(fgets(STDIN));
907
- if(!$echo)
908
- system("stty $stty");
909
-
910
- return $input;
911
- }
912
-
913
- static function promptCredentials($userPrompt, $passPrompt)
914
- {
915
- return array(self::promptUserInput($userPrompt),
916
- self::promptUserInput($passPrompt, false));
917
- }
918
-
919
- //on failure: returns false
920
- //on success: returns cookie string appropriate for curl_setopt(,CURLOPT_COOKIE,)
921
- static function authBouncer($bid, $password, $cookie_file_name, $use_guesthouse)
922
- {
923
- $url = "https://bouncer.by.corp.yahoo.com/login/";
924
- if($use_guesthouse)
925
- $url = "https://bouncer.gh.corp.yahoo.com/login/";
926
-
927
- $ch = curl_init();
928
- $timeout = 0;
929
-
930
- curl_setopt($ch, CURLOPT_POST, TRUE);
931
- curl_setopt($ch, CURLOPT_POSTFIELDS,
932
- array('action' => 'login',
933
- 'id' => $bid,
934
- 'pass_word' => $password));
935
-
936
- curl_setopt($ch, CURLOPT_URL, $url);
937
- curl_setopt($ch, CURLOPT_HEADER, TRUE);
938
- if($cookie_file_name){
939
- curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file_name);
940
- curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file_name);
941
- }
942
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
943
- curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
944
- if(self::isWindows()){
945
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
946
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
947
- }
948
-
949
- $result = curl_exec($ch);
950
- curl_close($ch);
951
- if($cookie_file_name)
952
- chmod($cookie_file_name, 0600);
953
- if($result === false || preg_match("/YCorp=/", $result) != 1){
954
- return false;
955
- }
956
-
957
- preg_match_all('|Set-Cookie: (.*);|U', $result, $matches);
958
- return implode(';', $matches[1]);
959
- // return true;
960
- }
961
-
962
- static function authYahoo($yid, $passwd, $cookie_file_name)
963
- {
964
- $agent = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US;'.
965
- 'rv:1.9.0.5) Gecko/2008120121 Firefox/3.0.5';
966
- $ch = curl_init();
967
- curl_setopt($ch, CURLOPT_USERAGENT, $agent);
968
- curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file_name);
969
- curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file_name);
970
- $postFields = "&login=$yid&passwd=$passwd";
971
- curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
972
- curl_setopt($ch, CURLOPT_URL, 'http://login.yahoo.com');
973
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
974
- $result = curl_exec($ch);
975
- curl_close($ch);
976
-
977
- return self::extractCookieString($cookie_file_name) != null;
978
- }
979
-
980
- static function extractCookieString($cookie_file_name)
981
- {
982
- if (!file_exists($cookie_file_name))
983
- return null;
984
- $file = fopen($cookie_file_name, 'r');
985
- if (!$file)
986
- return null;
987
-
988
- $regex = '/^\.yahoo\.com\tTRUE\t\/\tFALSE\t\d+\t(\w+)\t(.*)$/';
989
- while ($line = fgets($file)) {
990
- if (!preg_match($regex, $line, $matches))
991
- continue;
992
-
993
- $key = $matches[1];
994
- $val = $matches[2];
995
- $cookies[] = "$key=$val";
996
- }
997
- fclose($file);
998
- if(!count($cookies))
999
- return null;
1000
- $cstr = join('; ', $cookies);
1001
- return $cstr;
1002
- }
1003
-
1004
- static function extractBID_FromCookie($cookie_file_name)
1005
- {
1006
- if(!file_exists($cookie_file_name))
1007
- return null;
1008
-
1009
- static $regex = '/YBY\sid%3D[0-9]+%26userid%3D([^%]+)%26/';
1010
- $matches = array();
1011
- $contents = file_get_contents($cookie_file_name);
1012
- $count = preg_match($regex, $contents, $matches);
1013
- if($count != 1){
1014
- return null;
1015
- }
1016
- return $matches[1];
1017
- }
1018
-
1019
- }
1020
-
1021
-
1022
-
1023
- //Wraps calls to the development server.
1024
- class WebServiceClient
1025
- {
1026
- function __construct($hostname, $cookieFname, $lamessl, $uname, $passwd)
1027
- {
1028
-
1029
- $this->hostname = $hostname ? $hostname : ( getenv('YMDT_HOST') ? getenv('YMDT_HOST') : 'developer.mail.yahoo.com');
1030
- echo "Developer server: " . $this->hostname . "\n";
1031
- $this->cookieFname = $cookieFname;
1032
- $this->lamessl = $lamessl;
1033
- $this->uname = $uname;
1034
- $this->passwd = $passwd;
1035
- $this->wssid = null;
1036
- }
1037
-
1038
- function call($op, &$msg, $fields = array(), $format = 'json',
1039
- $checkStatus = true, $needLogin = true)
1040
- {
1041
- if(!$this->wssid && $needLogin)
1042
- $this->login();
1043
-
1044
- $url = 'https://' . $this->hostname;
1045
- if(strpos($op, 'admin.') !== false)
1046
- $url = 'http://' . $this->hostname . ':9999';
1047
-
1048
- $url .= '/om/api/1.0/openmail.' . $op;
1049
-
1050
- if($this->wssid){
1051
- $url .= '?bycrumb='.$this->wssid;
1052
- }
1053
-
1054
- $ch = curl_init();
1055
- $timeout = 0;
1056
- curl_setopt($ch, CURLOPT_POST, TRUE);
1057
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
1058
- curl_setopt($ch, CURLOPT_URL, $url);
1059
- curl_setopt($ch, CURLOPT_HEADER, TRUE);
1060
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1061
- curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1062
- if($this->cookieFname)
1063
- curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieFname);
1064
- else
1065
- curl_setopt($ch, CURLOPT_COOKIE, $this->cookies);
1066
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1067
- if($this->lamessl)
1068
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
1069
-
1070
- $result = curl_exec($ch);
1071
- if(curl_errno($ch)){
1072
- $msg = 'Curl failure: ' . curl_error($ch);
1073
- }
1074
-
1075
- $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1076
- $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1077
-
1078
- curl_close($ch);
1079
- if(file_exists($this->cookieFname))
1080
- chmod($this->cookieFname, 0600);
1081
-
1082
- $content = substr($result, $header_size);
1083
-
1084
- $rval = null;
1085
- if($format){
1086
- if($format == 'json')
1087
- $rval = json_decode($content);
1088
- elseif($format == 'xml')
1089
- $rval = simplexml_load_string(trim($content));
1090
- if(!get_class($rval) && !is_array($rval))
1091
- $rval = null;
1092
- }
1093
-
1094
- if($http_code != '200'){
1095
- $msg = "$op invoke failed (HTTP $http_code).";
1096
- if($rval && property_exists($rval, 'message'))
1097
- $msg .= "\nServer says: {$rval->message}";
1098
- verify(false, $msg);
1099
- }
1100
-
1101
- if(!$format)
1102
- return $content;
1103
-
1104
- verify($rval !== null,
1105
- "Unexpected webservice result from $op: \n$format:\n\t[$content]");
1106
-
1107
- //Would be nice if ws results were a little more standardized, a la JSON-RPC.
1108
- //But, they're not. . .
1109
- if($checkStatus && $rval->status != 200){
1110
- $msg = property_exists($rval, 'message') ? $rval->message : '';
1111
- $msg = $msg . " (status: {$rval->status})";
1112
- verify(false, $msg);
1113
- }
1114
-
1115
- return $rval;
1116
- }
1117
-
1118
- function getWSSID()
1119
- {
1120
- //This call, unlike all the others, returns in XML (since JSON is
1121
- //security no-no for wssid.)
1122
- $result = $this->call('dev.file.init', $msg, array(), 'xml', true,
1123
- false);
1124
-
1125
- verify($result && property_exists($result, 'wssid'),
1126
- 'unable to retrieve wssid');
1127
-
1128
- $this->wssid = $result->wssid;
1129
- if(property_exists($result, 'version') &&
1130
- YMDT_Version < $result->version){
1131
- $latest = $result->version;
1132
- echo "***You are running an outdated version of ymdt ".
1133
- "(latest is $latest, you have " . YMDT_Version . ".).\n".
1134
- "***Please run: ymdt upgrade\n\n";
1135
- }
1136
- }
1137
-
1138
- function login()
1139
- {
1140
- $uname = $this->uname;
1141
- $passwd = $this->passwd;
1142
-
1143
- $use_guesthouse = strpos($this->hostname, 'corp.yahoo.com') === false;
1144
-
1145
- //Username changed? Blow away cookie file.
1146
- $prevUsername = Login::extractBID_FromCookie($this->cookieFname);
1147
- if($uname && $prevUsername != $uname){
1148
- verify(!file_exists($this->cookieFname) ||
1149
- unlink($this->cookieFname),
1150
- "login fought {$this->cookieFname} and lost");
1151
- }
1152
-
1153
- //If we can't get a crumb, try logging into backyard to refresh cookie,
1154
- //then try getting crumb again.
1155
- try {
1156
- $this->getWSSID();
1157
- if($this->wssid)
1158
- return;
1159
- } catch (Exception $e) {}
1160
-
1161
- if(!$uname){
1162
- $prompt = 'Backyard ID: ';
1163
- if($use_guesthouse)
1164
- $prompt = 'Guesthouse ID: ';
1165
- list($uname, $passwd) = Login::promptCredentials($prompt,
1166
- 'Password: ');
1167
- }
1168
- elseif(!$passwd){
1169
- $passwd = Login::promptUserInput('Password:', false);
1170
- }
1171
-
1172
- $this->cookies = Login::authBouncer($uname, $passwd, $this->cookieFname, $use_guesthouse);
1173
- verify($this->cookies, 'login failed');
1174
- echo "\nlogin successful\n";
1175
- if($this->cookieFname){
1176
- echo "\nAn authentication token has been stored in " .
1177
- $this->cookieFname . "\nUntil its expiration,".
1178
- "it will be used by future ymdt invocations to avoid having to" .
1179
- " relogin.\nTo disable this behavior, use the -d option.\n\n";
1180
- }
1181
- $this->getWSSID();
1182
- }
1183
-
1184
- function appList()
1185
- {
1186
- $msg = null;
1187
- $fields = array('ignorePublicationStatus' => 'true');
1188
- verify(($result = $this->call('dev.app.list', $msg, $fields, 'json',
1189
- false)) !== null,
1190
- "No webservice result.");
1191
- return $result;
1192
- }
1193
-
1194
- function ls($appid, $subpath = null)
1195
- {
1196
- $fields = array('app' => $appid);
1197
- if($subpath){
1198
- $fields['path'] = $subpath;
1199
- }
1200
-
1201
- $result = $this->call('dev.file.ls', $msg, $fields);
1202
- return get_object_vars($result->data);
1203
- }
1204
-
1205
- //upgrade helper, not really a ws call
1206
- function fetchLatestScript()
1207
- {
1208
- $ch = curl_init();
1209
- $timeout = 0;
1210
- $url = 'https://' . $this->hostname . '/openmail/assets/ymdt';
1211
- curl_setopt($ch, CURLOPT_URL, $url);
1212
- curl_setopt($ch, CURLOPT_HEADER, TRUE);
1213
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1214
- curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1215
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1216
- if($this->lamessl)
1217
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
1218
- $result = curl_exec($ch);
1219
- $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1220
- $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1221
- curl_close($ch);
1222
- $content = substr($result, $header_size);
1223
- verify($http_code == '200' && !empty($content),
1224
- "Upgrade fetch failed (HTTP $http_code).");
1225
- return $content;
1226
- }
1227
-
1228
- };
1229
-
1230
-
1231
- define('YMDT_Version', '0.46');
1232
-
1233
-
1234
-
1235
- $HOMEDIR = Login::getHomeDir();
1236
-
1237
- ini_set('open_basedir', "");
1238
- ini_set('error_log', './error.log');
1239
- ini_set('display_errors', 'On');
1240
- ini_set('error_reporting', E_ERROR);
1241
-
1242
- $DEBUG_MODE = true;
1243
-
1244
- function verify($cond, $msg)
1245
- {
1246
- if($cond)
1247
- return;
1248
- throw new Exception($msg);
1249
- }
1250
-
1251
- class YMDT
1252
- {
1253
- private $ws;
1254
-
1255
- const OPTS___CONSTRUCT = 'h:ku:p:d';
1256
- public function __construct($cookieFname, $hostname = null, $lamessl = false,
1257
- $username = null, $password = null,
1258
- $nocookies = null)
1259
- {
1260
- if($nocookies){
1261
- verify( !file_exists($cookieFname) || unlink($cookieFname),
1262
- "Couldn't delete " . $cookieFname . '.');
1263
- $cookieFname = null;
1264
- }
1265
-
1266
- $lamessl_hosts = array('om0001.mail.mud.yahoo.com',
1267
- 'om0002.mail.mud.yahoo.com');
1268
- if(in_array($hostname, $lamessl_hosts))
1269
- $lamessl = true;
1270
-
1271
- $this->ws = new WebServiceClient($hostname, $cookieFname,
1272
- $lamessl, $username,
1273
- $password);
1274
- }
1275
-
1276
- private function membersFromCmdLineOptions($optString, $memberNames, $opts)
1277
- {
1278
- $opts = str_replace(':', '', $opts);
1279
- foreach($opts as $ndx=>$char){
1280
- $memberName = $memberNames[$ndx];
1281
-
1282
- if(array_key_exists($char, $opts))
1283
- $this->args->$memberName = $opts[$char];
1284
- else
1285
- $this->args->$memberName = null;
1286
- }
1287
- }
1288
-
1289
- public function apps()
1290
- {
1291
- $result = $this->ws->appList();
1292
-
1293
- printf("\n%-16s %-16s %.100s", 'private appid', 'public appid', 'name');
1294
- printf("\n%-16s %-16s %.100s", '--------------', '--------------',
1295
- '---------------------------------------------');
1296
- foreach ($result as $r) {
1297
- printf("\n%-16s %-16s %.100s", $r->app, $r->published_to,
1298
- $r->name);
1299
- }
1300
- echo "\n";
1301
- }
1302
-
1303
- const OPTS_CREATE = 'A:';
1304
- public function create($appdir, $appids = null)
1305
- {
1306
- verify(file_exists($appdir) || FileSys::mkdir($appdir),
1307
- "Couldn't create dir $appdir");
1308
-
1309
- $appidFname = $appdir.'/'.FileSys::APPID_FNAME;
1310
- $confFname = $appdir.'/'. 'config.xml';
1311
-
1312
- //If it's not a virgin app, we have a local working copy already
1313
- //(i.e. that we've unzipped from someone else), just nothing on the
1314
- //server yet.
1315
- $isVirginApp = !file_exists($confFname);
1316
-
1317
- $fields = array('name' => basename($appdir));
1318
- if($appids){
1319
- $appids = explode(':', $appids);
1320
- verify(count($appids) == 2, "Expected -A<pub appid>:<priv appid>");
1321
- if($appids[0])
1322
- $fields['pub_appid'] = $appids[0];
1323
- if($appids[0])
1324
- $fields['priv_appid'] = $appids[1];
1325
- }
1326
-
1327
- verify(($result = $this->ws->call('dev.app.create', $msg, $fields)),
1328
- "No webservice result.");
1329
-
1330
- verify(file_put_contents($appidFname, $result->id) !== false,
1331
- "Couldn't write $appidFname for {$result->id}");
1332
-
1333
- echo($result->message . "\n");
1334
-
1335
- if(!$isVirginApp)
1336
- return self::fixup($appdir);
1337
-
1338
- FileSys::layout(FileSys::realpath($appdir));
1339
- return self::get($appdir);
1340
- }
1341
-
1342
- function del($path)
1343
- {
1344
- list($appid, $basepath, $subpath) = FileSys::parsePath($path);
1345
- verify($subpath, 'del must reference file in working app dir');
1346
-
1347
- if(file_exists($path))
1348
- verify(!is_dir($path), 'del requires a path to a single file');
1349
-
1350
- $fields = array('app' => $appid);
1351
- $fields['path'] = $subpath;
1352
-
1353
- $json = $this->ws->call('dev.file.del', $msg, $fields);
1354
- echo "\tdeleted $path from server\n";
1355
- return;
1356
- }
1357
-
1358
- function dev($path)
1359
- {
1360
- //todo: offer choice of starting with sync from server to local dir or
1361
- // vice versa. Make sure this is an app dir, or you have an appid,
1362
- // etc.
1363
- self::get($path);
1364
- echo "\nMonitoring $path for changes. Hit Ctrl-C to exit\n\n";
1365
-
1366
-
1367
- $prevFiles = FileSys::expandPaths(array($path));
1368
- $tmLastMod = max(array_map(array('FileSys', 'modTime'), $prevFiles));
1369
-
1370
- while(true){
1371
- $files = FileSys::expandPaths(array($path));
1372
- $deletes = array_diff($prevFiles, $files);
1373
- $updates = array();
1374
- $tmMaxMod = $tmLastMod;
1375
- foreach($files as $f){
1376
- $tmMod = stat($f); $tmMod = $tmMod['mtime'];
1377
- if($tmMod <= $tmLastMod)
1378
- continue;
1379
- $updates[] = $f;
1380
- $tmMaxMod = max($tmMaxMod, $tmMod);
1381
- }
1382
- if(!empty($updates) || !empty($deletes)){
1383
- echo "\nNoticed some changes in $path, syncing. . .\n";
1384
- array_walk($updates, array($this, 'putOne'));
1385
- array_walk($deletes, array($this, 'del'));
1386
- echo "Sync done.\n";
1387
- }
1388
- $prevFiles = $files;
1389
- $tmLastMod = $tmMaxMod;
1390
- usleep(1000 * 100);
1391
- }
1392
- }
1393
-
1394
- const OPTS_DESTROY = 'a:z';
1395
- function destroy($appdir = null, $appid = null, $reallyReally = false)
1396
- {
1397
- verify($appdir || $appid, "Must specify either appdir or -a.");
1398
- if(!$appid){
1399
- list($appid, $basepath, $subpath) = FileSys::parsePath($appdir);
1400
- }
1401
-
1402
- $fields = array('app' => $appid);
1403
- $call = 'dev.app.delete';
1404
- if($reallyReally){
1405
- $call = 'admin.app.destroy';
1406
- }
1407
- verify(($result = $this->ws->call($call, $msg, $fields)),
1408
- "No webservice result.");
1409
-
1410
- echo($result->message . "\n");
1411
- }
1412
-
1413
- //fixup all asset URLs for view/assets files in $approot
1414
- const OPTS_FIXUP = 'nzs';
1415
- function fixup($approot, $appidFromName = false, $suppressAutoput = false,
1416
- $sync = false)
1417
- {
1418
- list($appid, $basepath, $subpath) = FileSys::parsePath($approot);
1419
- verify(!strlen($subpath),
1420
- "fixup requires app's root directory as an argument.");
1421
-
1422
- if($appidFromName){
1423
- $appid = $this->changePrivateAppid($basepath,
1424
- FileSys::nameFromConfFile($basepath));
1425
- }
1426
-
1427
- if(!$suppressAutoput){
1428
- echo "Uploading all files:\n";
1429
- self::put($approot, null, false, $sync);
1430
- }
1431
-
1432
- //Grab only text assets (by file extension). Assume everything in view
1433
- //dir is text.
1434
- $paths = FileSys::expandPaths(array($basepath . '/assets'));
1435
- $paths = FileSys::filterNonTextPaths($paths);
1436
- $paths = array_merge($paths, FileSys::expandPaths(array($basepath . '/views')));
1437
- $paths = FileSys::filterMetaFiles($paths);
1438
- $fixer = new AssetURL_Fixer($this->ws->ls($appid, 'assets'));
1439
- array_walk($paths, array($fixer, 'run'));
1440
- $numChanged = count($fixer->changedFilePaths);
1441
- if(!$suppressAutoput && $numChanged){
1442
- echo "Uploading changed files:\n";
1443
- array_walk($fixer->changedFilePaths, array($this, 'putOne'));
1444
- }
1445
- }
1446
-
1447
- const OPTS_GET = 'a:sy';
1448
- function get($path, $appid = null, $sync = false, $autoYes = false)
1449
- {
1450
- if($appid){
1451
- list($subpath, $basepath) = array(null, $path);
1452
- $fname = $basepath.'/'.FileSys::APPID_FNAME;
1453
- FileSys::mkdir($basepath);
1454
- verify(file_put_contents($fname, $appid), "Couldn't write $fname.");
1455
- FileSys::layout($basepath);
1456
- }
1457
- else{
1458
- list($appid, $basepath, $subpath) = FileSys::parsePath($path);
1459
- }
1460
- $fetchedPaths = self::lsAndGet($appid, $subpath, $basepath);
1461
- if(!$sync)
1462
- return;
1463
-
1464
- $fetchedPaths = array_map(array('FileSys', 'realpath'), $fetchedPaths);
1465
- $localPaths = FileSys::expandPaths(array($path));
1466
- // echo 'localPaths: ' . print_r($localPaths, true) . "\n";
1467
- $localPaths = FileSys::filterMetaFiles($localPaths, FileSys::realpath($basepath));
1468
- // echo 'filtered: ' . print_r($localPaths, true) . "\n";
1469
- //echo 'fetched: ' . print_r($fetchedPaths, true) . "\n";
1470
-
1471
- $deletes = array_diff($localPaths, $fetchedPaths);
1472
- if(!$autoYes &&
1473
- !self::confirmDeletes($deletes,
1474
- "\nThe following files aren't present on the server:\n",
1475
- "\nWould you like to delete the local copies? "))
1476
- return;
1477
-
1478
- foreach($deletes as $d){
1479
- verify(unlink($d) , "Couldn't delete $d");
1480
- echo "\tdeleted $d\n";
1481
- }
1482
- }
1483
-
1484
- function help($command)
1485
- {
1486
- if(!$command)
1487
- show_usage();
1488
-
1489
- $txt_var = 'HELP_' . strtoupper($command);
1490
- if(!array_key_exists($txt_var, $GLOBALS)){
1491
- echo 'Command ' . $command . ' unknown.' . "\n\n";
1492
- return;
1493
- }
1494
-
1495
- global $$txt_var, $HELP_COMMON_OPTIONS;
1496
- echo $$txt_var . "\n$HELP_COMMON_OPTIONS\n\n";;
1497
- }
1498
-
1499
- function ls($path)
1500
- {
1501
- list($appid, $basepath, $subpath) = FileSys::parsePath($path);
1502
- $results = $this->ws->ls($appid, $subpath);
1503
-
1504
- foreach($results as $fname => $url)
1505
- echo "\t" . $fname . "\t" . $url . "\n";
1506
- }
1507
-
1508
- const OPTS_PUBLISH = 'a:z';
1509
- function publish($appdir = null, $appidOverride = null, $suppressValidation = false)
1510
- {
1511
- $appid = null;
1512
- if(strlen($appdir)){
1513
- list($appid, $basepath, $subpath) = FileSys::parsePath($appdir);
1514
- verify(!strlen($subpath),
1515
- "publish requires path to be app's root directory.");
1516
- }
1517
-
1518
- if($appidOverride)
1519
- $appid = $appidOverride;
1520
-
1521
- verify($appid, 'publish requires -a option or a <path>');
1522
-
1523
- $fields = array('app' => $appid);
1524
- if(!$suppressValidation)
1525
- $fields['validate_assets'] = 'true';
1526
-
1527
- $this->ws->call('dev.app.publish', $msg, $fields);
1528
- echo "\tdone publication\n";
1529
- }
1530
-
1531
- const OPTS_PUT = 'a:nsy';
1532
- function put($pattern, $appidOverride = null, $appidFromName = false,
1533
- $sync = false, $autoYes = false)
1534
- {
1535
- list($appid, $basepath, $subpath) = FileSys::parsePath($pattern);
1536
- if($appidOverride){
1537
- $appid = $appidOverride;
1538
- }
1539
- if($appidFromName){
1540
- verify(!$appidOverride, "put can't accept both -n and -a");
1541
- $appid = $this->changePrivateAppid($basepath,
1542
- FileSys::nameFromConfFile($basepath));
1543
- }
1544
-
1545
- $paths = FileSys::expandPaths(glob($pattern, GLOB_MARK));
1546
- $paths = FileSys::filterMetaFiles($paths, $basepath);
1547
- array_walk($paths, array($this, 'putOne'));
1548
-
1549
- if(count($paths) > 1)
1550
- echo "Done all puts for $pattern.\n";
1551
-
1552
- if(!$sync)
1553
- return;
1554
-
1555
- echo "\tappid now $appid\n";
1556
- $remote_paths = $this->ws->ls($appid, $subpath);
1557
- $remote_paths = array_keys($remote_paths);
1558
-
1559
- //Need relative (to app root) paths
1560
- $root = FileSys::realpath($basepath);
1561
- $newpaths = array();
1562
- foreach($paths as $p){
1563
- $newpaths[] = substr($p, strlen($root)+1);
1564
- }
1565
- $paths = $newpaths;
1566
-
1567
- $deletes = array();
1568
-
1569
- //echo 'remote paths: ' . print_r($remote_paths, true) . "\n\n";
1570
- //echo 'paths: ' . print_r($paths, true) . "\n\n";
1571
-
1572
- foreach($remote_paths as $p){
1573
- if(in_array($p, $paths) || is_dir($p))
1574
- continue;
1575
- $deletes[] = $p;
1576
- }
1577
-
1578
- if(!$autoYes &&
1579
- !self::confirmDeletes($deletes,
1580
- "\nThe following files aren't present locally:\n",
1581
- "\nWould you like to delete them from the server? "));
1582
- return;
1583
-
1584
- foreach($deletes as $path){
1585
- $fields = array('app' => $appid);
1586
- $fields['path'] = $path;
1587
- $json = $this->ws->call('dev.file.del', $msg, $fields);
1588
- echo "\tdeleted $path from server\n";
1589
- }
1590
- }
1591
-
1592
- function tester($subcmd = null, $emailOrYid = null)
1593
- {
1594
- $legalSubs = array('ls', 'del', 'invite');
1595
- verify($subcmd && in_array($subcmd, $legalSubs),
1596
- "tester command requires a subcommand, one of: " .
1597
- implode(', ', $legalSubs) . ".");
1598
-
1599
- if($subcmd == 'ls')
1600
- return $this->testerLs();
1601
-
1602
- $msg = '';
1603
- if($subcmd == 'del'){
1604
- verify($emailOrYid, "tester del requires the tester's Yahoo! ID.");
1605
- $fields = array('email' => $emailOrYid);
1606
- $result = $this->ws->call('dev.yid.remove', $msg, $fields);
1607
- echo "Tester $emailOrYid deleted.\n\n";
1608
- return;
1609
- }
1610
-
1611
- verify($emailOrYid, "tester del requires the tester's Yahoo email address.");
1612
- $fields = array('email' => $emailOrYid);
1613
- $result = $this->ws->call('dev.yid.add', $msg, $fields);
1614
- echo "Tester $emailOrYid invited.\n\n";
1615
- }
1616
-
1617
- function testerLs()
1618
- {
1619
- $fields = array();
1620
- $arr = $this->ws->call('dev.yid.list', $fields, $msg, 'json', false);
1621
- verify(is_array($arr), "Unexpected ws result for dev.yid.list: "
1622
- . print_r($arr, true));
1623
- printf("%-32s %-16s\n", 'Yahoo! ID', "Pending?");
1624
- printf("-----------------------------------------\n");
1625
- foreach($arr as $tester){
1626
- printf("%-32s %-16s\n", $tester->yid,
1627
- $tester->pending ? 'yes' : '');
1628
- }
1629
- }
1630
-
1631
- function confirmDeletes($deletes, $list_header, $question)
1632
- {
1633
- if(!empty($deletes)){
1634
- shell_exec("./script/growl");
1635
- echo $list_header;
1636
- foreach($deletes as $d){
1637
- echo "\t$d\n";
1638
- }
1639
- $response = Login::promptUserInput($question);
1640
- if(strtolower($response[0]) === 'n')
1641
- return false;
1642
- }
1643
- return true;
1644
- }
1645
-
1646
- function lsAndGet($appid, $src_subpath, $dest_basepath)
1647
- {
1648
- //Do an ls first in case they're using a dir or glob for path.
1649
- $results = $this->ws->ls($appid, $src_subpath);
1650
- $count = 0;
1651
- //Get each file returned by ls
1652
- $local_file_paths = array();
1653
- foreach($results as $fname => $url){
1654
- $fields = array('app' => $appid,
1655
- 'name' => $fname);
1656
- $file_path = $dest_basepath . '/' . $fname;
1657
- echo "\tdownloading $file_path. . .\n";
1658
- $result = $this->ws->call('dev.file.get', $msg, $fields, null);
1659
-
1660
- FileSys::mkdir(dirname($file_path));
1661
-
1662
- verify(file_put_contents($file_path, $result) !== false,
1663
- "Couldn't write $file_path");
1664
- $local_file_paths[] = $file_path;
1665
- $count ++;
1666
- }
1667
- if($count > 1)
1668
- echo "Done all gets for $dest_basepath.\n";
1669
- return $local_file_paths;
1670
- }
1671
-
1672
- private function changePrivateAppidFromName($appdir, $name)
1673
- {
1674
- $list = $this->ws->appList();
1675
- $privAppid = null;
1676
- foreach($list as $app){
1677
- if($name != $app->name)
1678
- continue;
1679
- verify(!$privAppid,
1680
- "More than one app named '$name' for logged on developer.");
1681
- $privAppid = $app->app;
1682
- }
1683
- verify($privAppid, "No app named '$name' for logged-on developer.");
1684
- return $this->changeWorkingAppid($appdir, $privAppid);
1685
- }
1686
-
1687
- private function changeWorkingAppid($appdir, $appid)
1688
- {
1689
- verify(file_put_contents($appdir . '/' . FileSys::APPID_FNAME, $appid)
1690
- !== FALSE);
1691
- echo "\tchanged appid to $appid. \n";
1692
- return $appid;
1693
- }
1694
-
1695
- function putOne($path)
1696
- {
1697
- echo "\tuploading $path. . .\n";
1698
-
1699
- list($appid, $basepath, $subpath) = FileSys::parsePath($path);
1700
-
1701
- $contents = file_get_contents($path);
1702
- verify($contents !== false, "Couldn't read contents of $path.");
1703
-
1704
- $fields = array('app' => $appid,
1705
- 'name' => $subpath,
1706
- 'file' => '@' . $path);
1707
-
1708
- $result = $this->ws->call('dev.file.put', $msg, $fields);
1709
-
1710
- return;
1711
- }
1712
-
1713
- function upgrade()
1714
- {
1715
- $newYmdt = $this->ws->fetchLatestScript();
1716
-
1717
- verify(!strpos(__FILE__, '.php'),
1718
- "Can't upgrade source file, only built version.");
1719
- $archive = __FILE__ . '.old';
1720
- verify(copy(__FILE__, $archive),
1721
- "Upgrade failed, couldn't archive current version to $archive.");
1722
- verify(file_put_contents(__FILE__, $newYmdt) !== false,
1723
- "Upgrade failed, couldn't write " . __FILE__);
1724
- echo "Done upgrade, previous version archived to $archive.\n";
1725
- return 0;
1726
- }
1727
- }
1728
-
1729
- function show_usage()
1730
- {
1731
- global $HELP_USAGE;
1732
-
1733
- echo $HELP_USAGE . "\n\n";
1734
- exit(-1);
1735
- }
1736
-
1737
- //Given an options string as taken by getopt(), return options array and reindex
1738
- //global argv to omit the options.
1739
- function getopts_and_reindex($opts)
1740
- {
1741
- list($options, $rest) = Console_Getopt::getopt($GLOBALS['argv'], $opts);
1742
- $GLOBALS['argv'] = array_merge(array('ymdt'), $rest);
1743
- // echo "OPTS: $opts\n";
1744
- //echo "OPTIONS:\n" . print_r($options, true);
1745
- //echo "ARGV:\n" . print_r($GLOBALS['argv'], true);
1746
- return $options;
1747
- }
1748
-
1749
- function getMethodMetadata($className, $methodName)
1750
- {
1751
- $class = new ReflectionClass($className);
1752
- $optString = $class->getConstant(strtoupper('OPTS_' . $methodName));
1753
-
1754
- $method = new ReflectionMethod($className, $methodName);
1755
- $params = $method->getParameters();
1756
- $optionalParamNames = array();
1757
- $requiredParamCount = $method->getNumberOfRequiredParameters();
1758
- foreach($params as $ndx=>$p){
1759
- if($ndx < $requiredParamCount)
1760
- continue;
1761
- $optionalParamNames[] = $p->getName();
1762
- }
1763
-
1764
- //Optional parameters come either from -xYYY command-line or just plain argv args
1765
- $optChars = str_replace(':', '', $optString);
1766
- verify(strlen($optChars) <= count($optionalParamNames),
1767
- "Internal error: $methodName optstring wrong len.");
1768
- return array($method, $optString, $requiredParamCount);
1769
- }
1770
-
1771
- function getMethodOptionalParamVals($method, $optString, $options)
1772
- {
1773
- $params = $method->getParameters();
1774
- $requiredParamCount = $method->getNumberOfRequiredParameters();
1775
- $optionalParamCount = $method->getNumberOfParameters() - $requiredParamCount;
1776
-
1777
- $optChars = str_replace(':', '', $optString);
1778
- $paramVals = array();
1779
-
1780
- //Switchless as in specified w/o a command-line switch, i.e. for:
1781
- //ymdt destroy myappdir #myappdir is a switchless optional param
1782
- //ymdt destroy -a myappid #myappid is a command-line switch optional param
1783
- $switchlessOptionalParamCount = $optionalParamCount - strlen($optChars);
1784
-
1785
- //Grab the switchless optional params that came from argv, unspecified ones
1786
- //will get default vals. +2 excludes 'ymdt' and command
1787
- $paramVals = array_slice($GLOBALS['argv'], $requiredParamCount + 2, $switchlessOptionalParamCount);
1788
- $defaultSwitchlessOptionalParamCount = $switchlessOptionalParamCount - count($paramVals);
1789
- $defaultSwitchlessOptionalParamCount = max(0, $defaultSwitchlessOptionalParamCount);
1790
- // echo "sOPC $switchlessOptionalParamCount, dSOPC
1791
- // $defaultSwitchlessOptionalParamCount rPC $requiredParamCount\n";
1792
- // echo "paramVals " . print_r($paramVals, true);
1793
-
1794
- for($i = 0; $i < $defaultSwitchlessOptionalParamCount; $i++){
1795
- $paramNdx = $requiredParamCount + $i;
1796
- $paramVals[] = $params[$paramNdx]->getDefaultValue();
1797
- }
1798
-
1799
- //Grab the optional params that are specified by a command-line switch
1800
- $switchOptionalParamCount = strlen($optChars);
1801
- for($i = 0; $i < $switchOptionalParamCount; $i++){
1802
- $paramNdx = $requiredParamCount + $defaultSwitchlessOptionalParamCount + $i;
1803
- $optChar = $optChars[$i];
1804
- if(array_key_exists($optChar, $options))
1805
- $paramVals[] = strlen($options[$optChar]) ? $options[$optChar] : true;
1806
- else
1807
- $paramVals[] = $params[$paramNdx]->getDefaultValue();
1808
- }
1809
-
1810
- return $paramVals;
1811
- }
1812
-
1813
- function main()
1814
- {
1815
- echo "Yahoo! Mail Development Tool Version " . YMDT_Version . "\n";
1816
-
1817
- static $legal_cmds = array('apps', 'create', 'ls', 'fixup', 'get', 'help',
1818
- 'put', 'del', 'dev', 'upgrade', 'publish',
1819
- 'destroy', 'tester');
1820
-
1821
- if(count($GLOBALS['argv']) < 2){
1822
- echo "\nFirst argument must be a command\n\n";
1823
- show_usage();
1824
- }
1825
- $cmd = $GLOBALS['argv'][1];
1826
- if(!in_array($cmd, $legal_cmds)){
1827
- echo "\nFirst argument must be a command.\n"
1828
- ."'$cmd' is not a legal command.\n\n";
1829
- show_usage();
1830
- }
1831
-
1832
- //get constructor optstring, opt params
1833
- //get command optstring, opt params, required params
1834
-
1835
- list($ctor, $ctorOptString, $ctorRequiredParamCount) =
1836
- getMethodMetadata('YMDT', '__construct');
1837
-
1838
- list($method, $cmdOptString, $cmdRequiredParamCount) =
1839
- getMethodMetadata('YMDT', $cmd);
1840
-
1841
- $ctorOptChars = str_replace(':', '', $ctorOptString);
1842
- verify(!strpbrk($ctorOptChars, $cmdOptString),
1843
- "Internal error: $cmd optstring clashes with common optstring.");
1844
-
1845
- //array of option char ==> value
1846
- $options = getopts_and_reindex($cmdOptString . $ctorOptString);
1847
-
1848
- //Invoke constructor with cookieFname, <optional parameters. . .>
1849
- //All optional take defaults unless overridden at command line.
1850
- global $HOMEDIR;
1851
-
1852
- $paramVals = array("$HOMEDIR/.ymdtcookie");
1853
- $paramVals = array_merge($paramVals,
1854
- getMethodOptionalParamVals($ctor, $ctorOptString,
1855
- $options));
1856
- $paramVals = array_slice($paramVals, 0, -1);
1857
-
1858
- //create it
1859
- // echo "params: " . print_r($paramVals, true) . "\n\n";
1860
- $class = new ReflectionClass('YMDT');
1861
- $ymdt = $class->newInstanceArgs($paramVals);
1862
-
1863
- $argCount = count($GLOBALS['argv']) - 2;
1864
- if($argCount < $cmdRequiredParamCount){
1865
- echo "\n$cmd expected at least $cmdRequiredParamCount argument(s), " .
1866
- "got $argCount\n" .
1867
- "run ymdt help $cmd for more information.\n\n";
1868
- exit(-1);
1869
-
1870
- }
1871
-
1872
- $paramVals = array_slice($GLOBALS['argv'], 2, $cmdRequiredParamCount);
1873
- $paramVals = array_merge($paramVals,
1874
- getMethodOptionalParamVals($method, $cmdOptString,
1875
- $options));
1876
- // echo print_r($paramVals, true);
1877
- //invoke the command
1878
- echo "$cmd:\n";
1879
- // implode(' ', array_slice($paramVals, 0, $cmdRequiredParamCount)). "\n\n";
1880
-
1881
- try {
1882
- $method->invokeArgs($ymdt, $paramVals);
1883
- }
1884
- catch(Exception $e){
1885
- global $DEBUG_MODE;
1886
- echo $e->getMessage() . "\n";
1887
- if($DEBUG_MODE)
1888
- throw $e;
1889
- }
1890
-
1891
- }
1892
-
1893
- main();
1894
-
1895
- ?>