appsendr 0.0.6 → 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Manifest DELETED
@@ -1,25 +0,0 @@
1
- Manifest
2
- README.rdoc
3
- Rakefile
4
- bin/appsendr
5
- lib/appsendr.rb
6
- lib/appsendr/binary_plist.rb
7
- lib/appsendr/client.rb
8
- lib/appsendr/command.rb
9
- lib/appsendr/commands/app.rb
10
- lib/appsendr/commands/auth.rb
11
- lib/appsendr/commands/base.rb
12
- lib/appsendr/commands/build.rb
13
- lib/appsendr/commands/collaborators.rb
14
- lib/appsendr/commands/common.rb
15
- lib/appsendr/commands/deploy.rb
16
- lib/appsendr/commands/groups.rb
17
- lib/appsendr/commands/help.rb
18
- lib/appsendr/commands/portal.rb
19
- lib/appsendr/commands/testers.rb
20
- lib/appsendr/commands/version.rb
21
- lib/appsendr/constants.rb
22
- lib/appsendr/helpers.rb
23
- lib/appsendr/progressbar.rb
24
- portal.rb
25
- terms
@@ -1,49 +0,0 @@
1
- # == Synopsis
2
- # Ruby command-line app that interacts with Xcode and the AppSendr webservice
3
- #
4
- # == Examples
5
- # Calling this in a Xcode project directory will build the project with an active configuration of AdHoc
6
- # appsendr build AdHoc
7
- #
8
- # Other examples:
9
- # appsendr deploy AdHoc
10
- #
11
- # == Usage
12
- # appsendr [options]
13
- #
14
- #
15
- # == Author
16
- # Nolan Brown
17
- #
18
- # == Copyright
19
- # Copyright (c) 2010 Nolan Brown. Licensed under the MIT License:
20
- # http://www.opensource.org/licenses/mit-license.php
21
-
22
-
23
- === General Commands
24
-
25
- help # show this usage
26
- version # show the gem version
27
-
28
- list # list your apps
29
- link # link your app with an exsiting one in appsendr
30
- create <name> # create a new app
31
-
32
- url # get the latest version install url. pass --copy to copy to the clipboard
33
-
34
- build <active configuration> # build your xcode project and deploy
35
- build:clean # clean your xcode project
36
-
37
- deploy <active configuration> # deploy the current build. pass --notify to send notification to all testers
38
-
39
- testers # list testers
40
- testers:add <email> <name> # add a tester
41
- testers:remove <email> # remove a tester
42
- testers:clear # remove all testers
43
- testers:notify <group> # notify testers about the latest build. group is optional.
44
-
45
- groups # list groups
46
-
47
- collaborators # list collaborators
48
- collaborators:add <email> # add collaborators
49
- collaborators:remove <email> # add collaborators
@@ -1,494 +0,0 @@
1
- require "date"
2
- require "nkf"
3
- require "set"
4
- require "stringio"
5
-
6
- # Binary Plist implementation is from @schlueter
7
- # https://github.com/schlueter/Ipa-Reader/blob/master/lib/ipa_reader/plist_binary.rb
8
- #
9
-
10
- module AppSendr
11
- module Plist
12
- module Binary
13
- # Encodes +obj+ as a binary property list. If +obj+ is an Array, Hash, or
14
- # Set, the property list includes its contents.
15
- def self.binary_plist(obj)
16
- encoded_objs = flatten_collection(obj)
17
- ref_byte_size = min_byte_size(encoded_objs.length - 1)
18
- encoded_objs.collect! {|o| binary_plist_obj(o, ref_byte_size)}
19
- # Write header and encoded objects.
20
- plist = "bplist00" + encoded_objs.join
21
- # Write offset table.
22
- offset_table_addr = plist.length
23
- offset = 8
24
- offset_table = []
25
- encoded_objs.each do |o|
26
- offset_table << offset
27
- offset += o.length
28
- end
29
- offset_byte_size = min_byte_size(offset)
30
- offset_table.each do |offset|
31
- plist += pack_int(offset, offset_byte_size)
32
- end
33
- # Write trailer.
34
- plist += "\0\0\0\0\0\0" # Six unused bytes
35
- plist += [
36
- offset_byte_size,
37
- ref_byte_size,
38
- encoded_objs.length >> 32, encoded_objs.length & 0xffffffff,
39
- 0, 0, # Index of root object
40
- offset_table_addr >> 32, offset_table_addr & 0xffffffff
41
- ].pack("CCNNNNNN")
42
- plist
43
- end
44
-
45
- def self.decode_binary_plist(plist)
46
- # Check header.
47
- unless plist[0, 6] == "bplist"
48
- raise ArgumentError, "argument is not a binary property list"
49
- end
50
- version = plist[6, 2]
51
- unless version == "00"
52
- raise ArgumentError,
53
- "don't know how to decode format version #{version}"
54
- end
55
- # Read trailer.
56
- trailer = plist[-26, 26].unpack("CCNNNNNN")
57
- offset_byte_size = trailer[0]
58
- ref_byte_size = trailer[1]
59
- encoded_objs_length = combine_ints(32, trailer[2], trailer[3])
60
- root_index = combine_ints(32, trailer[4], trailer[5])
61
- offset_table_addr = combine_ints(32, trailer[6], trailer[7])
62
- # Decode objects.
63
- root_offset = offset_for_index(plist, offset_table_addr,
64
- offset_byte_size, root_index)
65
- root_obj = decode_binary_plist_obj(plist, root_offset, ref_byte_size)
66
- unflatten_collection(root_obj, [root_obj], plist, offset_table_addr,
67
- offset_byte_size, ref_byte_size)
68
- end
69
-
70
- private
71
-
72
- # These marker bytes are prefixed to objects in a binary property list to
73
- # indicate the type of the object.
74
- CFBinaryPlistMarkerNull = 0x00 # :nodoc:
75
- CFBinaryPlistMarkerFalse = 0x08 # :nodoc:
76
- CFBinaryPlistMarkerTrue = 0x09 # :nodoc:
77
- CFBinaryPlistMarkerFill = 0x0F # :nodoc:
78
- CFBinaryPlistMarkerInt = 0x10 # :nodoc:
79
- CFBinaryPlistMarkerReal = 0x20 # :nodoc:
80
- CFBinaryPlistMarkerDate = 0x33 # :nodoc:
81
- CFBinaryPlistMarkerData = 0x40 # :nodoc:
82
- CFBinaryPlistMarkerASCIIString = 0x50 # :nodoc:
83
- CFBinaryPlistMarkerUnicode16String = 0x60 # :nodoc:
84
- CFBinaryPlistMarkerUID = 0x80 # :nodoc:
85
- CFBinaryPlistMarkerArray = 0xA0 # :nodoc:
86
- CFBinaryPlistMarkerSet = 0xC0 # :nodoc:
87
- CFBinaryPlistMarkerDict = 0xD0 # :nodoc:
88
-
89
- # POSIX uses a reference time of 1970-01-01T00:00:00Z; Cocoa's reference
90
- # time is in 2001. This interval is for converting between the two.
91
- NSTimeIntervalSince1970 = 978307200.0 # :nodoc:
92
-
93
- # Takes an object (nominally a collection, like an Array, Set, or Hash, but
94
- # any object is acceptable) and flattens it into a one-dimensional array.
95
- # Non-collection objects appear in the array as-is, but the contents of
96
- # Arrays, Sets, and Hashes are modified like so: (1) The contents of the
97
- # collection are added, one-by-one, to the one-dimensional array. (2) The
98
- # collection itself is modified so that it contains indexes pointing to the
99
- # objects in the one-dimensional array. Here's an example with an Array:
100
- #
101
- # ary = [:a, :b, :c]
102
- # flatten_collection(ary) # => [[1, 2, 3], :a, :b, :c]
103
- #
104
- # In the case of a Hash, keys and values are both appended to the one-
105
- # dimensional array and then replaced with indexes.
106
- #
107
- # hsh = {:a => "blue", :b => "purple", :c => "green"}
108
- # flatten_collection(hsh)
109
- # # => [{1 => 2, 3 => 4, 5 => 6}, :a, "blue", :b, "purple", :c, "green"]
110
- #
111
- # An object will never be added to the one-dimensional array twice. If a
112
- # collection refers to an object more than once, the object will be added
113
- # to the one-dimensional array only once.
114
- #
115
- # ary = [:a, :a, :a]
116
- # flatten_collection(ary) # => [[1, 1, 1], :a]
117
- #
118
- # The +obj_list+ and +id_refs+ parameters are private; they're used for
119
- # descending into sub-collections recursively.
120
- def self.flatten_collection(collection, obj_list = [], id_refs = {})
121
- case collection
122
- when Array, Set
123
- if id_refs[collection.object_id]
124
- return obj_list[id_refs[collection.object_id]]
125
- end
126
- obj_refs = collection.class.new
127
- id_refs[collection.object_id] = obj_list.length
128
- obj_list << obj_refs
129
- collection.each do |obj|
130
- flatten_collection(obj, obj_list, id_refs)
131
- obj_refs << id_refs[obj.object_id]
132
- end
133
- return obj_list
134
- when Hash
135
- if id_refs[collection.object_id]
136
- return obj_list[id_refs[collection.object_id]]
137
- end
138
- obj_refs = {}
139
- id_refs[collection.object_id] = obj_list.length
140
- obj_list << obj_refs
141
- collection.each do |key, value|
142
- key = key.to_s if key.is_a?(Symbol)
143
- flatten_collection(key, obj_list, id_refs)
144
- flatten_collection(value, obj_list, id_refs)
145
- obj_refs[id_refs[key.object_id]] = id_refs[value.object_id]
146
- end
147
- return obj_list
148
- else
149
- unless id_refs[collection.object_id]
150
- id_refs[collection.object_id] = obj_list.length
151
- obj_list << collection
152
- end
153
- return obj_list
154
- end
155
- end
156
-
157
- def self.unflatten_collection(collection, obj_list, plist,
158
- offset_table_addr, offset_byte_size, ref_byte_size)
159
- case collection
160
- when Array, Set
161
- collection.collect! do |index|
162
- if obj = obj_list[index]
163
- obj
164
- else
165
- offset = offset_for_index(plist, offset_table_addr, offset_byte_size,
166
- index)
167
- obj = decode_binary_plist_obj(plist, offset, ref_byte_size)
168
- obj_list[index] = obj
169
- unflatten_collection(obj, obj_list, plist, offset_table_addr,
170
- offset_byte_size, ref_byte_size)
171
- end
172
- end
173
- when Hash
174
- hsh = {}
175
- collection.each do |key, value|
176
- unless key_obj = obj_list[key]
177
- offset = offset_for_index(plist, offset_table_addr, offset_byte_size,
178
- key)
179
- key_obj = decode_binary_plist_obj(plist, offset, ref_byte_size)
180
- obj_list[key] = key_obj
181
- key_obj = unflatten_collection(key_obj, obj_list, plist,
182
- offset_table_addr, offset_byte_size, ref_byte_size)
183
- end
184
- unless value_obj = obj_list[value]
185
- offset = offset_for_index(plist, offset_table_addr, offset_byte_size,
186
- value)
187
- value_obj = decode_binary_plist_obj(plist, offset, ref_byte_size)
188
- obj_list[value] = value_obj
189
- value_obj = unflatten_collection(value_obj, obj_list, plist,
190
- offset_table_addr, offset_byte_size, ref_byte_size)
191
- end
192
- hsh[key_obj] = value_obj
193
- end
194
- collection.replace(hsh)
195
- end
196
- return collection
197
- end
198
-
199
- # Returns a binary property list fragment that represents +obj+. The
200
- # returned string is not a complete property list, just a fragment that
201
- # describes +obj+, and is not useful without a header, offset table, and
202
- # trailer.
203
- #
204
- # The following classes are recognized: String, Float, Integer, the Boolean
205
- # classes, Time, IO, StringIO, Array, Set, and Hash. IO and StringIO
206
- # objects are rewound, read, and the contents stored as data (i.e., Cocoa
207
- # applications will decode them as NSData). All other classes are dumped
208
- # with Marshal and stored as data.
209
- #
210
- # Note that subclasses of the supported classes will be encoded as though
211
- # they were the supported superclass. Thus, a subclass of (for example)
212
- # String will be encoded and decoded as a String, not as the subclass:
213
- #
214
- # class ExampleString < String
215
- # ...
216
- # end
217
- #
218
- # s = ExampleString.new("disquieting plantlike mystery")
219
- # encoded_s = binary_plist_obj(s)
220
- # decoded_s = decode_binary_plist_obj(encoded_s)
221
- # puts decoded_s.class # => String
222
- #
223
- # +ref_byte_size+ is the number of bytes to use for storing references to
224
- # other objects.
225
- def self.binary_plist_obj(obj, ref_byte_size = 4)
226
- case obj
227
- when String
228
- obj = obj.to_s if obj.is_a?(Symbol)
229
- # This doesn't really work. NKF's guess method is really, really bad
230
- # at discovering UTF8 when only a handful of characters are multi-byte.
231
- encoding = NKF.guess2(obj)
232
- if encoding == NKF::ASCII && obj =~ /[\x80-\xff]/
233
- encoding = NKF::UTF8
234
- end
235
- if [NKF::ASCII, NKF::BINARY, NKF::UNKNOWN].include?(encoding)
236
- result = (CFBinaryPlistMarkerASCIIString |
237
- (obj.length < 15 ? obj.length : 0xf)).chr
238
- result += binary_plist_obj(obj.length) if obj.length >= 15
239
- result += obj
240
- return result
241
- else
242
- # Convert to UTF8.
243
- if encoding == NKF::UTF8
244
- utf8 = obj
245
- else
246
- utf8 = NKF.nkf("-m0 -w", obj)
247
- end
248
- # Decode each character's UCS codepoint.
249
- codepoints = []
250
- i = 0
251
- while i < utf8.length
252
- byte = utf8[i]
253
- if byte & 0xe0 == 0xc0
254
- codepoints << ((byte & 0x1f) << 6) + (utf8[i+1] & 0x3f)
255
- i += 1
256
- elsif byte & 0xf0 == 0xe0
257
- codepoints << ((byte & 0xf) << 12) + ((utf8[i+1] & 0x3f) << 6) +
258
- (utf8[i+2] & 0x3f)
259
- i += 2
260
- elsif byte & 0xf8 == 0xf0
261
- codepoints << ((byte & 0xe) << 18) + ((utf8[i+1] & 0x3f) << 12) +
262
- ((utf8[i+2] & 0x3f) << 6) + (utf8[i+3] & 0x3f)
263
- i += 3
264
- else
265
- codepoints << byte
266
- end
267
- if codepoints.last > 0xffff
268
- raise(ArgumentError, "codepoint too high - only the Basic Multilingual Plane can be encoded")
269
- end
270
- i += 1
271
- end
272
- # Return string of 16-bit codepoints.
273
- data = codepoints.pack("n*")
274
- result = (CFBinaryPlistMarkerUnicode16String |
275
- (codepoints.length < 15 ? codepoints.length : 0xf)).chr
276
- result += binary_plist_obj(codepoints.length) if codepoints.length >= 15
277
- result += data
278
- return result
279
- end
280
- when Float
281
- return (CFBinaryPlistMarkerReal | 3).chr + [obj].pack("G")
282
- when Integer
283
- nbytes = min_byte_size(obj)
284
- size_bits = { 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4 }[nbytes]
285
- return (CFBinaryPlistMarkerInt | size_bits).chr + pack_int(obj, nbytes)
286
- when TrueClass
287
- return CFBinaryPlistMarkerTrue.chr
288
- when FalseClass
289
- return CFBinaryPlistMarkerFalse.chr
290
- when Time
291
- return CFBinaryPlistMarkerDate.chr +
292
- [obj.to_f - NSTimeIntervalSince1970].pack("G")
293
- when IO, StringIO
294
- obj.rewind
295
- return binary_plist_data(obj.read)
296
- when Array
297
- # Must be an array of object references as returned by flatten_collection.
298
- result = (CFBinaryPlistMarkerArray | (obj.length < 15 ? obj.length : 0xf)).chr
299
- result += binary_plist_obj(obj.length) if obj.length >= 15
300
- result += obj.collect! { |i| pack_int(i, ref_byte_size) }.join
301
- when Set
302
- # Must be a set of object references as returned by flatten_collection.
303
- result = (CFBinaryPlistMarkerSet | (obj.length < 15 ? obj.length : 0xf)).chr
304
- result += binary_plist_obj(obj.length) if obj.length >= 15
305
- result += obj.to_a.collect! { |i| pack_int(i, ref_byte_size) }.join
306
- when Hash
307
- # Must be a table of object references as returned by flatten_collection.
308
- result = (CFBinaryPlistMarkerDict | (obj.length < 15 ? obj.length : 0xf)).chr
309
- result += binary_plist_obj(obj.length) if obj.length >= 15
310
- result += obj.keys.collect! { |i| pack_int(i, ref_byte_size) }.join
311
- result += obj.values.collect! { |i| pack_int(i, ref_byte_size) }.join
312
- else
313
- return binary_plist_data(Marshal.dump(obj))
314
- end
315
- end
316
-
317
- def self.decode_binary_plist_obj(plist, offset, ref_byte_size)
318
- case plist[offset]
319
- when CFBinaryPlistMarkerASCIIString..(CFBinaryPlistMarkerASCIIString | 0xf)
320
- length, offset = decode_length(plist, offset)
321
- return plist[offset, length]
322
- when CFBinaryPlistMarkerUnicode16String..(CFBinaryPlistMarkerUnicode16String | 0xf)
323
- length, offset = decode_length(plist, offset)
324
- codepoints = plist[offset, length * 2].unpack("n*")
325
- str = ""
326
- codepoints.each do |codepoint|
327
- if codepoint <= 0x7f
328
- ch = ' '
329
- ch[0] = to_i
330
- elsif codepoint <= 0x7ff
331
- ch = ' '
332
- ch[0] = ((codepoint & 0x7c0) >> 6) | 0xc0
333
- ch[1] = codepoint & 0x3f | 0x80
334
- else
335
- ch = ' '
336
- ch[0] = ((codepoint & 0xf000) >> 12) | 0xe0
337
- ch[1] = ((codepoint & 0xfc0) >> 6) | 0x80
338
- ch[2] = codepoint & 0x3f | 0x80
339
- end
340
- str << ch
341
- end
342
- return str
343
- when CFBinaryPlistMarkerReal | 3
344
- return plist[offset+1, 8].unpack("G").first
345
- when CFBinaryPlistMarkerInt..(CFBinaryPlistMarkerInt | 0xf)
346
- num_bytes = 2 ** (plist[offset] & 0xf)
347
- return unpack_int(plist[offset+1, num_bytes])
348
- when CFBinaryPlistMarkerTrue
349
- return true
350
- when CFBinaryPlistMarkerFalse
351
- return false
352
- when CFBinaryPlistMarkerDate
353
- secs = plist[offset+1, 8].unpack("G").first + NSTimeIntervalSince1970
354
- return Time.at(secs)
355
- when CFBinaryPlistMarkerData..(CFBinaryPlistMarkerData | 0xf)
356
- length, offset = decode_length(plist, offset)
357
- return StringIO.new(plist[offset, length])
358
- when CFBinaryPlistMarkerArray..(CFBinaryPlistMarkerArray | 0xf)
359
- ary = []
360
- length, offset = decode_length(plist, offset)
361
- length.times do
362
- ary << unpack_int(plist[offset, ref_byte_size])
363
- offset += ref_byte_size
364
- end
365
- return ary
366
- when CFBinaryPlistMarkerDict..(CFBinaryPlistMarkerDict | 0xf)
367
- hsh = {}
368
- keys = []
369
- length, offset = decode_length(plist, offset)
370
- length.times do
371
- keys << unpack_int(plist[offset, ref_byte_size])
372
- offset += ref_byte_size
373
- end
374
- length.times do |i|
375
- hsh[keys[i]] = unpack_int(plist[offset, ref_byte_size])
376
- offset += ref_byte_size
377
- end
378
- return hsh
379
- end
380
- end
381
-
382
- # Returns a binary property list fragment that represents a data object
383
- # with the contents of the string +data+. A Cocoa application would decode
384
- # this fragment as NSData. Like binary_plist_obj, the value returned by
385
- # this method is not usable by itself; it is only useful as part of a
386
- # complete binary property list with a header, offset table, and trailer.
387
- def self.binary_plist_data(data)
388
- result = (CFBinaryPlistMarkerData |
389
- (data.length < 15 ? data.length : 0xf)).chr
390
- result += binary_plist_obj(data.length) if data.length > 15
391
- result += data
392
- return result
393
- end
394
-
395
- # Determines the minimum number of bytes that is a power of two and can
396
- # represent the integer +i+. Raises a RangeError if the number of bytes
397
- # exceeds 16. Note that the property list format considers integers of 1,
398
- # 2, and 4 bytes to be unsigned, while 8- and 16-byte integers are signed;
399
- # thus negative integers will always require at least 8 bytes of storage.
400
- def self.min_byte_size(i)
401
- if i < 0
402
- i = i.abs - 1
403
- else
404
- if i <= 0xff
405
- return 1
406
- elsif i <= 0xffff
407
- return 2
408
- elsif i <= 0xffffffff
409
- return 4
410
- end
411
- end
412
- if i <= 0x7fffffffffffffff
413
- return 8
414
- elsif i <= 0x7fffffffffffffffffffffffffffffff
415
- return 16
416
- end
417
- raise(RangeError, "integer too big - exceeds 128 bits")
418
- end
419
-
420
- # Packs an integer +i+ into its binary representation in the specified
421
- # number of bytes. Byte order is big-endian. Negative integers cannot be
422
- # stored in 1, 2, or 4 bytes.
423
- def self.pack_int(i, num_bytes)
424
- if i < 0 && num_bytes < 8
425
- raise(ArgumentError, "negative integers require 8 or 16 bytes of storage")
426
- end
427
- case num_bytes
428
- when 1
429
- [i].pack("c")
430
- when 2
431
- [i].pack("n")
432
- when 4
433
- [i].pack("N")
434
- when 8
435
- [(i >> 32) & 0xffffffff, i & 0xffffffff].pack("NN")
436
- when 16
437
- [i >> 96, (i >> 64) & 0xffffffff, (i >> 32) & 0xffffffff,
438
- i & 0xffffffff].pack("NNNN")
439
- else
440
- raise(ArgumentError, "num_bytes must be 1, 2, 4, 8, or 16")
441
- end
442
- end
443
-
444
- def self.combine_ints(num_bits, *ints)
445
- i = ints.pop
446
- shift_bits = num_bits
447
- ints.reverse.each do |i_part|
448
- i += i_part << shift_bits
449
- shift_bits += num_bits
450
- end
451
- return i
452
- end
453
-
454
- def self.offset_for_index(plist, table_addr, offset_byte_size, index)
455
- offset = plist[table_addr + index * offset_byte_size, offset_byte_size]
456
- unpack_int(offset)
457
- end
458
-
459
- def self.unpack_int(s)
460
- case s.length
461
- when 1
462
- s.unpack("C").first
463
- when 2
464
- s.unpack("n").first
465
- when 4
466
- s.unpack("N").first
467
- when 8
468
- i = combine_ints(32, *(s.unpack("NN")))
469
- (i & 0x80000000_00000000 == 0) ?
470
- i :
471
- -(i ^ 0xffffffff_ffffffff) - 1
472
- when 16
473
- i = combine_ints(32, *(s.unpack("NNNN")))
474
- (i & 0x80000000_00000000_00000000_00000000 == 0) ?
475
- i :
476
- -(i ^ 0xffffffff_ffffffff_ffffffff_ffffffff) - 1
477
- else
478
- raise(ArgumentError, "length must be 1, 2, 4, 8, or 16 bytes")
479
- end
480
- end
481
-
482
- def self.decode_length(plist, offset)
483
- if plist[offset] & 0xf == 0xf
484
- offset += 1
485
- length = decode_binary_plist_obj(plist, offset, 0)
486
- offset += min_byte_size(length) + 1
487
- return length, offset
488
- else
489
- return (plist[offset] & 0xf), (offset + 1)
490
- end
491
- end
492
- end
493
- end
494
- end