1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19:
20: require_once( __DIR__ . '/includes/php-classes/AlfredBundlerLogger.php' );
21: require_once( __DIR__ . '/includes/php-classes/AlfredBundlerIcon.php' );
22:
23:
24: if ( ! class_exists( 'AlfredBundlerInternalClass' ) ) :
25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37:
38: class AlfredBundlerInternalClass {
39:
40: 41: 42: 43: 44: 45:
46: public $data;
47:
48: 49: 50: 51: 52: 53:
54: public $cache;
55:
56: 57: 58: 59: 60: 61:
62: public $major_version;
63:
64: 65: 66: 67: 68: 69:
70: public $minor_version;
71:
72: 73: 74: 75: 76: 77:
78: private $plist;
79:
80: 81: 82: 83: 84: 85:
86: public $bundle;
87:
88: 89: 90: 91: 92: 93:
94: public $name;
95:
96: 97: 98: 99: 100:
101: public $workflowData;
102:
103: 104: 105: 106: 107: 108:
109: public $background;
110:
111:
112: public $finfo;
113:
114:
115: public $alfredVersion;
116:
117: 118: 119: 120: 121: 122:
123: private $caches;
124:
125: 126: 127: 128: 129: 130:
131: public $log;
132:
133: 134: 135: 136: 137: 138:
139: public $userLog;
140:
141: 142: 143: 144: 145: 146:
147: public $env;
148:
149:
150: 151: 152: 153: 154: 155: 156: 157: 158:
159: public function __construct( $options = [] ) {
160:
161: if ( isset( $_ENV['AB_BRANCH'] ) ) {
162: $this->major_version = $_ENV['AB_BRANCH'];
163: } else {
164: $this->major_version = file_get_contents( __DIR__ . '/meta/version_major' );
165: }
166:
167: $this->minor_version = file_get_contents( __DIR__ . '/meta/version_minor' );
168:
169: $this->data = trim( "{$_SERVER[ 'HOME' ]}/Library/Application Support/Alfred 2/Workflow Data/alfred.bundler-{$this->major_version}" );
170: $this->cache = trim( "{$_SERVER[ 'HOME' ]}/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/alfred.bundler-{$this->major_version}" );
171:
172: $this->setup();
173:
174: $this->log = new AlfredBundlerLogger( "{$this->data}/data/logs/bundler-{$this->major_version}" );
175:
176: if ( isset( $options[ 'log' ] ) )
177: $log = $options[ 'log' ];
178: else
179: $log = 'file';
180:
181: $this->userLog = new AlfredBundlerLogger( "{$this->workflowData}/{$this->name}", $log );
182:
183:
184: return TRUE;
185: }
186:
187: 188: 189: 190:
191: private function setup() {
192:
193:
194: if ( ! file_exists( 'info.plist' ) )
195: throw new Exception( 'Using the Alfred Bundler requires a valid info.plist file to be found; in other words, it needs to be used in a workflow. ');
196:
197: if ( isset( $_ENV[ 'alfred_version' ] ) )
198: $this->setupModern();
199: else
200: $this->setupDeprecated();
201:
202: $this->setupDirStructure();
203:
204: }
205:
206: 207: 208:
209: private function setupModern() {
210:
211: $this->bundle = $_ENV[ 'alfred_workflow_bundleid' ];
212: $this->name = $_ENV[ 'alfred_workflow_name' ];
213: $this->workflowData = $_ENV[ 'alfred_workflow_data' ];
214: $this->env = TRUE;
215:
216: }
217:
218: 219: 220:
221: private function setupDeprecated() {
222:
223: $this->bundle = $this->readPlist( 'info.plist', 'bundleid' );
224: $this->name = $this->readPlist( 'info.plist', 'name' );
225: $this->workflowData = $_SERVER[ 'HOME' ] .
226: "/Library/Application Support/Alfred 2/Workflow Data/" . $this->bundle;
227: $this->env = FALSE;
228:
229: }
230:
231: 232: 233:
234: private function setupDirStructure() {
235:
236:
237: $directories = array(
238: "{$this->data}/data",
239: "{$this->cache}",
240: "{$this->cache}/color",
241: "{$this->cache}/misc",
242: "{$this->cache}/php",
243: "{$this->cache}/ruby",
244: "{$this->cache}/python",
245: "{$this->cache}/utilities",
246: );
247:
248: foreach ( $directories as $dir ) :
249:
250: if ( ! file_exists( $dir ) )
251: mkdir( $dir, 0775, TRUE );
252: endforeach;
253: }
254:
255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267:
268: public function load( $type, $name, $version, $json = '' ) {
269:
270: if ( empty( $json ) ) {
271: if ( file_exists( __DIR__ . "/meta/defaults/{$name}.json" ) ) {
272: $json_path = __DIR__ . "/meta/defaults/{$name}.json";
273: } else {
274:
275: $error = TRUE;
276: }
277: } else if ( file_exists( $json ) ) { $line = __LINE__;
278: $json_path = $json;
279: } else {
280:
281: $error = TRUE;
282: }
283:
284:
285: if ( ! json_decode( file_get_contents( $json_path ) ) ) { $line = __LINE__;
286:
287: $error = TRUE;
288: }
289:
290:
291: if ( isset( $error ) && ( $error === TRUE ) ) {
292:
293:
294:
295: $this->log->log( "There is a problem with the __implementation__ of " .
296: "the Alfred Bundler when trying to load '{$name}'. Please " .
297: "let the workflow author know.", 'CRITICAL', 'console' );
298: return FALSE;
299: }
300:
301: $json = json_decode( file_get_contents( $json_path ), TRUE );
302:
303:
304: if ( ! file_exists(
305: "{$this->data}/data/assets/{$type}/{$name}/{$version}/invoke" ) ) {
306:
307: if ( ! $this->installAsset(
308: "{$this->data}/bundler/meta/defaults/{$name}.json", $version ) ) {
309: return FALSE;
310: }
311: }
312:
313:
314: $this->register( $name, $version ); $line = __LINE__;
315: $this->log->log( "Registering assset '{$name}'",
316: 'INFO', 'console' );
317:
318:
319: if ( ! file_exists(
320: "{$this->data}/data/assets/{$type}/{$name}/{$version}/invoke" ) ) {
321:
322: return FALSE;
323: }
324:
325: if ( $type != 'utility' ) {
326:
327: $this->log->log( "Loaded '{$name}' version {$version} of type " .
328: "'{$type}'", 'INFO', 'console' );
329:
330: return "{$this->data}/data/assets/{$type}/{$name}/{$version}/"
331: . trim( file_get_contents( "{$this->data}/data/assets/{$type}/{$name}/{$version}/invoke" ) );
332: } else {
333:
334: if ( ! ( isset( $json[ 'gatekeeper' ] )
335: && ( $json[ 'gatekeeper' ] == TRUE ) ) ) {
336:
337:
338: $this->log->log( "Loaded '{$name}' version {$version} of type " .
339: "'{$type}'", 'INFO', 'console' );
340:
341: return "{$this->data}/data/assets/{$type}/{$name}/{$version}/"
342: . trim( file_get_contents( "{$this->data}/data/assets/{$type}/{$name}/{$version}/invoke" ) );
343: }
344: }
345:
346:
347:
348:
349: if ( file_exists( 'icon.png' ) )
350: $icon = realpath( 'icon.png' );
351: else
352: $icon = 'default';
353:
354:
355: $path = "{$this->data}/data/assets/{$type}/{$name}/{$version}/"
356: . $json[ 'versions' ][ $version ][ 'invoke' ];
357:
358:
359: if ( isset( $json[ 'message' ] ) )
360: $message = $json[ 'message' ];
361: else
362: $message = '';
363:
364:
365:
366: if ( $this->gatekeeper( $name, $path, $message, $icon ) ) {
367:
368: $this->log->log( "Loaded '{$name}' v{$version} of type '{$type}'.",
369: 'INFO', 'console' );
370: return $path;
371: } else {
372:
373:
374: return FALSE;
375: }
376:
377:
378:
379: $this->log->log( "There is a problem with the __implementation__ of " .
380: "the Alfred Bundler when trying to load '{$name}'. Please let the " .
381: "workflow author know.", 'ERROR', 'console' );
382:
383: return FALSE;
384: }
385:
386:
387:
388: public function icon( $font, $name, $color = '000000', $alter = FALSE ) {
389: if ( ! isset( $this->icon ) )
390: $this->icon = new AlfredBundlerIcon( $this );
391:
392: return $this->icon->icon([ 'font' => $font, 'name' => $name, 'color' => $color, 'alter' => $alter ]);
393: }
394:
395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405:
406: public function utility( $name, $version = 'latest', $json = '' ) {
407: if ( empty( $json ) ) {
408: return $this->load( 'utility', $name, $version );
409: } else {
410: if ( file_exists( $json ) ) {
411: return $this->load( 'utility', $name, $version, $json );
412: }
413: }
414: return FALSE;
415: }
416:
417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427:
428: public function library( $name, $version = 'latest', $json = '' ) {
429: $dir = "{$this->data}/data/assets/php/{$name}/{$version}";
430: if ( file_exists( "{$dir}/invoke" ) ) {
431: require_once "{$dir}/" . trim( file_get_contents( "{$dir}/invoke" ) );
432: return TRUE;
433: } else {
434: if ( $this->load( 'php', $name, $version, $json ) ) {
435: require_once "{$dir}/" . trim( file_get_contents( "{$dir}/invoke" ) );
436: return TRUE;
437: } else {
438: return FALSE;
439: }
440: }
441: }
442:
443: 444: 445: 446: 447: 448: 449: 450:
451: public function wrapper( $wrapper, $debug = FALSE ) {
452: $wrapperPointer = [
453: 'cocoadialog'=>'cocoaDialog',
454: 'terminalnotifier'=>'terminal-notifier'
455: ];
456: $wrappersDir = "{$this->data}/bundler/includes/wrappers/php";
457: if ( file_exists( "{$wrappersDir}/{$wrapper}.php" ) ) {
458: require_once "{$wrappersDir}/{$wrapper}.php";
459: $this->log->log( "Loaded '{$wrapper}' bindings", 'INFO', 'console' );
460: return new $wrapper( $this->utility( $wrapperPointer[strtolower( $wrapper )] ), $debug );
461: } else {
462: $this->log->log( "'{$wrapper}' not found.", 'ERROR', 'console' );
463: return 10;
464: }
465: }
466:
467: 468: 469: 470: 471: 472: 473: 474:
475: public function composer( $packages ) {
476: $composerDir = "{$this->data}/data/assets/php/composer";
477: if ( ! file_exists( $composerDir ) )
478: mkdir( $composerDir, 0755, TRUE );
479:
480: if ( ! file_exists( "{$composerDir}/composer.phar" ) ) {
481: $this->download( "https://getcomposer.org/composer.phar", "{$composerDir}/composer.phar" ); $line = __LINE__;
482: exec( "'{$composerDir}/composer.phar'", $output, $status );
483: if ( $status !== 0 ) {
484: $this->log->log( "Composer.phar is corrupt. Deleting...", 'CRITICAL', 'console' );
485: } else {
486: $this->log->log( "Installing Composer.phar to `{$composerDir}`", 'INFO', 'both' );
487: }
488:
489: }
490:
491: $install = FALSE;
492:
493: if ( file_exists( "{$composerDir}/bundles/{$this->bundle}/autoload.php" ) ) {
494: if ( file_exists( "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}/composer.json" ) ) {
495: $installDir = "{$this->cache}/{$this->bundle}/composer";
496: if ( ! file_exists( $installDir ) )
497: mkdir( "{$installDir}", 0775, TRUE );
498: $json = json_encode( array( "require" => $packages ) );
499: $json = str_replace( '\/', '/', $json );
500: file_put_contents( "{$installDir}/composer.json", $json );
501:
502: if ( hash_file( 'md5', "{$installDir}/composer.json" )
503: == hash_file( 'md5', "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}/composer.json" ) ) {
504: $this->log->log( "Loaded Composer packages for {$this->bundle}.",
505: 'INFO', 'console' );
506: require_once(
507: "{$composerDir}/bundles/{$this->bundle}/autoload.php" );
508:
509: return TRUE;
510: } else {
511: $install = TRUE;
512: if ( file_exists( "{$composerDir}/bundles/{$this->bundle}" ) ) {
513: $this->rrmdir( "{$composerDir}/bundles/{$this->bundle}" );
514: }
515: }
516: }
517: } else {
518: $install = TRUE;
519: }
520:
521: if ( $install == TRUE ) {
522: if ( is_dir( "{$composerDir}/bundles/{$this->bundle}" ) ) {
523: $this->rrmdir( "{$composerDir}/bundles/{$this->bundle}" );
524: }
525: if ( $this->installComposerPackage( $packages ) === TRUE ) {
526: $this->log->log( "Loaded Composer packages for {$this->bundle}.",
527: 'INFO', 'console' );
528: require_once "{$composerDir}/bundles/{$this->bundle}/autoload.php";
529: return TRUE;
530: } else {
531: $this->log->log( "ERROR: failed to install packages for {$this->bundle}", 'ERROR', 'both' );
532: return FALSE;
533: }
534: }
535: }
536:
537:
538:
539: 540: 541: 542: 543:
544: public function icns() {
545:
546: if ( ! file_exists( $this->plist ) )
547: return FALSE;
548: if ( ( ! isset( $this->bundle ) ) || empty( $this->bundle ) )
549: return FALSE;
550: if ( ! file_exists(
551: realpath( dirname( "{$this->plist}" ) . "/icon.png" ) ) ) {
552: return FALSE;
553: }
554:
555: if ( file_exists( "{$this->cache}/icns/{$this->bundle}.icns" ) ) {
556: return "{$this->cache}/icns/{$this->bundle}.icns";
557: } else {
558: $script = realpath( "'" . __DIR__ . '/includes/png_to_icns.sh' . "'" );
559: $icon = realpath( dirname( "{$this->plist}" ) . "/icon.png" );
560: exec( "bash '{$script}' '{$icon}' '{$this->bundle}.icns'" );
561: if ( file_exists( "{$this->cache}/icns/{$this->bundle}.icns" ) )
562: return "{$this->cache}/icns/{$this->bundle}.icns";
563: else
564: return FALSE;
565: }
566: }
567:
568: 569: 570:
571:
572: 573: 574: 575: 576: 577: 578:
579: public function installAsset( $json, $version = 'latest' ) {
580: if ( ! file_exists( $json ) ) {
581: $this->log->log( "Cannot install asset because the JSON file ('{$json}') is not present.", 'ERROR', 'console' );
582: return FALSE;
583: }
584:
585: $json = json_decode( file_get_contents( $json ), TRUE );
586:
587:
588: if ( $json == null ) {
589: $this->log->log( "Cannot install asset because the JSON file ('{$json}') is not valid.", 'ERROR', 'console' );
590: return FALSE;
591: }
592:
593: $installDir = "{$this->data}/data/assets/{$json[ 'type' ]}/{$json[ 'name' ]}/{$version}";
594:
595: if ( ! file_exists( $installDir ) )
596: mkdir( $installDir, 0775, TRUE );
597:
598:
599: $tmpDir = "{$this->cache}/installers";
600: if ( ! file_exists( $tmpDir ) )
601: mkdir( $tmpDir, 0775, TRUE );
602:
603: $name = $json[ 'name' ];
604: $type = $json[ 'type' ];
605:
606:
607:
608: if ( ! isset( $json[ 'versions' ][ $version ] ) ) {
609: if ( ! isset( $json[ 'versions' ][ 'latest' ] ) ) {
610: $this->log->log( "Cannot install {$name} because no version found and cannot fallback to 'latest'.", 'ERROR', 'both');
611: return FALSE;
612: } else {
613: $version = 'latest';
614: }
615: }
616: $invoke = $json[ 'versions' ][ $version ][ 'invoke' ];
617: $install = $json[ 'versions' ][ $version ][ 'install' ];
618:
619:
620: foreach ( $json[ 'versions' ][ $version ][ 'files' ] as $url ) {
621: $file = pathinfo( parse_url( $url[ 'url' ], PHP_URL_PATH ) );
622: $file = $file[ 'basename' ];
623: if ( ! $this->download( $url[ 'url' ], "{$tmpDir}/{$file}" ) ) {
624: $this->log->log( "Cannot download {$name} at {$url['url']}.", 'ERROR', 'console' );
625: return FALSE;
626: }
627:
628:
629: if ( $url[ 'method' ] == 'zip' ) {
630:
631: exec( "unzip -qo '{$tmpDir}/{$file}' -d '{$tmpDir}'" );
632: } else if ( $url[ 'method' ] == 'tgz' || $url[ 'method' ] == 'tar.gz' ) {
633:
634: exec( "tar xzf '{$tmpDir}/{$file}' -C '{$tmpDir}'" );
635: }
636: }
637: if ( is_array( $install ) ) {
638: foreach ( $install as $i ) {
639:
640: $i = str_replace( "__FILE__" , "{$tmpDir}/$file", $i );
641: $i = str_replace( "__CACHE__", "{$tmpDir}/", $i );
642: $i = str_replace( "__DATA__" , "{$installDir}/", $i );
643: exec( $i );
644: }
645: }
646:
647: file_put_contents( "{$installDir}/invoke", $invoke );
648: $this->log->log( "Installed '{$type}': '{$name}' -- version '{$version}'.", 'INFO', 'both' );
649: $this->rrmdir( "{$tmpDir}" );
650: return TRUE;
651: }
652:
653: 654: 655: 656: 657: 658: 659: 660:
661: private function installComposerPackage( $packages ) {
662: if ( ! is_array( $packages ) ) {
663:
664: $this->log->log( "An array must be passed to install Composer assets.", 'ERROR', 'console' );
665: return FALSE;
666: }
667:
668: $installDir = "{$this->cache}/{$this->bundle}/composer";
669:
670: if ( ! file_exists( $installDir ) )
671: mkdir( "{$installDir}", 0775, TRUE );
672:
673: $json = json_encode( array( "require" => $packages ) );
674: $json = str_replace( '\/', '/', $json );
675: file_put_contents( "{$installDir}/composer.json", $json );
676:
677: $cmd = "php '{$this->data}/data/assets/php/composer/composer.phar' install -q -d '{$installDir}'";
678: exec( $cmd );
679:
680:
681: $packages = json_decode( file_get_contents( "{$installDir}/vendor/composer/installed.json" ), TRUE );
682:
683:
684: $files = array( 'autoload_psr4.php', 'autoload_namespaces.php', 'autoload_files.php', 'autoload_classmap.php' );
685: $destination = "{$this->data}/data/assets/php/composer/vendor";
686: $installed = array();
687:
688: foreach ( $packages as $package ) :
689:
690: $name = explode( '/', $package[ 'name' ] );
691: $vendor = $name[0];
692: $name = $name[1];
693: $version = $package[ 'version' ];
694: $installed[] = array( 'name' => $name,
695: 'vendor' => $vendor,
696: 'version' => $version );
697:
698: foreach ( $files as $file ) :
699: if ( file_exists( "{$installDir}/vendor/composer/{$file}" ) ) {
700: $f = file( "{$installDir}/vendor/composer/{$file}" );
701: foreach ( $f as $num => $line ) :
702: $line = str_replace( '$vendorDir = dirname(dirname(__FILE__));', "\$vendorDir = '{$this->data}/data/assets/php/composer/vendor';", $line );
703: $line = str_replace( '$baseDir = dirname($vendorDir);', "\$baseDir = '{$this->data}/data/assets/php/composer';", $line );
704: $line = str_replace( 'array($vendorDir . \'/' . $vendor . '/' . $name, 'array($vendorDir . \'/' . $vendor . '/' . $name . '-' . $version, $line );
705: $f[ $num ] = $line;
706: endforeach;
707: file_put_contents( "{$installDir}/vendor/composer/{$file}",
708: implode( '', $f ) );
709: }
710: endforeach;
711: $this->log->log( "Rewrote Composer autoload file for workflow.", 'INFO', 'console' );
712:
713: if ( ! file_exists( "{$destination}/{$vendor}/{$name}-{$version}" ) ) {
714: if ( ! file_exists( "{$destination}/{$vendor}" ) )
715: mkdir( "{$destination}/{$vendor}", 0775, TRUE );
716: rename( "{$installDir}/vendor/{$vendor}/{$name}", "{$destination}/{$vendor}/{$name}-{$version}" );
717: }
718: endforeach;
719: if ( ! file_exists( "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}" ) )
720: mkdir( "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}", 0775, TRUE );
721:
722: if ( ! file_exists( "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}/packages.json" ) ) {
723: $data = str_replace( '\/', '/', json_encode( $installed ) );
724: file_put_contents( "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}/packages.json", $data );
725: }
726:
727: rename( "{$installDir}/vendor/composer", "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}/composer" );
728: rename( "{$installDir}/vendor/autoload.php", "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}/autoload.php" );
729: file_put_contents( "{$this->data}/data/assets/php/composer/bundles/{$this->bundle}/composer.json", $json );
730:
731: $this->log->log( "Successfully installed composer packages. Cleaning up....", 'INFO', 'console' );
732:
733: $this->rrmdir( $installDir );
734:
735: return TRUE;
736: }
737:
738: 739: 740:
741:
742:
743:
744: 745: 746:
747:
748: 749: 750: 751: 752:
753: public function bundle() {
754: return $this->bundle;
755: }
756:
757: 758: 759: 760: 761: 762: 763:
764: private function readPlist( $plist, $key ) {
765: if ( ! file_exists( $plist ) )
766: return FALSE;
767:
768: return exec( "/usr/libexec/PlistBuddy -c 'Print :{$key}' '{$plist}'" );
769: }
770:
771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781:
782: public function download( $url, $file, $timeout = '5' ) {
783:
784:
785:
786: if ( ! ( file_exists( dirname( $file ) ) && is_dir( dirname( $file ) ) ) )
787: return FALSE;
788:
789: $ch = curl_init( $url );
790: $fp = fopen( $file , "w" );
791:
792: curl_setopt_array( $ch, array(
793: CURLOPT_FILE => $fp,
794: CURLOPT_HEADER => FALSE,
795: CURLOPT_FOLLOWLOCATION => TRUE,
796: CURLOPT_CONNECTTIMEOUT => $timeout
797: ) );
798:
799:
800:
801: if ( curl_exec( $ch ) === FALSE ) {
802: curl_close( $ch );
803: fclose( $fp );
804: return curl_error( $ch );
805:
806:
807: }
808:
809: $this->log->log( "Downloading `{$url}` ...", 'INFO', 'console' );
810:
811: curl_close( $ch );
812: fclose( $fp );
813: return TRUE;
814: }
815:
816:
817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828:
829: public function log( $message, $level = 'INFO', $destination = '' ) {
830: $this->userLog->log( $message, $level, $destination, 3 );
831: }
832:
833: 834: 835: 836: 837: 838: 839: 840: 841: 842: 843: 844:
845: public function debug( $message, $destination = '' ) {
846: $this->userLog->log( $message, 'DEBUG', $destination, 3 );
847: }
848:
849: 850: 851: 852: 853: 854: 855: 856: 857: 858: 859: 860:
861: public function info( $message, $destination = '' ) {
862: $this->userLog->log( $message, 'INFO', $destination, 3 );
863: }
864:
865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875: 876:
877: public function warning( $message, $destination = '' ) {
878: $this->userLog->log( $message, 'WARNING', $destination, 3 );
879: }
880:
881: 882: 883: 884: 885: 886: 887: 888: 889: 890: 891: 892:
893: public function error( $message, $destination = '' ) {
894: $this->userLog->log( $message, 'ERROR', $destination, 3 );
895: }
896:
897: 898: 899: 900: 901: 902: 903: 904: 905: 906: 907: 908:
909: public function critical( $message, $destination = '' ) {
910: $this->userLog->log( $message, 'CRITICAL', $destination, 3 );
911: }
912:
913: 914: 915: 916: 917: 918: 919: 920: 921: 922:
923: public function console( $message, $level = 'INFO' ) {
924: $this->userLog->log( $message, $level, 'console', 3 );
925: }
926:
927: 928: 929: 930: 931: 932: 933: 934: 935: 936:
937: public function rrmdir( $path ) {
938:
939: $files = array_diff( scandir( $path ), array( '.', '..' ) );
940: foreach ( $files as $file ) {
941: if ( is_dir( "{$path}/{$file}" ) )
942: $this->rrmdir( "{$path}/{$file}" );
943: else if ( file_exists( "{$path}/{$file}" ) )
944: unlink( "{$path}/{$file}" );
945: else {
946: echo "Removing dir error... uh..." . PHP_EOL;
947: }
948: }
949: return rmdir( $path );
950: }
951:
952: 953: 954: 955: 956: 957: 958: 959: 960: 961: 962: 963: 964: 965: 966: 967:
968: public function gatekeeper( $name, $path, $message = '', $icon = '' ) {
969:
970: $assetCache = "{$this->cache}/utilities";
971:
972:
973: if ( ! ( ( file_exists( $assetCache ) && is_dir( $assetCache ) ) ) )
974: mkdir( $assetCache, 0775, TRUE );
975:
976:
977: $key = md5( "{$name}-{$version}-{$type}-{$json}" );
978: $cachePath = "{$assetCache}/{$key}";
979:
980: if ( file_exists( "$cachePath" ) ) {
981: $path = file_get_contents( $cachePath );
982: if ( file_exists( $path ) ) {
983:
984: return $path;
985: }
986: }
987:
988:
989:
990:
991: $gatekeeper = realpath( __DIR__ ) . '/includes/gatekeeper.sh';
992:
993: exec( "bash '{$gatekeeper}' '{$name}' '{$path}' '{$message}' '{$icon}' '{$this->bundle}'", $output, $status );
994:
995:
996:
997: if ( $status == 0 ) {
998: file_put_contents( $cachePath, $path );
999: return $path;
1000: }
1001:
1002:
1003:
1004:
1005:
1006: $this->log->log( "Bundler Error: '{$name}' is needed to properly run " .
1007: "this workflow, and it must be whitelisted for Gatekeeper. You " .
1008: "either denied the request, or another error occured with " .
1009: " the Gatekeeper script.", 'ERROR', 'both' );
1010:
1011:
1012: return FALSE;
1013: }
1014:
1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025: 1026:
1027: public function register( $asset, $version ) {
1028:
1029:
1030: if ( ( ! isset( $this->bundle ) ) || empty( $this->bundle ) )
1031: return FALSE;
1032:
1033:
1034: if ( ! file_exists( "{$this->data}/data/registry.json" ) ) {
1035: $registry = array();
1036: } else {
1037: if ( ! ( json_decode( file_get_contents( "{$this->data}/data/registry.json" ) ) ) ) {
1038:
1039: $registry = array();
1040: } else {
1041: $registry = json_decode( file_get_contents( "{$this->data}/data/registry.json" ), TRUE );
1042: }
1043: }
1044:
1045: if ( isset( $registry[ $asset ] ) ) {
1046: if ( ! array_key_exists( $version , $registry[ $asset ] ) ) {
1047: $registry[ $asset ][ $version ] = array();
1048: $update = TRUE;
1049: }
1050: if ( ! is_array( $registry[ $asset ][ $version] ) ) {
1051: $registry[ $asset ][ $version ] = array();
1052: }
1053: if ( ! in_array( $this->bundle , $registry[ $asset ][ $version ] ) ) {
1054: $registry[ $asset ][ $version ][] = $this->bundle;
1055: $update = TRUE;
1056: }
1057: } else {
1058: $registry[ $asset ] = array( $version => $this->bundle );
1059: $update = TRUE;
1060: }
1061:
1062: if ( $update ) file_put_contents( "{$this->data}/data/registry.json" , utf8_encode( json_encode( $registry ) ) );
1063:
1064: return TRUE;
1065: }
1066:
1067: 1068: 1069:
1070:
1071: 1072: 1073:
1074:
1075: 1076: 1077: 1078: 1079: 1080: 1081: 1082:
1083: public function notify( $title, $message, $icon = null ) {
1084: if ( gettype( $title ) !== 'string' || gettype( $message ) !== 'string' )
1085: return false;
1086:
1087: $client = $this->wrapper( 'CocoaDialog' );
1088: $icon_type = 'icon';
1089: if ( ( ! is_null( $icon ) ) && ( gettype( $icon ) === 'string' ) ) {
1090: if ( ! file_exists( $icon ) ) {
1091: if ( ! in_array( $icon, $client->global_icons ) ) {
1092: $icon_type = null;
1093: }
1094: } else {
1095: $icon_type = 'icon_file';
1096: }
1097: } else {
1098: $icon_type = null;
1099: }
1100: $notification = [
1101: 'title'=>$title,
1102: 'description'=>$message,
1103: 'alpha'=>1,
1104: 'background_top'=>'ffffff',
1105: 'background_bottom'=>'ffffff',
1106: 'border_color'=>'ffffff',
1107: 'text_color'=>'000000',
1108: 'no_growl'=>true,
1109: ];
1110: if ( ! is_null( $icon_type ) ) {
1111: $notification[$icon_type] = $icon;
1112: }
1113: $client->notify( $notification );
1114: return true;
1115:
1116: }
1117:
1118: 1119: 1120:
1121:
1122: }
1123: endif;
1124:
1125: