monofile 0.1.0 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 460899daff3c93d15ae49ed3163f2c56bb7e15e9
4
- data.tar.gz: 7b3e215fe00027e3f4b85e107f30029e048b6e35
3
+ metadata.gz: dc46a512fd3305af7a7d3949bdfe049de0e1e238
4
+ data.tar.gz: f152af472841c5145d37ca45f54504fbb48e6f3a
5
5
  SHA512:
6
- metadata.gz: 6aa5bf5125f770f42d2063d62991779cf7cde8ed06c5752dcd8cd1a3f84556e438b638246884e826951e56219125fafda1e2f00bcb7525fa405f8cc4608996ab
7
- data.tar.gz: 4b1452d92bd1e7104fe8f918596978661bdbf3997ab9121327e7ed4527269bdc1ac04d3db4007408582710fdaf74a50691cebda387c645127ac3d9f5f983321c
6
+ metadata.gz: 83b933f57ceab663f8186d1fd8f99737bebc1f35ecde411b44f4a24d6dc3476b510376d7194f77f68f9d9f5537919e00c7fcf66aedc2a22ce90e37fa75f840ea
7
+ data.tar.gz: 73acb18f7deb86cc6e4669459c4f531b98cdd7c248c12f36c820577550fcc1ba4eeebc65edbac2ba2fb9f0b697fe73f0b028c828c9f0c420d9c225b3be3b27fa
@@ -4,4 +4,9 @@ README.md
4
4
  Rakefile
5
5
  bin/monofile
6
6
  lib/monofile.rb
7
+ lib/monofile/monofile.rb
8
+ lib/monofile/mononame.rb
9
+ lib/monofile/tool.rb
7
10
  lib/monofile/version.rb
11
+ test/helper.rb
12
+ test/test_names.rb
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # monofile - read in/ parse mono (source) tree defintions with git (and github) projects, and more
1
+ # monofile - read in / parse monorepo / mono source tree definitions - a list of git (and github) projects, and more
2
2
 
3
- * home :: [github.com/rubycoco/git](https://github.com/rubycoco/git)
4
- * bugs :: [github.com/rubycoco/git/issues](https://github.com/rubycoco/git/issues)
3
+ * home :: [github.com/rubycoco/monos](https://github.com/rubycoco/monos)
4
+ * bugs :: [github.com/rubycoco/monos/issues](https://github.com/rubycoco/monos/issues)
5
5
  * gem :: [rubygems.org/gems/monofile](https://rubygems.org/gems/monofile)
6
6
  * rdoc :: [rubydoc.info/gems/monofile](http://rubydoc.info/gems/monofile)
7
7
 
@@ -9,7 +9,127 @@
9
9
 
10
10
  ## Usage
11
11
 
12
- To be done
12
+
13
+ Use `Monofile.read` to read in / parse monorepo / mono source tree definitions - supporting a ruby or a yaml format.
14
+
15
+
16
+ Example - `Monofile`:
17
+ ``` ruby
18
+ project "@openfootball/england"
19
+ project "@openfootball/world-cup"
20
+ project "@geraldb/austria"
21
+ project "@geraldb/geraldb.github.io"
22
+
23
+ project "geraldb", "catalog"
24
+ project "openfootball", "europe"
25
+ project "openfootball", "south-america"
26
+ ```
27
+
28
+ or
29
+
30
+ Example - `monofile.yml`:
31
+
32
+ ``` yaml
33
+ geraldb:
34
+ - austria
35
+ - catalog
36
+ - geraldb.github.io
37
+
38
+ openfootball:
39
+ - england
40
+ - europe
41
+ - south-america
42
+ - world-cup
43
+ ```
44
+
45
+
46
+ To read use.
47
+
48
+ ``` ruby
49
+ monofile = Monofile.read( "./Monofile" )
50
+ # -or-
51
+ monofile = Monofile.read( "./monofile.yml" )
52
+ pp monofile.to_a
53
+ #=> ["@openfootball/england",
54
+ # "@openfootball/world-cup",
55
+ # "@geraldb/austria",
56
+ # "@geraldb/geraldb.github.io",
57
+ # "@geraldb/catalog",
58
+ # "@openfootball/europe"]
59
+ # "@openfootball/south-america"]
60
+
61
+ pp monofile.to_h
62
+ #=> {"openfootball"=>["england", "world-cup", "europe", "south-america"],
63
+ # "geraldb" =>["austria", "geraldb.github.io", "catalog"]}
64
+
65
+ monofile.each do |proj|
66
+ puts " #{proj}"
67
+ end
68
+ #=> @openfootball/england
69
+ # @openfootball/world-cup
70
+ # @geraldb/austria
71
+ # @geraldb/geraldb.github.io
72
+ # @geraldb/catalog
73
+ # @openfootball/europe
74
+ # @openfootball/south-america
75
+
76
+ monofile.size
77
+ #=> 7
78
+ ```
79
+
80
+ and so on. That's it for now.
81
+
82
+
83
+
84
+ ### Troubleshooting / Debugging
85
+
86
+ Use the `monofile` command line tool to test reading in of
87
+ monorepo / mono source tree definitions.
88
+ Example:
89
+
90
+ ``` shell
91
+ # option 1) try to find default name (e.g. Monofile, Monofile.rb, etc.)
92
+ $ monofile
93
+
94
+ # option 2) pass in monofiles
95
+ $ monofile ./Monofile
96
+ $ monofile ./monfile.yml
97
+ # ...
98
+ ```
99
+
100
+ Printing the normalized / canonical names of the repo sources. Example.
101
+
102
+ ```
103
+ @openfootball/england
104
+ @openfootball/world-cup
105
+ @geraldb/austria
106
+ @geraldb/geraldb.github.io
107
+ @geraldb/catalog
108
+ @openfootball/europe
109
+ @openfootball/south-america
110
+ ```
111
+
112
+
113
+
114
+
115
+ ## Real-World Usage
116
+
117
+ See the [`monos`](https://github.com/rubycoco/monos/tree/master/monos) package that incl. the `mono` (or short `mo`)
118
+ command line tool lets you run
119
+ git commands on multiple repo(sitories) with a single command.
120
+
121
+
122
+ ## Installation
123
+
124
+ Use
125
+
126
+ gem install monofile
127
+
128
+ or add to your Gemfile
129
+
130
+ gem 'monofile'
131
+
132
+
13
133
 
14
134
  ## License
15
135
 
data/Rakefile CHANGED
@@ -6,10 +6,10 @@ Hoe.spec 'monofile' do
6
6
 
7
7
  self.version = Mono::Module::Monofile::VERSION
8
8
 
9
- self.summary = "monofile - read in/ parse mono (source) tree defintions with git (and github) projects, and more"
9
+ self.summary = "monofile - read in / parse monorepo / mono source tree definitions - a list of git (and github) projects, and more"
10
10
  self.description = summary
11
11
 
12
- self.urls = { home: 'https://github.com/rubycoco/git' }
12
+ self.urls = { home: 'https://github.com/rubycoco/monos' }
13
13
 
14
14
  self.author = 'Gerald Bauer'
15
15
  self.email = 'opensport@googlegroups.com'
@@ -13,14 +13,16 @@ require 'net/http'
13
13
  require 'net/https'
14
14
 
15
15
 
16
- require 'optparse'
16
+ require 'optparse' ## used by monofile (built-in test/debug) command line tool
17
17
 
18
18
 
19
19
 
20
20
  #####################
21
21
  # our own code
22
22
  require 'monofile/version' # note: let version always go first
23
-
23
+ require 'monofile/mononame'
24
+ require 'monofile/monofile'
25
+ require 'monofile/tool'
24
26
 
25
27
 
26
28
 
@@ -46,291 +48,17 @@ module Mono
46
48
  ## use expand path to make (assure) absolute path - why? why not?
47
49
  @@root = File.expand_path( path )
48
50
  end
49
-
50
-
51
-
52
- def self.monofile
53
- path = Monofile.find
54
- Monofile.read( path )
55
-
56
- # if path
57
- # GitRepoSet.read( path )
58
- # else
59
- # puts "!! WARN: no mono configuration file found; looking for #{MONOFILES.join(', ')} in (#{Dir.getwd})"
60
- # GitRepoSet.new( {} ) ## return empty set -todo/check: return nil - why? why not?
61
- # end
62
- end
63
51
  end ## module Mono
64
52
 
65
53
 
66
54
 
67
55
 
68
-
69
- class Monofile
70
- ## holds a list of projects
71
-
72
- ## nested class
73
- class Project
74
-
75
- ## use some different names / attributes ??
76
- attr_reader :org, ## todo/check: find a different name (or add alias e.g. login/user/etc.)
77
- :name
78
-
79
- ## todo/fix:
80
- ## - use *args and than split if args==2 or args==1 etc.
81
- def initialize( *args )
82
- if args.size == 2 && args[0].is_a?(String) && args[1].is_a?(String)
83
- ## assume [org, name]
84
- @org = args[0]
85
- @name = args[1]
86
- elsif args.size == 1 && args[0].is_a?( String )
87
- ## todo/fix: use norm_name parser or such!!!!
88
- parts = args[0].split( '/' )
89
- @org = parts[0][1..-1] ## cut-off leading @ (always assume for now!!)
90
- @name = parts[1]
91
- else
92
- raise ArgumentError, "[Monorepo::Project] one or two string args expected; got: #{args.pretty_inspect}"
93
- end
94
- end
95
-
96
- def to_s() "@#{org}/#{name}"; end
97
- def to_path() "#{org}/#{name}"; end
98
-
99
- ## add clone_ssh_url or such too!!!!
100
- end ## (nested) class Project
101
-
102
-
103
-
104
- class Builder ## "clean room" pattern/spell - keep accessible methods to a minimum (by eval in "cleanroom")
105
- def initialize( monofile )
106
- @monofile = monofile
107
- end
108
-
109
- def project( *args )
110
- project = Project.new( *args )
111
- @monofile.projects << project
112
- end
113
- end # (nested) class Builder
114
-
115
-
116
-
117
- RUBY_NAMES = ['monofile',
118
- 'Monofile',
119
- 'monofile.rb',
120
- 'Monofile.rb',
121
- ]
122
-
123
- TXT_NAMES = ['monofile.txt',
124
- 'monotree.txt', ## keep monotree - why? why not?
125
- 'monorepo.txt',
126
- 'repos.txt']
127
-
128
- ## note: yaml always requires an extension
129
- YML_NAMES = ['monofile.yml', 'monofile.yaml',
130
- 'monotree.yml', 'monotree.yaml', ## keep monotree - why? why not?
131
- 'monorepo.yml', 'monorepo.yaml',
132
- 'repos.yml', 'repos.yaml',
133
- ] ## todo/check: add mono.yml too - why? why not?
134
-
135
- NAMES = RUBY_NAMES + TXT_NAMES + YML_NAMES
136
-
137
-
138
- def self.find
139
- RUBY_NAMES.each do |name|
140
- return "./#{name}" if File.exist?( "./#{name}")
141
- end
142
-
143
- TXT_NAMES.each do |name|
144
- return "./#{name}" if File.exist?( "./#{name}")
145
- end
146
-
147
- YML_NAMES.each do |name|
148
- return "./#{name}" if File.exist?( "./#{name}")
149
- end
150
-
151
- nil ## no monofile found; return nil
152
- end
153
-
154
-
155
- def self.read( path )
156
- txt = File.open( path, 'r:utf-8') { |f| f.read }
157
-
158
- ## check for yml or yaml extension;
159
- ## or for txt extension; otherwise assume ruby
160
- extname = File.extname( path ).downcase
161
- if ['.yml', '.yaml'].include?( extname )
162
- hash = YAML.load( txt )
163
- new( hash )
164
- elsif ['.txt'].include?( extname )
165
- new( txt )
166
- else ## assume ruby code (as text in string)
167
- new().load( txt )
168
- end
169
- end
170
-
171
-
172
-
173
- def self.load( code )
174
- monofile = new
175
- monofile.load( code )
176
- monofile
177
- end
178
-
179
- def self.load_file( path ) ## keep (or add load_yaml to or such) - why? why not?
180
- code = File.open( path, 'r:utf-8') { |f| f.read }
181
- load( code )
182
- end
183
-
184
-
185
- ### attr readers
186
- def projects() @projects; end
187
- def size() @projects.size; end
188
-
189
-
190
- def initialize( obj={} ) ## todo/fix: change default to obj=[]
191
- @projects = []
192
-
193
- ## puts "[debug] obj.class=#{obj.class.name}"
194
- add( obj )
195
- end
196
-
197
- def load( code ) ## note: code is text as a string
198
- builder = Builder.new( self )
199
- builder.instance_eval( code )
200
- self ## note: for chaining always return self
201
- end
202
-
203
-
204
- def add( obj )
205
- ## todo/check: check for proc too! and use load( proc/block ) - possible?
206
- if obj.is_a?( String )
207
- puts "sorry add String - to be done!!!"
208
- exit 1
209
- elsif obj.is_a?( Array )
210
- puts "sorry add Array- to be done!!!"
211
- exit 1
212
- elsif obj.is_a?( Hash )
213
- add_hash( obj )
214
- else ## assume text (evaluate/parse)
215
- puts "sorry add Text - to be done!!!"
216
- exit 1
217
- end
218
- self ## note: return self for chaining
219
- end
220
-
221
-
222
- def add_hash( hash )
223
- hash.each do |org_with_counter, names|
224
-
225
- ## remove optional number from key e.g.
226
- ## mrhydescripts (3) => mrhydescripts
227
- ## footballjs (4) => footballjs
228
- ## etc.
229
-
230
- ## todo/check: warn about duplicates or such - why? why not?
231
-
232
- org = org_with_counter.sub( /\([0-9]+\)/, '' ).strip.to_s
233
-
234
- names.each do |name|
235
- @projects << Project.new( org, name )
236
- end
237
- end
238
-
239
- self ## note: return self for chaining
240
- end
241
-
242
-
243
-
244
- def each( &block )
245
- ## puts "[debug] arity: #{block.arity}"
246
-
247
- ## for backwards compatibility support "old" each with/by org & names
248
- ## add deprecated warnings and use to_h or such - why? why not?
249
- if block.arity == 2
250
- puts "!! DEPRECATED - please, use Monofile#to_h or Monofile.each {|proj| ...}"
251
- to_h.each do |org, names|
252
- block.call( org, names )
253
- end
254
- else
255
- ## assume just regular
256
- @projects.each do |project|
257
- block.call( project )
258
- end
259
- end
260
- end # method each
261
-
262
- def each_with_index( &block )
263
- @projects.each_with_index do |project,i|
264
- block.call( project, i )
265
- end
266
- end
267
-
268
-
269
-
270
- ### for backward compat(ibility) add a hash in the form e.g:
271
- ##
272
- ## geraldb:
273
- ## - austria
274
- ## - catalog
275
- ## - geraldb.github.io
276
- ## - logos
277
- ## yorobot:
278
- ## - auto
279
- ## - backup
280
- ## - football.json
281
- ## - logs
282
- ##
283
- def to_h
284
- h = {}
285
- @projects.each do |project|
286
- h[ project.org ] ||= []
287
- h[ project.org ] << project.name
288
- end
289
- h
290
- end
291
-
292
- def to_a
293
- ## todo/check:
294
- ## - sort all entries a-z - why? why not?
295
- ## - always start name with @ marker - why? why not?
296
- @projects.map {|project| project.to_s }
297
- end
298
- end # class Monofile
299
-
300
-
301
-
302
-
303
-
304
- class Monofile
305
- class Tool
306
- def self.main( args=ARGV )
307
-
308
- path = Monofile.find
309
- if path.nil?
310
- puts "!! ERROR: no mono configuration file found; looking for #{Monofile::NAMES.join(', ')} in (#{Dir.getwd})"
311
- exit 1
312
- end
313
-
314
- ## add check for auto-require (e.g. ./config.rb)
315
- config_path = "./config.rb"
316
- if File.exist?( config )
317
- puts "[monofile] auto-require >#{config_path}<..."
318
- require( config_path )
319
- end
320
-
321
- puts "[monofile] reading >#{path}<..."
322
- monofile=Monofile.read( path )
323
- pp monofile
324
-
325
- ## print one project per line
326
- puts "---"
327
- monofile.each do |proj|
328
- puts proj.to_s
329
- end
330
- end
331
- end # (nested) class Tool
332
- end # class Monofile
56
+ ###
57
+ ## add some convenience alias for alternate spelling (CamelCase)
58
+ MonoName = Mononame
59
+ MonoPath = Monopath
60
+ MonoFile = Monofile
333
61
 
334
62
 
335
- Mono::Module::Monofile.banner
63
+ puts Mono::Module::Monofile.banner ## say hello
336
64
 
@@ -0,0 +1,251 @@
1
+
2
+ class Monofile
3
+ ## holds a list of projects
4
+
5
+ ## nested class
6
+ class Project ## todo/fix: change to Monoproject/MonoProject - why? why not?
7
+ def initialize( *args )
8
+ if args.size == 1 && args[0].is_a?( String )
9
+ @name = Mononame.parse( args[0] )
10
+ elsif args.size == 2 && args[0].is_a?(String) && args[1].is_a?(String)
11
+ ## assume [org, name]
12
+ @name = Mononame.new( *args )
13
+ else
14
+ raise ArgumentError, "[MonoProject] one or two string args expected; got: #{args.inspect}"
15
+ end
16
+ end
17
+
18
+ def org() @name.org; end
19
+ def name() @name.name; end
20
+
21
+ def to_path() @name.to_path; end
22
+ def to_s() @name.to_s; end
23
+
24
+ ## add clone_ssh_url or such too!!!!
25
+ end ## (nested) class Project
26
+
27
+
28
+
29
+ class Builder ## "clean room" pattern/spell - keep accessible methods to a minimum (by eval in "cleanroom")
30
+ def initialize( monofile )
31
+ @monofile = monofile
32
+ end
33
+
34
+ def project( *args )
35
+ ## auto-convert symbols to string
36
+ args = args.map do |arg|
37
+ arg.is_a?( Symbol ) ? arg.to_s : arg
38
+ end
39
+
40
+ project = Project.new( *args )
41
+ @monofile.projects << project
42
+ end
43
+
44
+ ###
45
+ ## adding many projects at once (by batch) - keep - why? why not?
46
+ def projects( *args )
47
+ ## note: for now only support (list of) hash
48
+ ## add more later (nested array or text or such) - why? why not?
49
+ args.each do |arg|
50
+ raise ArgumentError, "expected Hash type - got: #{arg.inspect} : #{arg.class.name}" unless arg.is_a?( Hash )
51
+ end
52
+
53
+ ## pp arg
54
+ args.each do |arg|
55
+ arg.each do |org, names|
56
+ names.each do |name|
57
+ ## puts "adding #{org} #{name}"
58
+ project( org, name )
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end # (nested) class Builder
64
+
65
+
66
+
67
+
68
+ RUBY_NAMES = ['monofile',
69
+ 'Monofile',
70
+ 'monofile.rb',
71
+ 'Monofile.rb',
72
+ ]
73
+
74
+ TXT_NAMES = ['monofile.txt',
75
+ 'monotree.txt', ## keep monotree - why? why not?
76
+ 'monorepo.txt',
77
+ 'repos.txt']
78
+
79
+ ## note: yaml always requires an extension
80
+ YML_NAMES = ['monofile.yml', 'monofile.yaml',
81
+ 'monotree.yml', 'monotree.yaml', ## keep monotree - why? why not?
82
+ 'monorepo.yml', 'monorepo.yaml',
83
+ 'repos.yml', 'repos.yaml',
84
+ ] ## todo/check: add mono.yml too - why? why not?
85
+
86
+ NAMES = RUBY_NAMES + TXT_NAMES + YML_NAMES
87
+
88
+
89
+ def self.find
90
+ RUBY_NAMES.each do |name|
91
+ return "./#{name}" if File.exist?( "./#{name}")
92
+ end
93
+
94
+ TXT_NAMES.each do |name|
95
+ return "./#{name}" if File.exist?( "./#{name}")
96
+ end
97
+
98
+ YML_NAMES.each do |name|
99
+ return "./#{name}" if File.exist?( "./#{name}")
100
+ end
101
+
102
+ nil ## no monofile found; return nil
103
+ end
104
+
105
+
106
+ def self.read( path )
107
+ txt = File.open( path, 'r:utf-8') { |f| f.read }
108
+
109
+ ## check for yml or yaml extension;
110
+ ## or for txt extension; otherwise assume ruby
111
+ extname = File.extname( path ).downcase
112
+ if ['.yml', '.yaml'].include?( extname )
113
+ hash = YAML.load( txt )
114
+ new( hash )
115
+ elsif ['.txt'].include?( extname )
116
+ new( txt )
117
+ else ## assume ruby code (as text in string)
118
+ new().load( txt )
119
+ end
120
+ end
121
+
122
+
123
+
124
+ def self.load( code )
125
+ monofile = new
126
+ monofile.load( code )
127
+ monofile
128
+ end
129
+
130
+ def self.load_file( path ) ## keep (or add load_yaml to or such) - why? why not?
131
+ code = File.open( path, 'r:utf-8') { |f| f.read }
132
+ load( code )
133
+ end
134
+
135
+
136
+ ### attr readers
137
+ def projects() @projects; end
138
+ def size() @projects.size; end
139
+
140
+
141
+ def initialize( obj={} ) ## todo/fix: change default to obj=[]
142
+ @projects = []
143
+
144
+ ## puts "[debug] obj.class=#{obj.class.name}"
145
+ add( obj )
146
+ end
147
+
148
+ def load( code ) ## note: code is text as a string
149
+ builder = Builder.new( self )
150
+ builder.instance_eval( code )
151
+ self ## note: for chaining always return self
152
+ end
153
+
154
+
155
+ def add( obj )
156
+ ## todo/check: check for proc too! and use load( proc/block ) - possible?
157
+ if obj.is_a?( String )
158
+ puts "sorry add String - to be done!!!"
159
+ exit 1
160
+ elsif obj.is_a?( Array )
161
+ puts "sorry add Array- to be done!!!"
162
+ exit 1
163
+ elsif obj.is_a?( Hash )
164
+ add_hash( obj )
165
+ else ## assume text (evaluate/parse)
166
+ puts "sorry add Text - to be done!!!"
167
+ exit 1
168
+ end
169
+ self ## note: return self for chaining
170
+ end
171
+
172
+
173
+ def add_hash( hash )
174
+ hash.each do |org_with_counter, names|
175
+
176
+ ## remove optional number from key e.g.
177
+ ## mrhydescripts (3) => mrhydescripts
178
+ ## footballjs (4) => footballjs
179
+ ## etc.
180
+
181
+ ## todo/check: warn about duplicates or such - why? why not?
182
+
183
+ org = org_with_counter.sub( /\([0-9]+\)/, '' ).strip.to_s
184
+
185
+ names.each do |name|
186
+ @projects << Project.new( org, name )
187
+ end
188
+ end
189
+
190
+ self ## note: return self for chaining
191
+ end
192
+
193
+
194
+
195
+ def each( &block )
196
+ ## puts "[debug] arity: #{block.arity}"
197
+
198
+ ## for backwards compatibility support "old" each with/by org & names
199
+ ## add deprecated warnings and use to_h or such - why? why not?
200
+ if block.arity == 2
201
+ puts "!! DEPRECATED - please, use Monofile#to_h or Monofile.each {|proj| ...}"
202
+ to_h.each do |org, names|
203
+ block.call( org, names )
204
+ end
205
+ else
206
+ ## assume just regular
207
+ @projects.each do |project|
208
+ block.call( project )
209
+ end
210
+ end
211
+ end # method each
212
+
213
+ def each_with_index( &block )
214
+ @projects.each_with_index do |project,i|
215
+ block.call( project, i )
216
+ end
217
+ end
218
+
219
+
220
+
221
+ ### for backward compat(ibility) add a hash in the form e.g:
222
+ ##
223
+ ## geraldb:
224
+ ## - austria
225
+ ## - catalog
226
+ ## - geraldb.github.io
227
+ ## openfootball:
228
+ ## - england
229
+ ## - europe
230
+ ## - south-america
231
+ ## - world-cup
232
+ ##
233
+ def to_h
234
+ h = {}
235
+ @projects.each do |project|
236
+ h[ project.org ] ||= []
237
+ h[ project.org ] << project.name
238
+ end
239
+ h
240
+ end
241
+
242
+ def to_a
243
+ ## todo/check:
244
+ ## - sort all entries a-z - why? why not?
245
+ ## - always start name with @ marker - why? why not?
246
+ @projects.map {|project| project.to_s }
247
+ end
248
+ end # class Monofile
249
+
250
+
251
+
@@ -0,0 +1,176 @@
1
+ #####
2
+ # mononame (e.g. @org/hello) machinery
3
+ # turn
4
+ # - @openfootball/england/2020-21
5
+ # - 2020-21@openfootball/england
6
+ # - england/2020-21@openfootball
7
+ # => into
8
+ # - openfootball/england/2020-21
9
+
10
+
11
+
12
+
13
+ module Mono
14
+ ## shared parse/norm helper (for Name/Path)
15
+ ## - find something better - why? why not?
16
+ def self.parse_name( line )
17
+ if line.is_a?( String )
18
+ parts = line.split( '@' )
19
+ raise ArgumentError, "[Mononame] no @ found BUT required in name; got >#{line}<" if parts.size == 1
20
+ raise ArgumentError, "[Mononame] too many @ found (#{parts.size-1}) in name; got >#{line}<" if parts.size > 2
21
+
22
+ ## pass 1) rebuild (normalized) name/path
23
+ name = String.new('')
24
+ name << parts[1] ## add orgs path first - w/o leading @ - gets removed by split :-)
25
+ if parts[0].length > 0 ## has leading repo name (w/ optional path)
26
+ name << '/'
27
+ name << parts[0]
28
+ end
29
+
30
+ ## pass 2) split (normalized) name/path into components (org/name/path)
31
+ parts = name.split( '/' )
32
+
33
+ args = [parts[0], parts[1]]
34
+
35
+ more_parts = parts[2..-1] ## check for any extra (optional) path parts
36
+ args << more_parts.join( '/' ) if more_parts.size > 0
37
+
38
+ args
39
+ else
40
+ raise ArgumentError, "[Mononame] string with @ expected; got: #{line.pretty_inspect} of type #{line.class.name}"
41
+ end
42
+ end
43
+ end # module Mono
44
+
45
+
46
+
47
+ class Mononame
48
+ def self.parse( line )
49
+ values = Mono.parse_name( line )
50
+ raise ArgumentError, "[Mononame] expected two parts (org/name); got #{values.pretty_inspect}" if values.size != 2
51
+ new( *values )
52
+ end
53
+
54
+ def self.real_path( line )
55
+ ## add one-time (quick) usage convenience shortcut
56
+ mononame = parse( line )
57
+ mononame.real_path
58
+ end
59
+
60
+
61
+ ## note: org and name for now required
62
+ ## - make name optional too - why? why not?!!!
63
+ ## use some different names / attributes ??
64
+ attr_reader :org, ## todo/check: find a different name (or add alias e.g. login/user/etc.)
65
+ :name
66
+
67
+ def initialize( org, name )
68
+ if org.is_a?(String) && name.is_a?(String)
69
+ @org = org
70
+ @name = name
71
+ else
72
+ raise ArgumentError, "[Mononame] expected two strings (org, name); got >#{org}< of type #{org.class.name}, >#{name}< of type #{name.class.name}"
73
+ end
74
+ end
75
+
76
+ def to_path() "#{@org}/#{@name}"; end
77
+ def to_s() "@#{to_path}"; end
78
+
79
+ def real_path() "#{Mono.root}/#{to_path}"; end
80
+ end # class Mononame
81
+
82
+
83
+
84
+ ####
85
+ ## todo/check:
86
+ ## use as shared Mono/nomen/resource or such
87
+ # shared base class for Mononame & Monopath - why? why not?
88
+ #
89
+ # Monoloc (for location)
90
+ # Monores (for resource)
91
+ # Mono__ ??
92
+ #
93
+ # name components:
94
+ # - better name for path? - use filepath, relpath, ...
95
+
96
+
97
+
98
+ class Monopath
99
+ def self.parse( line )
100
+ values = Mono.parse_name( line )
101
+ raise ArgumentError, "[Monopath] expected three parts (org/name/path); got #{values.pretty_inspect}" if values.size != 3
102
+ new( *values )
103
+ end
104
+
105
+ def self.real_path( line )
106
+ monopath = parse( line )
107
+ monopath.real_path
108
+ end
109
+
110
+
111
+ ## note: org and name AND path for now required
112
+ ## - make name path optional too - why? why not?!!!
113
+ attr_reader :org, :name, :path
114
+
115
+ def initialize( org, name, path )
116
+ ## support/check for empty path too - why? why not?
117
+
118
+ if org.is_a?(String) && name.is_a?(String) && path.is_a?(String)
119
+ ## assume [org, name, path?]
120
+ ## note: for now assumes proper formatted strings
121
+ ## e.g. no leading @ or combined @hello/text in org
122
+ ## or name or such
123
+ ## - use parse/norm_name here too - why? why not?
124
+ @org = org
125
+ @name = name
126
+ @path = path
127
+ else
128
+ raise ArgumentError, "[Monopath] expected three strings (org, name, path); got >#{org}< of type #{org.class.name}, >#{name}< of type #{name.class.name}, >#{path}< of type #{path.class.name}"
129
+ end
130
+ end
131
+
132
+ def to_path() "#{@org}/#{@name}/#{@path}"; end
133
+ def to_s() "@#{to_path}"; end
134
+
135
+ def real_path() "#{Mono.root}/#{to_path}"; end
136
+
137
+
138
+ ## some File-like convenience helpers
139
+ ## e.g. File.exist? => Monopath.exist?
140
+ ## File.open => Monopath.open( ... ) { block }
141
+ ## etc.
142
+ def self.exist?( line )
143
+ File.exist?( real_path( line ) )
144
+ end
145
+
146
+
147
+ ## path always relative to Mono.root
148
+ ## todo/fix: use File.expand_path( path, Mono.root ) - why? why not?
149
+ ## or always enfore "absolut" path e.g. do NOT allow ../ or ./ or such
150
+ def self.open( line, mode='r:utf-8', &block )
151
+ path = real_path( line )
152
+ ## make sure path exists if we open for writing/appending - why? why not?
153
+ if mode[0] == 'w' || mode[0] == 'a'
154
+ FileUtils.mkdir_p( File.dirname( path ) ) ## make sure path exists
155
+ end
156
+
157
+ File.open( path, mode ) do |file|
158
+ block.call( file )
159
+ end
160
+ end
161
+
162
+ def self.read_utf8( line )
163
+ open( line, 'r:utf-8') { |file| file.read }
164
+ end
165
+ end # class Monopath
166
+ ## note: use Monopath - avoid confusion with Monofile (a special file with a list of mono projects)!!!!
167
+
168
+
169
+
170
+
171
+
172
+ ## todo/check: add a (global) Mono/Mononame converter - why? why not?
173
+ ##
174
+ ## module Kernel
175
+ ## def Mono( *args ) Mononame.parse( *args ); end
176
+ ## end
@@ -0,0 +1,59 @@
1
+ class Monofile
2
+ class Tool
3
+ def self.main( args=ARGV )
4
+
5
+ options = {}
6
+ OptionParser.new do |parser|
7
+ ## note:
8
+ ## you can add many/multiple modules
9
+ ## e.g. -r gitti -r mono etc.
10
+ parser.on( '-r NAME', '--require NAME') do |name|
11
+ options[:requires] ||= []
12
+ options[:requires] << name
13
+ end
14
+ ## todo/fix:
15
+ ## add --verbose
16
+ ## add -d/--debug
17
+ end.parse!( args )
18
+
19
+
20
+ if args.size == 0 ## auto-add default arg (monofile)
21
+ monofile_path = Monofile.find
22
+ if monofile_path.nil?
23
+ puts "!! ERROR: no mono configuration file found; looking for #{Monofile::NAMES.join(', ')} in (#{Dir.getwd})"
24
+ exit 1
25
+ end
26
+ args << monofile_path
27
+ end
28
+
29
+
30
+ ## add check for auto-require (e.g. ./config.rb)
31
+ if options[:requires] ## use custom (auto-)requires
32
+ options[:requires].each do |path|
33
+ puts "[monofile] auto-require >#{path}<..."
34
+ require( path )
35
+ end
36
+ else ## use/try defaults
37
+ config_path = "./config.rb"
38
+ if File.exist?( config_path )
39
+ puts "[monofile] auto-require (default) >#{config_path}<..."
40
+ require( config_path )
41
+ end
42
+ end
43
+
44
+
45
+ args.each do |path|
46
+ puts "[monofile] reading >#{path}<..."
47
+ monofile=Monofile.read( path )
48
+ pp monofile
49
+
50
+ ## print one project per line
51
+ puts "---"
52
+ monofile.each do |proj|
53
+ puts proj.to_s
54
+ end
55
+ end
56
+ end # method self.main
57
+ end # (nested) class Tool
58
+ end # class Monofile
59
+
@@ -4,8 +4,8 @@ module Module
4
4
  module Monofile
5
5
 
6
6
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
7
- MINOR = 1
8
- PATCH = 0
7
+ MINOR = 2
8
+ PATCH = 3
9
9
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
10
 
11
11
  def self.version
@@ -0,0 +1,7 @@
1
+ # minitest setup
2
+ require 'minitest/autorun'
3
+
4
+
5
+ ## our own code
6
+ require 'monofile'
7
+
@@ -0,0 +1,97 @@
1
+ ###
2
+ # to run use
3
+ # ruby -I ./lib -I ./test test/test_names.rb
4
+
5
+
6
+ require 'helper'
7
+
8
+
9
+ class TestNames < MiniTest::Test
10
+
11
+ def test_parse
12
+ %w[
13
+ @openfootball/england
14
+ england@openfootball
15
+ ].each do |line|
16
+ mono = Mononame.parse( line )
17
+
18
+ assert_equal '@openfootball/england', mono.to_s
19
+ assert_equal 'openfootball/england', mono.to_path
20
+
21
+ assert_equal 'openfootball', mono.org
22
+ assert_equal 'england', mono.name
23
+ end
24
+
25
+
26
+ %w[
27
+ @openfootball/england/2020-21
28
+ 2020-21@openfootball/england
29
+ england/2020-21@openfootball
30
+ ].each do |line|
31
+ mono = Monopath.parse( line )
32
+
33
+ assert_equal '@openfootball/england/2020-21', mono.to_s
34
+ assert_equal 'openfootball/england/2020-21', mono.to_path
35
+
36
+ assert_equal 'openfootball', mono.org
37
+ assert_equal 'england', mono.name
38
+ assert_equal '2020-21', mono.path
39
+ end
40
+
41
+ %w[
42
+ @openfootball/england/2020-21/premierleague.txt
43
+ 2020-21/premierleague.txt@openfootball/england
44
+ england/2020-21/premierleague.txt@openfootball
45
+ ].each do |line|
46
+ mono = Monopath.parse( line )
47
+
48
+ assert_equal '@openfootball/england/2020-21/premierleague.txt', mono.to_s
49
+ assert_equal 'openfootball/england/2020-21/premierleague.txt', mono.to_path
50
+
51
+ assert_equal 'openfootball', mono.org
52
+ assert_equal 'england', mono.name
53
+ assert_equal '2020-21/premierleague.txt', mono.path
54
+ end
55
+ end # method test_parse
56
+
57
+
58
+
59
+ def test_init
60
+ mono = Mononame.new( 'openfootball','england' )
61
+
62
+ assert_equal '@openfootball/england', mono.to_s
63
+ assert_equal 'openfootball/england', mono.to_path
64
+
65
+ assert_equal 'openfootball', mono.org
66
+ assert_equal 'england', mono.name
67
+
68
+
69
+ mono = Monopath.new( 'openfootball', 'england', '2020-21' )
70
+
71
+ assert_equal '@openfootball/england/2020-21', mono.to_s
72
+ assert_equal 'openfootball/england/2020-21', mono.to_path
73
+
74
+ assert_equal 'openfootball', mono.org
75
+ assert_equal 'england', mono.name
76
+ assert_equal '2020-21', mono.path
77
+
78
+
79
+ ## !!!!todo/check/fix!!!!!:
80
+ ## - support '2020-21', 'premierleague.txt' too (or only) - why? why not?
81
+ ##
82
+ ## todo/check/fix:
83
+ ## find a better name for path/path? component / part - why? why not?
84
+ ## to_path and path/path? to confusing!!!
85
+ mono = Monopath.new( 'openfootball', 'england', '2020-21/premierleague.txt' )
86
+
87
+ assert_equal '@openfootball/england/2020-21/premierleague.txt', mono.to_s
88
+ assert_equal 'openfootball/england/2020-21/premierleague.txt', mono.to_path
89
+
90
+ assert_equal 'openfootball', mono.org
91
+ assert_equal 'england', mono.name
92
+ assert_equal '2020-21/premierleague.txt', mono.path
93
+ end # method test_init
94
+
95
+
96
+
97
+ end # class TestNames
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monofile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-29 00:00:00.000000000 Z
11
+ date: 2020-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -44,8 +44,8 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '3.22'
47
- description: monofile - read in/ parse mono (source) tree defintions with git (and
48
- github) projects, and more
47
+ description: monofile - read in / parse monorepo / mono source tree definitions -
48
+ a list of git (and github) projects, and more
49
49
  email: opensport@googlegroups.com
50
50
  executables:
51
51
  - monofile
@@ -61,8 +61,13 @@ files:
61
61
  - Rakefile
62
62
  - bin/monofile
63
63
  - lib/monofile.rb
64
+ - lib/monofile/monofile.rb
65
+ - lib/monofile/mononame.rb
66
+ - lib/monofile/tool.rb
64
67
  - lib/monofile/version.rb
65
- homepage: https://github.com/rubycoco/git
68
+ - test/helper.rb
69
+ - test/test_names.rb
70
+ homepage: https://github.com/rubycoco/monos
66
71
  licenses:
67
72
  - Public Domain
68
73
  metadata: {}
@@ -87,6 +92,6 @@ rubyforge_project:
87
92
  rubygems_version: 2.5.2
88
93
  signing_key:
89
94
  specification_version: 4
90
- summary: monofile - read in/ parse mono (source) tree defintions with git (and github)
91
- projects, and more
95
+ summary: monofile - read in / parse monorepo / mono source tree definitions - a list
96
+ of git (and github) projects, and more
92
97
  test_files: []