kodiak 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ module Kodiak
2
+ class Generator
3
+
4
+ attr_accessor :options
5
+
6
+ def initialize(options)
7
+ @options = options
8
+ end
9
+
10
+ def generate
11
+ if config_exists? && ! options[:force]
12
+ Kodiak::Notification.new "Kodiak config already exists in this directory. Use --force to overwrite.\n", "failure"
13
+ elsif (!config_exists?) || (config_exists? && options[:force])
14
+ copy_config
15
+ end
16
+ end
17
+
18
+ # check to see if Kodiak.yaml already exists in directory
19
+ def config_exists?
20
+ File.exists? Kodiak::CONFIG_FILENAME
21
+ end
22
+
23
+ # copy sample Kodiak.yaml to directory
24
+ def copy_config
25
+ FileUtils.cp_r "#{Kodiak::CONFIG_PATH}/#{Kodiak::CONFIG_FILENAME}", "#{Kodiak::CONFIG_FILENAME}", :remove_destination => true
26
+
27
+ # if logs exist already, don't overwrite them. Not even in force mode. Never ever.
28
+ if not File.exists? Kodiak::LOG_FILENAME
29
+ FileUtils.cp_r "#{Kodiak::CONFIG_PATH}/#{Kodiak::LOG_FILENAME}", "#{Kodiak::LOG_FILENAME}", :remove_destination => true
30
+ end
31
+
32
+ Kodiak::Notification.new "Kodiak configuration created at #{Kodiak::CONFIG_FILENAME}\n", "success"
33
+ system("open #{Kodiak::CONFIG_FILENAME}")
34
+ exit
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,65 @@
1
+ require 'appscript'
2
+ require 'term/ansicolor'
3
+ include Term::ANSIColor
4
+
5
+ module Kodiak
6
+ class Notification
7
+
8
+ attr_accessor :growl, :application, :icon, :default_notifications, :notifications, :type, :message
9
+
10
+ def initialize(message, type = "message")
11
+ @message = message
12
+ @type = type
13
+
14
+ console_notify
15
+
16
+ if Config::CONFIG['target_os'] =~ /darwin/i
17
+ @growl = Appscript.app("GrowlHelperApp");
18
+
19
+ if @growl.is_running?
20
+ growl_register
21
+ growl_notify
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+ def console_notify
28
+ case @type
29
+ when "success"
30
+ print @message.green
31
+ when "warning"
32
+ print @message.yellow
33
+ when "failure"
34
+ print @message.red
35
+ else
36
+ print @message.white
37
+ end
38
+ end
39
+
40
+
41
+ # trigger a growl notification
42
+ def growl_notify
43
+ options = { :title => @application,
44
+ :description => @message.gsub(/[\n]+/, ""),
45
+ :application_name => @application,
46
+ :image_from_location => @icon,
47
+ :sticky => false,
48
+ :priority => 0,
49
+ :with_name => notifications.first }
50
+ @growl.notify options
51
+ end
52
+
53
+
54
+ # register Kodiak as an application with Growl
55
+ def growl_register
56
+ @application = Kodiak::APP_NAME
57
+ @icon = "#{Kodiak::CONFIG_PATH}/#{Kodiak::CONFIG_ICON}"
58
+ @default_notifications = ["Kodiak Success"]
59
+ @notifications = ["Kodiak Success", "Kodiak Failure"]
60
+ @growl.register(:as_application => @application, :all_notifications => @notifications, :default_notifications => @default_notifications)
61
+ end
62
+
63
+
64
+ end
65
+ end
@@ -0,0 +1,129 @@
1
+ module Kodiak
2
+ class Transporter
3
+
4
+ attr_accessor :config, :options, :files, :pushed, :ignored
5
+
6
+ def initialize(config, options)
7
+ @config = config
8
+ @files = @config.files
9
+ @files = @config.files
10
+ @options = options
11
+ end
12
+
13
+
14
+ def transport(files = nil)
15
+ @pushed = []
16
+ @ignored = []
17
+ @files = files || @files
18
+ if @config.ftp?
19
+ ftp
20
+ else
21
+ local
22
+ end
23
+ end
24
+
25
+
26
+ def local
27
+ puts "\nPushing to [#{@options[:environment]}]"
28
+
29
+ @files.each do |file|
30
+
31
+ if @options[:force]
32
+ push file
33
+
34
+ elsif File.exists? file[:destination]
35
+ source_changed = File.ctime(file[:source])
36
+ destination_changed = File.ctime(file[:destination])
37
+
38
+ # check if destination is older than source
39
+ if (destination_changed <=> source_changed) == -1
40
+ push file
41
+ else
42
+ ignore file, "Destination file was newer than source."
43
+ end
44
+
45
+ else
46
+ push file
47
+ end
48
+ end
49
+
50
+ if ! @options[:quiet]
51
+ Kodiak::Notification.new "\nPushed #{@pushed.length} files, Ignored #{@ignored.length} files\n\n", "success"
52
+ else
53
+ puts "\nPushed #{@pushed.length} files, Ignored #{@ignored.length} files\n\n"
54
+ end
55
+
56
+ if @options[:verbose] && @ignored.length > 0
57
+ puts "Some files were ignored. Use --force to force overwrite.\n\n"
58
+ end
59
+
60
+ Kodiak.log :pushed => @pushed, :ignored => @ignored
61
+
62
+ end
63
+
64
+
65
+ def ftp
66
+ require 'net/ftp'
67
+ credentials = @config.ftp
68
+
69
+ puts "Connecting to #{credentials['server']}..."
70
+
71
+ Net::FTP.open credentials['server'] do |ftp|
72
+ ftp.login credentials['username'], credentials['password']
73
+ ftp.chdir credentials['path']
74
+
75
+ @files.each do |file|
76
+ source = file[:source]
77
+ destination = file[:destination]
78
+
79
+ if not File.directory? source
80
+ folders = destination.split("/")
81
+ filename = folders.pop
82
+
83
+ folders.each do |folder|
84
+ if not ftp.nlst.index(folder)
85
+ puts "- /#{folder} not found. Creating."
86
+ ftp.mkdir folder
87
+ end
88
+ puts "- opening directory /#{folder}"
89
+ ftp.chdir folder
90
+ end
91
+
92
+ puts "+ pushing #{filename}"
93
+ if File.directory? filename
94
+ ftp.mkdir filename
95
+ else
96
+ ftp.put source, filename
97
+ end
98
+ folders.length.times { ftp.chdir("..") }
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+
105
+ def push(file)
106
+ FileUtils.cp_r file[:source], file[:destination], :remove_destination => true
107
+
108
+ if @options[:verbose]
109
+ Kodiak::Notification.new "Pushed #{file[:source]} --> #{file[:destination]}\n"
110
+ else
111
+ puts " - Pushed #{file[:source]} --> #{file[:destination]}\n"
112
+ end
113
+
114
+ @pushed.push file
115
+ end
116
+
117
+ def ignore(file, reason)
118
+ file[:reason] = reason
119
+ if @options[:verbose]
120
+ Kodiak::Notification.new "Ignored #{file[:source]}\n - #{file[:reason]}\n"
121
+ else
122
+ puts "Ignored #{file[:source]}\n - #{file[:reason]}\n"
123
+ end
124
+
125
+ @ignored.push file
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,29 @@
1
+ module Kodiak
2
+
3
+ def self.log(params={})
4
+ pushed = params[:pushed]
5
+ ignored = params[:ignored]
6
+
7
+ file = File.open("#{Kodiak::LOG_FILENAME}", "a+")
8
+
9
+ time = Time.now.strftime("%A, %m/%d/%Y at %I:%M:%3N %p")
10
+ message = "#{time} | #{Kodiak.user['name']} (#{Kodiak.user['email']})\n"
11
+ message += "---------------------------------------------------------------------------------\n"
12
+ message += "Pushed #{pushed.length} files and ignored #{ignored.length} files\n"
13
+ message += "---------------------------------------------------------------------------------\n"
14
+
15
+ pushed.each do |file|
16
+ message += "Pushed [#{file[:source]}] --> [#{file[:destination]}]\n"
17
+ end
18
+
19
+ ignored.each do |file|
20
+ message += "Ignored #{file[:source]} because #{file[:reason].downcase}\n"
21
+ end
22
+
23
+ message += "\n\n\n"
24
+
25
+ file.write(message)
26
+ file.close
27
+ end
28
+
29
+ end
@@ -0,0 +1,37 @@
1
+ require 'directory_watcher'
2
+
3
+ module Kodiak
4
+ class Watcher
5
+
6
+ attr_accessor :config, :options, :files
7
+
8
+ def initialize(config, options)
9
+ @config = config
10
+ @files = config.files
11
+ @options = options
12
+ watch
13
+ end
14
+
15
+ def watch
16
+ transporter = Kodiak::Transporter.new(config, options)
17
+
18
+ dw = []
19
+ @files.each do |file|
20
+ dw = DirectoryWatcher.new '.', :glob => file[:source], :pre_load => true
21
+ dw.add_observer do |*args|
22
+ args.each do |event|
23
+ if event.type == :stable then transporter.transport [file] end
24
+ end
25
+ end
26
+ dw.interval = 0.25 # polling interval
27
+ dw.stable = 2 # mutiple of interval for 'stable' events
28
+ dw.start
29
+ end
30
+
31
+ puts "Kodiak server started"
32
+ STDIN.gets
33
+ dw.stop
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,451 @@
1
+ // require utils.hash
2
+ // require jquery
3
+
4
+ var Application = Application || function(data){
5
+
6
+ var self = this;
7
+ var fxspeed = 200;
8
+ var hash = new Utils.Hash();
9
+ var $loading = $("#loading");
10
+
11
+ //
12
+
13
+ self.initialize = function(){
14
+ self.map = new Map(data.map, "map");
15
+ self.panels.init();
16
+ self.layers.init();
17
+ self.overlays.init();
18
+ self.observe();
19
+ return self;
20
+ }
21
+
22
+ //
23
+
24
+ self.observe = function(){
25
+
26
+ $("a.flyout-trigger").live('click',function(e){
27
+ e.preventDefault();
28
+ var href = $(this).attr("href");
29
+ var $remote = $(href);
30
+
31
+
32
+
33
+
34
+ if( $remote.is(':hidden') ){
35
+ $remote.siblings('.flyout').slideUp(fxspeed);
36
+ $remote.slideDown(fxspeed);
37
+ }
38
+ else {
39
+ $remote.slideUp(fxspeed);
40
+ }
41
+ });
42
+ return self;
43
+ }
44
+
45
+
46
+
47
+
48
+
49
+
50
+ //
51
+
52
+ self.panels = {
53
+
54
+ init : function(){
55
+ this.build();
56
+ this.observe();
57
+ },
58
+
59
+ build : function(){
60
+
61
+ if( hash.element() ) {
62
+ var $panel = $(hash.element());
63
+ self.panels.show($panel);
64
+ } else {
65
+ $panel = $('#panel .panel').eq(0);
66
+ self.panels.show($panel);
67
+ }
68
+
69
+ },
70
+
71
+ observe : function(){
72
+
73
+ hash.onChange( function(){
74
+ var $panel = $(hash.element());
75
+ self.panels.show($panel);
76
+ });
77
+
78
+ $('.hash-trigger').live('click', function(e){
79
+ e.preventDefault();
80
+ e.stopPropagation();
81
+ var href = $(this).attr("href");
82
+ hash.set(href);
83
+ });
84
+
85
+ $('.panel').live('click',function(e){
86
+ if ( $(this).hasClass("active") ) {
87
+ e.stopPropagation();
88
+
89
+ var id = $(this).attr("id");
90
+
91
+ if ( id ) {
92
+ hash.set(id);
93
+ }
94
+
95
+ } else {
96
+ return false;
97
+ }
98
+ });
99
+ },
100
+
101
+ show : function($panel){
102
+ var fxs = 200;
103
+ var animation = {};
104
+ var css = {};
105
+
106
+ if ( $panel.parents('.panel').length ) {
107
+ animation.opacity = 1;
108
+
109
+ if ( $panel.parents('.panel').length == 1 ){
110
+ animation.left = "80px";
111
+ }
112
+ else {
113
+ animation.left = "20px";
114
+ }
115
+
116
+ if( $panel.is(':hidden') ){
117
+ css.display = "block";
118
+ css.opacity = 0;
119
+ }
120
+ }
121
+
122
+ $panel.parents('.panel').each(function(){
123
+ var css = {
124
+ display : 'block',
125
+ opacity : 1
126
+ };
127
+ if ( $(this).parents('.panel').length == 1 ){
128
+ css.left = "80px";
129
+ }
130
+ else {
131
+ css.left = "0px";
132
+ }
133
+ $(this).css(css).addClass("inactive");
134
+ });
135
+
136
+ $panel.css(css).animate(animation, fxs, function(){
137
+ $panel.removeClass("inactive").addClass("active");
138
+ });
139
+
140
+ $panel.siblings('.panel').each(function(){
141
+ $(this).removeClass("active").addClass("inactive").fadeOut(fxs, function(){
142
+ $(this).css("left","-100%");
143
+ });
144
+ });
145
+
146
+ $panel.children('.panel').each(function(){
147
+ $(this).removeClass("active").addClass("inactive").fadeOut(fxs, function(){
148
+ $(this).css("left","-100%");
149
+ });
150
+ });
151
+ }
152
+
153
+ };
154
+
155
+ //
156
+
157
+ self.layers = {
158
+
159
+ init : function(){
160
+ this.build();
161
+ this.observe();
162
+ },
163
+
164
+ build : function(){
165
+
166
+ self.loader.start();
167
+
168
+ var layers = self.map.layers;
169
+ self.map.layers = {};
170
+
171
+ for ( var index in layers ) {
172
+ var layer = layers[index];
173
+ self.map.layers[layer.id] = new Layer(layer);
174
+ }
175
+
176
+ self.layers.refresh();
177
+ },
178
+
179
+
180
+ observe : function(){
181
+
182
+ $(".layer-toggle").live('click', function(e){
183
+ e.preventDefault();
184
+ var id = $(this).attr("rel");
185
+ var layer = self.map.layers[id];
186
+ self.layers.toggle(layer, $(this));
187
+ });
188
+
189
+ $('.delete-layer').live('click', function(e){
190
+ e.preventDefault();
191
+ e.stopPropagation();
192
+ var href = $(this).attr("href");
193
+ var id = $(this).attr("data-layer-id");
194
+ var layer = self.map.layers[id];
195
+ if (confirm("Are you sure?")) {
196
+ self.layers.remove(layer, href);
197
+ }
198
+ });
199
+
200
+ $('#new-layer form').submit(function(e){
201
+ e.preventDefault();
202
+ self.loader.start();
203
+ var $map_id = $(this).children("input[name='map_id']");
204
+ var $name = $(this).children("input[name='name']");
205
+
206
+ var data = {
207
+ map_id : $map_id.val(),
208
+ name : $name.val()
209
+ }
210
+
211
+ $.post("/api/layers/create", data,
212
+ function(layer) {
213
+ self.map.layers[layer.id] = new Layer(layer);
214
+ $('#new-layer').slideUp(fxspeed);
215
+ $name.val('');
216
+ self.layers.refresh();
217
+ }, 'json'
218
+ );
219
+
220
+ });
221
+
222
+ },
223
+
224
+
225
+ refresh : function(){
226
+ self.loader.start();
227
+
228
+ $("#layers > ul.nav").fadeOut(fxspeed, function(){
229
+ $(this).remove();
230
+ });
231
+
232
+ $("#layers > .panel").fadeOut(fxspeed, function(){
233
+ $(this).remove();
234
+ });
235
+
236
+ $.post("/api/layers/index", {},
237
+ function(response) {
238
+ $("#layers").append(response);
239
+ self.panels.build();
240
+ self.loader.stop();
241
+ }
242
+ );
243
+ },
244
+
245
+
246
+ toggle : function(layer, $element){
247
+
248
+ if ( layer.hidden ) {
249
+ layer.show();
250
+ $element.addClass('active');
251
+ }
252
+ else {
253
+ layer.hide();
254
+ $element.removeClass('active');
255
+ }
256
+
257
+ },
258
+
259
+ remove : function(layer, href){
260
+ self.loader.start();
261
+ layer.hide();
262
+ var url = "/api/layers/delete/" + layer.id;
263
+ $.post(url, {}, function(response){
264
+ self.loader.stop();
265
+ hash.set(href);
266
+ var $anchor = $("#layers > ul.nav > li > a[rel='" + layer.id + "']");
267
+ var $li = $anchor.parent('li');
268
+ $li.delay(fxspeed).fadeOut(fxspeed);
269
+ });
270
+ }
271
+
272
+ };
273
+
274
+ //
275
+
276
+ self.overlays = {
277
+
278
+ init : function(){
279
+ this.build();
280
+ this.observe();
281
+ },
282
+
283
+ build : function(){
284
+ for ( var index in self.map.layers ) {
285
+ var layer = self.map.layers[index];
286
+
287
+ console.log(layer);
288
+
289
+
290
+ var overlays = layer.overlays;
291
+
292
+ layer.overlays = {};
293
+
294
+ for ( var index in overlays ) {
295
+ var overlay = overlays[index];
296
+ switch ( overlay.type ) {
297
+ case 'polygon' :
298
+ layer.overlays[overlay.id] = new Polygon(overlay);
299
+ break;
300
+ case 'marker' :
301
+ layer.overlays[overlay.id] = new Marker(overlay);
302
+ break;
303
+ case 'line' :
304
+ layer.overlays[overlay.id] = new Line(overlay);
305
+ break;
306
+ }
307
+ }
308
+ }
309
+
310
+
311
+ },
312
+
313
+ observe : function(){
314
+
315
+ $(".draw-overlay").click(function(e){
316
+ e.preventDefault();
317
+
318
+ var layer_id = $(this).siblings("input[name='layer_id']").val();
319
+
320
+ overlay = map.layers[layer_id].addOverlay({
321
+ layer_id : layer_id,
322
+ points: [{ lat: 0, lng: 0 },{ lat: 0, lng: 0 }],
323
+ strokeColor: "#FF00FF",
324
+ strokeOpacity: 0,
325
+ strokeWeight: 0,
326
+ fillColor: "#F0F",
327
+ fillOpacity: 0.5
328
+ });
329
+
330
+ overlay.draw();
331
+ });
332
+
333
+ $(".clear-overlay").click(function(e){
334
+ e.preventDefault();
335
+ overlay.remove();
336
+ });
337
+
338
+ $(".save-overlay").click(function(e){
339
+ e.preventDefault();
340
+ var name = $(this).siblings("input[name='name']").val();
341
+ if ( name == "" ){
342
+ alert("Please provide a name for this overlay");
343
+ return false;
344
+ }
345
+ else {
346
+ overlay.name = name;
347
+ self.overlays.save(overlay);
348
+ }
349
+ });
350
+
351
+ },
352
+
353
+ save : function(overlay){
354
+ self.loader.start();
355
+
356
+ var data = {
357
+ name : overlay.name,
358
+ layer_id : overlay.data.layer_id
359
+ };
360
+
361
+ $.post("/api/overlays/create", data,
362
+ function(data) {
363
+ overlay.id = data.id;
364
+
365
+ var points = overlay.data.points;
366
+
367
+ for ( var index in points ) {
368
+ points[index].overlay_id = overlay.id;
369
+ }
370
+
371
+ $.post("/api/points/create", { points: points },
372
+ function(response) {
373
+ self.loader.stop();
374
+ }
375
+ );
376
+ }
377
+ );
378
+ },
379
+
380
+ remove : function(overlay){
381
+
382
+ }
383
+
384
+ };
385
+
386
+
387
+
388
+
389
+ //
390
+
391
+ self.loader = {
392
+
393
+ start : function(){
394
+ $loading.fadeIn(fxspeed);
395
+ },
396
+
397
+ stop : function(){
398
+ $loading.delay(500).fadeOut(fxspeed);
399
+ }
400
+
401
+ };
402
+
403
+ //
404
+
405
+
406
+
407
+
408
+ // self.map.canvas.setOptions({ draggableCursor: 'crosshair' });
409
+ //
410
+ // self.data.paths = [];
411
+ // self.data.points = [];
412
+ //
413
+ // google.maps.event.addListener(self.map.canvas, 'click', function(mdEvent) {
414
+ //
415
+ // google.maps.event.addListener(self.map.canvas, 'mousemove', function(event) {
416
+ // self.addPoint({ lat: event.latLng.lat(), lng: event.latLng.lng() });
417
+ // });
418
+ //
419
+ // google.maps.event.addListener(self.map.canvas, 'click', function(event) {
420
+ // google.maps.event.clearListeners(self.map.canvas);
421
+ // google.maps.event.clearListeners(self.polygon);
422
+ // });
423
+ //
424
+ // google.maps.event.addListener(self.polygon, 'mousemove', function(event) {
425
+ // self.addPoint({ lat: event.latLng.lat(), lng: event.latLng.lng() });
426
+ // });
427
+ //
428
+ // google.maps.event.addListener(self.polygon, 'click', function(event) {
429
+ // google.maps.event.clearListeners(map.canvas);
430
+ // google.maps.event.clearListeners(self.polygon);
431
+ // });
432
+ //
433
+ // });
434
+
435
+
436
+
437
+
438
+
439
+
440
+
441
+
442
+
443
+
444
+
445
+
446
+
447
+
448
+
449
+
450
+ return self.initialize();
451
+ };