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 +4 -4
- data/Manifest.txt +5 -0
- data/README.md +124 -4
- data/Rakefile +2 -2
- data/lib/monofile.rb +10 -282
- data/lib/monofile/monofile.rb +251 -0
- data/lib/monofile/mononame.rb +176 -0
- data/lib/monofile/tool.rb +59 -0
- data/lib/monofile/version.rb +2 -2
- data/test/helper.rb +7 -0
- data/test/test_names.rb +97 -0
- metadata +12 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc46a512fd3305af7a7d3949bdfe049de0e1e238
|
4
|
+
data.tar.gz: f152af472841c5145d37ca45f54504fbb48e6f3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83b933f57ceab663f8186d1fd8f99737bebc1f35ecde411b44f4a24d6dc3476b510376d7194f77f68f9d9f5537919e00c7fcf66aedc2a22ce90e37fa75f840ea
|
7
|
+
data.tar.gz: 73acb18f7deb86cc6e4669459c4f531b98cdd7c248c12f36c820577550fcc1ba4eeebc65edbac2ba2fb9f0b697fe73f0b028c828c9f0c420d9c225b3be3b27fa
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# monofile - read in/ parse mono
|
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/
|
4
|
-
* bugs :: [github.com/rubycoco/
|
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
|
-
|
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
|
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/
|
12
|
+
self.urls = { home: 'https://github.com/rubycoco/monos' }
|
13
13
|
|
14
14
|
self.author = 'Gerald Bauer'
|
15
15
|
self.email = 'opensport@googlegroups.com'
|
data/lib/monofile.rb
CHANGED
@@ -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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
+
|
data/lib/monofile/version.rb
CHANGED
data/test/helper.rb
ADDED
data/test/test_names.rb
ADDED
@@ -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.
|
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-
|
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
|
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
|
-
|
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
|
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: []
|