monofile 0.1.0 → 0.2.3
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.
- 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: []
|