zimt 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use system
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in zimt.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ task :default => :spec
4
+ task :spec do
5
+ require 'bacon'
6
+ Bacon.summary_on_exit
7
+ Dir.glob(File.join(File.dirname(__FILE__),'spec','*_spec.rb')).each {|f| load(f) }
8
+ end
data/bin/zimt ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/ruby
2
+ require 'rubygems'
3
+ require 'zimt'
4
+
5
+ Zimt::CLI.start
6
+
data/lib/zimt.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'open-uri'
4
+ require 'pathname'
5
+ require 'thor'
6
+ require "zimt/cli"
7
+ require "zimt/pbxproj"
8
+ require "zimt/sprinkle"
9
+ require "zimt/version"
10
+
11
+ module Zimt
12
+ def self.xcodeproj
13
+ @xcodeproj ||= find_xcodeproj
14
+ raise "Could not locate .xcodeproj" unless @xcodeproj
15
+ Pathname.new(@xcodeproj)
16
+ end
17
+
18
+ def self.pbxproj
19
+ path = Pathname.new(File.join(self.xcodeproj, 'project.pbxproj'))
20
+ @pbxproj ||= PBXProj.new(path)
21
+ end
22
+
23
+ def self.zimts_dir
24
+ Pathname.new(File.expand_path(File.join(self.xcodeproj, '..', 'zimts')))
25
+ end
26
+
27
+ private
28
+
29
+ def self.find_xcodeproj
30
+ given = ENV['ZIMT_XCODEPROJ']
31
+ return given if given && !given.empty?
32
+
33
+ previous = nil
34
+ current = File.expand_path(Dir.pwd)
35
+
36
+ until !File.directory?(current) || current == previous
37
+ # otherwise return the Gemfile if it's there
38
+ filenames = Dir.glob(File.join(current, '*.xcodeproj'))
39
+ raise "More than one .xcodeproj found: #{filenames}" if filenames.length > 1
40
+ filename = filenames.first
41
+ return filename if File.directory?(filename) and File.file?(File.join(filename, 'project.pbxproj'))
42
+ current, previous = File.expand_path("..", current), current
43
+ end
44
+ end
45
+
46
+ end
47
+
data/lib/zimt/cli.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Zimt
2
+ class CLI < Thor
3
+ desc "add SPRINKLE", "Adds the sprinkle"
4
+ def add(name)
5
+ sprinkle = Sprinkle.get(name)
6
+ sprinkle.install
7
+ rescue OpenURI::HTTPError
8
+ puts 'Sprinkle not found'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,300 @@
1
+ module Zimt
2
+ class PBXProj
3
+ def self.plutil(file)
4
+ `plutil -convert json -o - #{file}`
5
+ end
6
+
7
+ def randhex(length=1)
8
+ @buffer = ""
9
+ length.times do
10
+ @buffer << rand(16).to_s(16).upcase
11
+ end
12
+ @buffer
13
+ end
14
+
15
+ # Documentation on PBXObjectId by @tjw
16
+ # http://lists.apple.com/archives/projectbuilder-users/2003/Jan/msg00263.html
17
+ #
18
+ # ObjectId gets generated in the following format:
19
+ # +----------------------------------------------------------------------+
20
+ # | RANDOM | SEQ | TIME | PID | IP (2) |
21
+ # | byte byte | byte byte | byte byte byte byte | byte byte | byte byte |
22
+ # +----------------------------------------------------------------------+
23
+ # RANDOM = 2 bytes of random number for distribution
24
+ # SEQ = Unsigned short sequence counter that starts randomly.
25
+ # TIME = Seconds since epoch (1/1/1970)
26
+ # PID = Process ID
27
+ # This is only two bytes even though most pids are longs.
28
+ # Here you would take the lower 2 bytes.
29
+ # IP = IP Address of the machine (subnet.hostId)
30
+ def uuid
31
+ # TODO
32
+ @prefix ||= randhex(4)
33
+ @suffix ||= Time.now.to_i.to_s(16).upcase + randhex(8)
34
+ @count ||= rand(16**4)
35
+ @count += 1
36
+ if @count.to_s(16).length < 4
37
+ @count = @count * 16
38
+ end
39
+ uuid = "#{@prefix}#{@count.to_s(16).upcase}#{@suffix}"
40
+ if uuid.length != 24
41
+ puts "uuid length wrong: #{uuid}"
42
+ exit
43
+ end
44
+ uuid
45
+ end
46
+
47
+ attr_reader :content, :hash, :objects, :root
48
+ attr_accessor :position
49
+
50
+ def initialize(file)
51
+ @filename = file
52
+ @content = File.readlines(file)
53
+ self.parse
54
+ end
55
+
56
+ def parse
57
+ @hash = JSON.parse(PBXProj.plutil(@filename)).freeze
58
+ @objects = @hash['objects']
59
+ @root = PBXHash.new(self, @hash['rootObject'], @objects[@hash['rootObject']])
60
+ end
61
+
62
+ def save!
63
+ File.open(@filename, "w") { |f|
64
+ f.write(self.content.join(''))
65
+ }
66
+ end
67
+
68
+ def zimt_group
69
+ self.root.mainGroup.children.select{ |g| g.path == 'Zimt' }.first
70
+ end
71
+
72
+ def ensure_zimt_group
73
+ zimt_group = self.zimt_group
74
+ if zimt_group.nil?
75
+ self.add_zimt_group
76
+ end
77
+ end
78
+
79
+ # C5FE9B6F13BA7537004CCA66 = {
80
+ # isa = PBXGroup;
81
+ # children = (
82
+ # C5FE9B8413BA7537004CCA66 /* Sources */,
83
+ # C7826AD313D9137D00661EEC /* Resources */,
84
+ # C5FE9B7D13BA7537004CCA66 /* Frameworks */,
85
+ # C5FE9B7B13BA7537004CCA66 /* Products */,
86
+ # C5E20A8613F4507D00C5DDF3 /* Zimt */,
87
+ # );
88
+ # sourceTree = "<group>";
89
+ # };
90
+ def add_zimt_group
91
+ # Add Zimt reference to mainGroup
92
+ groupid = self.root.mainGroup.pbxid
93
+ scan_to "\t\t#{groupid}"
94
+ scan_to "\t\t\t);"
95
+ newgroup = self.uuid
96
+ self.content.insert(@position, "\t\t\t\t#{newgroup} /* Zimt */,\n")
97
+
98
+ # Find position for Zimt reference in PBXGRoup section
99
+ @position = 0
100
+ scan_to "/* Begin PBXGroup section */"
101
+ begin_position = @position
102
+ scan_to "/* End PBXGroup section */"
103
+ end_position = @position
104
+
105
+ @position = begin_position
106
+ while @position < end_position
107
+ line = self.content[@position]
108
+ if (line.end_with? " = {\n")
109
+ groupname = line.split(' ')[0]
110
+ if groupname > newgroup
111
+ break
112
+ end
113
+ end
114
+ @position += 1
115
+ end
116
+
117
+ # Add Zimt Group
118
+ self.content.insert(@position,
119
+ "\t\t#{newgroup} /* Zimt */ = {\n",
120
+ "\t\t\tisa = PBXGroup;\n",
121
+ "\t\t\tchildren = (\n",
122
+ "\t\t\t);\n",
123
+ "\t\t\tpath = Zimt;\n",
124
+ "\t\t\tsourceTree = \"<group>\";\n",
125
+ "\t\t};\n")
126
+
127
+ self.save!
128
+ self.parse
129
+ end
130
+
131
+ #/* Begin PBXFileReference section */
132
+ # C5D0CB021406C3AA002E631F /* Hans.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Hans.h; sourceTree = "<group>"; };
133
+ #/* End PBXFileReference section */
134
+ def add_file(file, file_type)
135
+ zimt_group_id = self.zimt_group.pbxid
136
+ # Add file to Zimt group
137
+ groupid = self.root.mainGroup.pbxid
138
+ scan_to "\t\t#{zimt_group_id}"
139
+ scan_to "\t\t\t);"
140
+ newgroup = self.uuid
141
+ self.content.insert(@position, "\t\t\t\t#{newgroup} /* #{file} */,\n")
142
+
143
+ # Find position for Zimt reference in PBXGRoup section
144
+ @position = 0
145
+ scan_to "/* Begin PBXFileReference section */"
146
+ begin_position = @position
147
+ scan_to "/* End PBXFileReference section */"
148
+ end_position = @position
149
+
150
+ @position = begin_position
151
+ while @position < end_position
152
+ line = self.content[@position]
153
+ groupname = line.split(' ')[0]
154
+ if groupname > newgroup
155
+ break
156
+ end
157
+ @position += 1
158
+ end
159
+
160
+ # Add Zimt Group
161
+ self.content.insert(@position,
162
+ "\t\t#{newgroup} /* #{file} */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = #{file_type}; path = #{file}; sourceTree = \"<group>\"; };\n")
163
+
164
+ self.save!
165
+ self.parse
166
+ return newgroup
167
+ end
168
+
169
+ def add_h_file(file)
170
+ add_file(file, "sourcecode.c.h")
171
+ end
172
+
173
+ def add_m_file(file)
174
+ fileref = self.add_file(file, "sourcecode.c.objc")
175
+ buildfileref = self.add_buildfile(file, fileref)
176
+ add_buildfileref_to_build_phase(file, buildfileref)
177
+ end
178
+
179
+ #/* Begin PBXBuildFile section */
180
+ # C53D93B21406F98300F4CDDE /* Hans.m in Sources */ = {isa = PBXBuildFile; fileRef = C53D93B11406F98300F4CDDE /* Hans.m */; };
181
+ #/* End PBXBuildFile section */
182
+ def add_buildfile(file, fileref)
183
+ newgroup = self.uuid
184
+ # Find position for Zimt reference in PBXGRoup section
185
+ @position = 0
186
+ scan_to "/* Begin PBXBuildFile section */"
187
+ begin_position = @position
188
+ scan_to "/* End PBXBuildFile section */"
189
+ end_position = @position
190
+
191
+ @position = begin_position
192
+ while @position < end_position
193
+ line = self.content[@position]
194
+ groupname = line.split(' ')[0]
195
+ if groupname > newgroup
196
+ break
197
+ end
198
+ @position += 1
199
+ end
200
+
201
+ # Add Zimt Group
202
+ self.content.insert(@position,
203
+ "\t\t#{newgroup} /* #{file} in Sources */ = {isa = PBXBuildFile; fileRef = #{fileref} /* #{file} */; };\n")
204
+
205
+ self.save!
206
+ self.parse
207
+ return newgroup
208
+ end
209
+
210
+ #/* Begin PBXSourcesBuildPhase section */
211
+ # 8D11072C0486CEB800E47090 /* Sources */ = {
212
+ # files = (
213
+ # C53D93B21406F98300F4CDDE /* Hans.m in Sources */,
214
+ # );
215
+ # C56D96C81385E71800070608 /* Sources */ = {
216
+ #/* End PBXSourcesBuildPhase section */
217
+ def add_buildfileref_to_build_phase(file, buildfileref)
218
+ @position = 0
219
+ scan_to "/* Begin PBXSourcesBuildPhase section */"
220
+ begin_position = @position
221
+ scan_to "/* End PBXSourcesBuildPhase section */"
222
+ end_position = @position
223
+
224
+ @position = begin_position
225
+ while @position < end_position
226
+ line = self.content[@position]
227
+ if (line.end_with? " = {\n")
228
+ old_position = @position
229
+ scan_to(" );\n")
230
+ self.content.insert(@position,
231
+ " #{buildfileref} /* #{file} in Sources */,\n")
232
+ @position = old_position + 1 # offset for added line
233
+ break
234
+ end
235
+ @position += 1
236
+ end
237
+
238
+ self.save!
239
+ self.parse
240
+ end
241
+
242
+ def scan_to(what)
243
+ @position ||= 0
244
+ while true
245
+ line = self.content[@position]
246
+ if line.nil?
247
+ raise "#{what} not found"
248
+ end
249
+ if line.start_with? what
250
+ return
251
+ end
252
+ @position += 1
253
+ end
254
+ end
255
+
256
+ def current_line
257
+ @position ||= 0
258
+ self.content[@position]
259
+ end
260
+ end
261
+
262
+ class PBXHash
263
+ attr_reader :pbxid
264
+
265
+ def initialize(pbxproj, pbxid, node)
266
+ @pbxproj = pbxproj
267
+ @pbxid = pbxid
268
+ @node = node
269
+ end
270
+
271
+ def keys
272
+ @node.keys
273
+ end
274
+
275
+ def inspect
276
+ "<PBX: #{keys.join(', ')}>"
277
+ end
278
+
279
+ private
280
+ def wrap(raw, recurse=true, id=nil)
281
+ if raw.is_a? Array
282
+ raw.map { |i| wrap(i, recurse) }
283
+ elsif raw.is_a? Hash
284
+ new_hash = raw.inject({}) { |h,(k,v)| h[k] = wrap(v, recurse) ; h }
285
+ PBXHash.new(@pbxproj, id, new_hash)
286
+ else
287
+ if recurse and @pbxproj.objects.include? raw
288
+ wrap(@pbxproj.objects[raw], false, raw)
289
+ else
290
+ raw
291
+ end
292
+ end
293
+ end
294
+
295
+ def method_missing(sym)
296
+ wrap(@node[sym.to_s])
297
+ end
298
+
299
+ end
300
+ end
@@ -0,0 +1,41 @@
1
+ module Zimt
2
+ class Sprinkle
3
+ attr_accessor :name, :url, :files
4
+
5
+ def self.get(name)
6
+ if name.start_with?('http://') || name.start_with?('https://')
7
+ url = name
8
+ else
9
+ url = "https://raw.github.com/zimt/sprinkles/stable/#{name.downcase}.sprinkle.yml"
10
+ end
11
+ spec = open(url) { |f| YAML::load(f) }
12
+ self.new(spec)
13
+ end
14
+
15
+ def initialize(spec)
16
+ @spec = spec
17
+ @name = spec["name"]
18
+ @url = spec["url"]
19
+ @files = spec["files"]
20
+ end
21
+
22
+ def install
23
+ puts "Installing #{name}"
24
+ FileUtils.mkdir "Zimt"
25
+ Zimt.pbxproj.ensure_zimt_group
26
+ files.each do |url|
27
+ file = Pathname.new(URI.parse(url).path).basename('.sprinkle.yml').to_s
28
+ puts "Adding #{file}..."
29
+ open(Pathname.new("Zimt").join(file), "w") do |io|
30
+ io.write(open(url).read)
31
+ end
32
+ if file.end_with? ".m"
33
+ Zimt.pbxproj.add_m_file(file)
34
+ else
35
+ Zimt.pbxproj.add_h_file(file)
36
+ end
37
+ end
38
+ puts "All done"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module Zimt
2
+ VERSION = "0.0.1"
3
+ end
data/zimt.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "zimt/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "zimt"
7
+ s.version = Zimt::VERSION
8
+ s.authors = ["Martin Schürrer"]
9
+ s.email = ["martin@schuerrer.org"]
10
+ s.homepage = "https://github.com/zimt/zimt"
11
+ s.summary = "Zimt is a collection of Cocoa extensions with clever package management"
12
+ s.description = "Zimt downloads and adds files to your .xcodeproj."
13
+
14
+ s.rubyforge_project = "zimt"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'json', '~> 1.5.0'
22
+ s.add_dependency 'thor', '~> 0.14.0'
23
+ s.add_development_dependency 'bacon', '~> 1.1.0'
24
+ s.add_development_dependency 'ruby-debug', '~> 0.10.0'
25
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zimt
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - "Martin Schu\xCC\x88rrer"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-08-29 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ~>
24
+ - !ruby/object:Gem::Version
25
+ segments:
26
+ - 1
27
+ - 5
28
+ - 0
29
+ version: 1.5.0
30
+ requirement: *id001
31
+ name: json
32
+ prerelease: false
33
+ type: :runtime
34
+ - !ruby/object:Gem::Dependency
35
+ version_requirements: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ - 14
42
+ - 0
43
+ version: 0.14.0
44
+ requirement: *id002
45
+ name: thor
46
+ prerelease: false
47
+ type: :runtime
48
+ - !ruby/object:Gem::Dependency
49
+ version_requirements: &id003 !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 1
55
+ - 1
56
+ - 0
57
+ version: 1.1.0
58
+ requirement: *id003
59
+ name: bacon
60
+ prerelease: false
61
+ type: :development
62
+ - !ruby/object:Gem::Dependency
63
+ version_requirements: &id004 !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ - 10
70
+ - 0
71
+ version: 0.10.0
72
+ requirement: *id004
73
+ name: ruby-debug
74
+ prerelease: false
75
+ type: :development
76
+ description: Zimt downloads and adds files to your .xcodeproj.
77
+ email:
78
+ - martin@schuerrer.org
79
+ executables:
80
+ - zimt
81
+ extensions: []
82
+
83
+ extra_rdoc_files: []
84
+
85
+ files:
86
+ - .gitignore
87
+ - .rvmrc
88
+ - Gemfile
89
+ - Rakefile
90
+ - bin/zimt
91
+ - lib/zimt.rb
92
+ - lib/zimt/cli.rb
93
+ - lib/zimt/pbxproj.rb
94
+ - lib/zimt/sprinkle.rb
95
+ - lib/zimt/version.rb
96
+ - zimt.gemspec
97
+ has_rdoc: true
98
+ homepage: https://github.com/zimt/zimt
99
+ licenses: []
100
+
101
+ post_install_message:
102
+ rdoc_options: []
103
+
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project: zimt
123
+ rubygems_version: 1.3.6
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Zimt is a collection of Cocoa extensions with clever package management
127
+ test_files: []
128
+