squared 0.0.9 → 0.0.11

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.
@@ -1,13 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rexml/document'
4
+
3
5
  module Squared
4
6
  module Workspace
5
7
  module Repo
6
8
  include Common
7
9
  include Format
10
+ include Prompt
8
11
  include System
12
+ include Utils
13
+
14
+ class << self
15
+ def read_manifest(path)
16
+ return unless (file = path.join('.repo/manifest.xml')).exist?
17
+
18
+ doc = REXML::Document.new(file.read)
19
+ doc.elements['manifest/include'].attributes['name']&.sub('.xml', '')
20
+ end
21
+
22
+ def empty?(dir)
23
+ dir.empty? || (dir.children.size == 1 && dir.join(dir.children.first).to_s == __FILE__)
24
+ end
25
+ end
26
+
27
+ attr_reader :manifest_url, :manifest
9
28
 
10
- def repo(url, manifest = 'latest', run: nil, dev: nil, prod: nil, ref: @ref, group: @group)
29
+ def repo(url, manifest = 'latest', run: nil, script: nil, dev: nil, prod: nil, ref: @ref, group: @group)
11
30
  @home = if (val = env('REPO_HOME'))
12
31
  home = Pathname.new(val)
13
32
  if main == home.basename.to_s
@@ -16,71 +35,79 @@ module Squared
16
35
  @root = nil unless home.directory?
17
36
  elsif !@root.exist?
18
37
  @root.mkpath
19
- elsif !install?
20
- @root = nil unless confirm_install
38
+ elsif !repo_install?
39
+ @root = nil unless repo_confirm
21
40
  end
22
41
  end
23
42
  raise_error('REPO_HOME', val, hint: 'invalid') unless @root
24
-
25
43
  home.realdirpath
26
44
  elsif (val = env('REPO_ROOT'))
27
45
  @root = Pathname.new(val).realdirpath
28
46
  if !@root.exist?
29
47
  @root.mkpath
30
- elsif !install?
31
- raise_error('REPO_ROOT', val, hint: 'exist') unless confirm_install
48
+ elsif !repo_install?(parent: true)
49
+ raise_error('REPO_ROOT', val, hint: 'exist') unless repo_confirm
32
50
  end
33
51
  @root.join(main).realdirpath
34
52
  else
35
- install?(pwd = @home) ? pwd.join(main) : pwd
53
+ repo_install?(@home) ? @home.join(main) : @home
36
54
  end
37
55
  @root = @home.parent
38
56
  @manifest_url = url
39
57
  @manifest = manifest
40
- set_ref = lambda do
41
- if group
42
- @script[:group][:_] = group.to_s
43
- elsif ref
44
- @script[:ref][:_] = ref.to_sym
45
- end
46
- end
58
+ data = script_obj
47
59
  if repo?
48
- @script[:build] = case (val = env('REPO_BUILD'))
49
- when 'verbose'
50
- @verbose = true
51
- run.is_a?(String) ? "#{run}:verbose" : run
52
- when 'silent'
53
- @verbose = false
54
- @warning = false
55
- run
56
- else
57
- val || run
58
- end
59
- @script[:dev] = bool_match(env('REPO_DEV'), dev)
60
- @script[:prod] = bool_match(env('REPO_PROD'), prod)
61
- if (val = env('REPO_GROUP'))
62
- @script[:group][:_] = val.to_s
63
- @script[:env] = true
64
- elsif (val = env('REPO_REF'))
65
- @script[:ref][:_] = val.to_sym
66
- @script[:env] = true
60
+ if script
61
+ if (val = env('REPO_BUILD'))
62
+ data[:script] = case val
63
+ when 'verbose'
64
+ @verbose = 1
65
+ if script.is_a?(::Array)
66
+ script[0] = task_join(script[0], 'verbose')
67
+ script
68
+ else
69
+ task_join(script, 'verbose')
70
+ end
71
+ when 'silent'
72
+ @verbose = false
73
+ @warning = false
74
+ script
75
+ else
76
+ val
77
+ end
78
+ data[:env] = true
79
+ else
80
+ data[:script] = script
81
+ end
82
+ elsif (val = env('REPO_BUILD'))
83
+ data[:run] = val
84
+ data[:env] = true
67
85
  else
68
- set_ref
86
+ data[:run] = run
87
+ end
88
+ data[:global] = true
89
+ data[:dev] = env_match('REPO_DEV', dev, suffix: @envname)
90
+ data[:prod] = env_match('REPO_PROD', prod, suffix: @envname)
91
+ if (val = env('REPO_GROUP'))
92
+ script_set(data, group: val.split(','))
93
+ found = true
69
94
  end
70
- @warning = case env('REPO_WARN')
71
- when '0'
72
- false
73
- when '1'
74
- true
75
- else
76
- @warning && !empty?(@root)
77
- end
95
+ if (val = env('REPO_REF'))
96
+ script_set(data, ref: val.split(','))
97
+ found = true
98
+ end
99
+ script_set(data, group: group, ref: ref) unless found
100
+ @warning = env_match('REPO_WARN', @warning && !Repo.empty?(@root), suffix: @envname) != false
78
101
  @extensions << :__repo__
79
- else
80
- @script[:build] = run
81
- @script[:dev] = dev
82
- @script[:prod] = prod
83
- set_ref
102
+ elsif script || run
103
+ if script
104
+ data[:script] = script
105
+ else
106
+ data[:run] = run
107
+ end
108
+ data[:dev] = dev
109
+ data[:prod] = prod
110
+ script_set(data, group: group, ref: ref)
84
111
  end
85
112
  self
86
113
  end
@@ -90,8 +117,8 @@ module Squared
90
117
  def __repo__(**kwargs)
91
118
  kwargs.delete(:parallel) if env('REPO_SYNC', ignore: '0')
92
119
 
93
- branch = env('REPO_MANIFEST') || read_manifest
94
- target = branch || @manifest
120
+ branch = env('REPO_MANIFEST') || Repo.read_manifest(root)
121
+ target = branch || manifest
95
122
  stage = nil
96
123
  failfast = true
97
124
  cmd = []
@@ -115,12 +142,9 @@ module Squared
115
142
  end
116
143
  end
117
144
  status = lambda do |val, alt = nil|
118
- ver = branch || alt
119
- if ver
120
- message(@prefix || '', 'repo', val.sub('{0}', 'opts*=force,rebase,detach,gc,no-update,no-fail'), ver)
121
- else
122
- 'inactive'
123
- end
145
+ return 'inactive' unless (ver = branch || alt)
146
+
147
+ message(@prefix, 'repo', val.sub('{0}', 'opts*=force,rebase,detach,gc,no-update,no-fail'), ver, empty: true)
124
148
  end
125
149
 
126
150
  namespace task_name('repo') do |repo|
@@ -130,12 +154,21 @@ module Squared
130
154
  stage ||= 'all'
131
155
  repo['sync'].invoke
132
156
  @project.select do |_, proj|
133
- next false unless proj.enabled? && proj.ref?(Project::Base.ref)
157
+ next unless proj.enabled?(proj.workspace.baseref)
134
158
 
135
- proj.depend if proj.depend?
159
+ proj.depend(sync: true) if proj.depend?
136
160
  proj.build?
137
161
  end
138
- .each_value { |proj| proj.has?(:dev) ? proj.refresh : proj.build }
162
+ .each_value do |proj|
163
+ proj.build(sync: true)
164
+ next unless proj.has?('dev') && proj.copy?
165
+
166
+ if (ws = proj.workspace).task_defined?(target = ws.task_name(proj.name, 'copy'))
167
+ Common::Task.invoke(target, **ws.invokeargs)
168
+ else
169
+ proj.copy(sync: true)
170
+ end
171
+ end
139
172
  end
140
173
 
141
174
  desc status.("init[manifest?=#{target},{0}]", target)
@@ -143,7 +176,7 @@ module Squared
143
176
  parse_opts.(args)
144
177
  stage = 'init'
145
178
  puts if newline
146
- system("repo init -u #{@manifest_url} -m #{args.manifest || target}.xml", chdir: root)
179
+ system("repo init -u #{manifest_url} -m #{args.manifest || target}.xml", chdir: root)
147
180
  repo['all'].invoke
148
181
  end
149
182
 
@@ -159,58 +192,32 @@ module Squared
159
192
  begin
160
193
  shell("repo sync #{cmd.join(' ')}", chdir: root, exception: failfast)
161
194
  rescue StandardError => e
162
- emphasize(e, title: "rake stash #{task_name("repo:#{stage || 'sync'}")}")
195
+ emphasize(e, title: "rake stash #{task_name(task_join('repo', stage || 'sync'))}")
163
196
  raise
164
197
  end
165
198
  end
166
199
  end
167
200
  end
168
201
 
169
- def read_manifest
170
- require 'rexml/document'
171
- return unless (file = root_path('.repo/manifest.xml')).exist?
172
-
173
- doc = REXML::Document.new(file.read)
174
- doc.elements['manifest/include'].attributes['name']&.sub('.xml', '')
175
- end
176
-
177
- def confirm_install
202
+ def repo_confirm
178
203
  return false unless root.directory?
179
204
 
180
205
  path = sub_style(root, styles: theme[:inline])
181
- @override = confirm(
206
+ @repo_override = confirm(
182
207
  "#{log_title(:warn)} \"#{path}\" is not empty. Continue with installation? [y/N] ",
183
- default: 'N',
208
+ 'N',
184
209
  timeout: env('REPO_TIMEOUT', 15, ignore: '0')
185
210
  )
186
211
  end
187
212
 
188
- def bool_match(val, pat)
189
- case val
190
- when nil, ''
191
- pat
192
- when '0'
193
- false
194
- when '1'
195
- true
196
- else
197
- Regexp.new(val)
198
- end
199
- end
200
-
201
213
  def repo?
202
- !@manifest_url.nil? && (install? || !!@override)
203
- end
204
-
205
- def empty?(dir)
206
- dir.empty? || (dir.children.size == 1 && dir.join(dir.children.first).to_s == __FILE__)
214
+ !manifest_url.nil? && (repo_install? || @repo_override == true)
207
215
  end
208
216
 
209
- def install?(dir = root)
210
- return true if empty?(dir) || dir.join('.repo').directory?
211
- return false unless dir == root && env('REPO_HOME').nil? && !env('REPO_ROOT').nil?
217
+ def repo_install?(dir = root, parent: false)
218
+ return true if Repo.empty?(dir) || dir.join('.repo').directory?
212
219
 
213
- root.children.none? { |path| path.directory? && path.basename.to_s[0] != '.' && path.to_s != home.to_s }
220
+ parent && root.children.none? { |ent| ent.directory? && ent.basename.to_s[0] != '.' && ent.to_s != home.to_s }
214
221
  end
215
222
  end
216
223
 
@@ -8,22 +8,51 @@ module Squared
8
8
  include ::Rake::DSL
9
9
  extend Forwardable
10
10
 
11
- TASK_BASE = %i[build refresh depend outdated doc test copy clean].freeze
12
- TASK_ALIAS = {
13
- refresh: :build
14
- }
15
- TASK_KEYS = TASK_BASE.dup
11
+ TASK_BASE = %i[build depend doc test copy clean]
12
+ TASK_BATCH = {}
16
13
  TASK_EXTEND = {}
17
- private_constant :TASK_BASE, :TASK_ALIAS, :TASK_KEYS, :TASK_EXTEND
14
+ TASK_KEYS = TASK_BASE.dup
15
+ TASK_ALIAS = {}
16
+ TASK_NAME = {}
17
+ private_constant :TASK_BASE, :TASK_BATCH, :TASK_KEYS, :TASK_NAME, :TASK_EXTEND
18
18
 
19
19
  class << self
20
20
  def add(task, obj)
21
- TASK_KEYS << task unless TASK_KEYS.include?(task)
21
+ key_set task
22
22
  (TASK_EXTEND[task] ||= []).push(obj)
23
23
  end
24
24
 
25
- def alias(key, task)
26
- TASK_ALIAS[key.to_sym] = task.to_sym
25
+ def batch(ref, obj)
26
+ if obj.is_a?(::Hash)
27
+ obj.each do |key, val|
28
+ key_set key
29
+ data = TASK_BATCH[key] ||= {}
30
+ (data[ref] ||= []).concat(val)
31
+ end
32
+ elsif (data = TASK_BATCH[obj]) && data.delete(ref) && data.empty?
33
+ TASK_KEYS.delete(obj)
34
+ end
35
+ end
36
+
37
+ def alias(ref, obj)
38
+ if obj.is_a?(::Hash)
39
+ obj.each { |key, val| (TASK_ALIAS[key] ||= {})[ref] = val }
40
+ elsif (data = TASK_ALIAS[obj])
41
+ data.delete(ref)
42
+ end
43
+ end
44
+
45
+ def rename(key, task)
46
+ TASK_NAME[key.to_sym] = task.to_sym
47
+ end
48
+
49
+ private
50
+
51
+ def key_set(val)
52
+ return if TASK_KEYS.include?(val)
53
+
54
+ TASK_KEYS << val
55
+ TASK_BASE.delete(val)
27
56
  end
28
57
  end
29
58
 
@@ -45,55 +74,48 @@ module Squared
45
74
  TASK_KEYS.each { |key| @data[key] = [] }
46
75
  end
47
76
 
48
- def __set__(key)
49
- self[key.to_sym] ||= []
50
- end
51
-
52
- def __populate__(proj)
53
- return unless @session
54
-
77
+ def populate(proj)
55
78
  group, parent, id = @session.values
56
- ws = proj.workspace
57
- each do |key, items|
58
- task = "#{proj.name}:#{key}"
59
- unless include?(key) ? proj.has?(key) || ws.task_defined?(key) : ws.task_extend?(proj, key)
60
- alt = TASK_ALIAS[key]
61
- next unless alt && (task = "#{proj.name}:#{alt}") && self[alt].include?(task)
62
- end
63
- next unless ws.task_defined?(task)
79
+ @data.each do |key, items|
80
+ ws = proj.workspace
81
+ next if (tasks = ws.task_resolve(proj, key)).empty?
64
82
 
65
83
  if (g = proj.group)
66
84
  id << g
67
- (group[:"#{key}:#{g}"] ||= []).push(task)
85
+ (group[:"#{key}:#{g}"] ||= []).push(*tasks)
68
86
  else
69
- items << task
87
+ items.concat(tasks)
88
+ end
89
+ if tasks.size > 1 && (data = batch_get(key)) && data.keys.any? { |ref| proj.ref?(ref) }
90
+ desc ws.task_name(t = ws.task_join(proj.name, key), desc: true)
91
+ task ws.task_name(t) => tasks
70
92
  end
71
93
  next unless (b = ws.find_base(proj)) && (name = b.ref.to_s) != g
72
94
 
73
95
  id << name
74
- (parent[:"#{key}:#{name}"] ||= []).push(task)
96
+ (parent[:"#{key}:#{name}"] ||= []).push(*tasks)
75
97
  end
76
98
  end
77
99
 
78
- def __build__(parallel: [], **)
79
- group, parent, id = @session.values
80
- merge!(parent) if id.uniq.size > 1
81
- merge!(group)
82
- each do |key, items|
100
+ def build(parallel: [], **)
101
+ @data.merge!(@session[:parent]) if @session[:id].uniq.size > 1
102
+ @data.merge!(@session[:group])
103
+ @data.each do |key, items|
83
104
  next if items.empty?
84
105
 
85
- key = @workspace.task_name(name = key.to_s)
86
- val = @workspace.task_name(name, desc: true)
106
+ key = @workspace.task_name(t = name_get(key))
107
+ val = @workspace.task_name(t, desc: true)
87
108
  if items.size > 1
88
109
  @multiple << key
89
- if parallel.include?(name) || ((ns = @workspace.task_namespace(name)) && parallel.include?(ns))
110
+ if parallel.include?(t) || ((ns = @workspace.task_namespace(t)) && parallel.include?(ns))
90
111
  desc "#{val} (thread)"
91
112
  multitask key => items
92
113
  @parallel << key
93
114
 
115
+ s = @workspace.task_join(key, 'sync')
94
116
  desc "#{val} (sync)"
95
- task "#{key}:sync" => items
96
- @sync << "#{key}:sync"
117
+ task s => items
118
+ @sync << s
97
119
  next
98
120
  end
99
121
  end
@@ -101,19 +123,31 @@ module Squared
101
123
  desc val
102
124
  task key => items
103
125
  end
104
- TASK_ALIAS.each_key do |key|
105
- suf = ":#{key}"
106
- self[key].clear unless self[key].any? { |val| val.end_with?(suf) }
107
- end
108
126
  @multiple += sync
109
- @session = nil
127
+ end
128
+
129
+ def name_get(key)
130
+ (TASK_NAME[key] || key).to_s
131
+ end
132
+
133
+ def batch_get(key)
134
+ TASK_BATCH[key]
135
+ end
136
+
137
+ def alias_get(key)
138
+ TASK_ALIAS[key]
110
139
  end
111
140
 
112
141
  def some?(key)
113
- !key.nil? && key?(key = key.to_sym) && !self[key].empty?
142
+ return @data.key?(key) && !@data[key].empty? unless (batch = batch_get(key))
143
+
144
+ batch.each_value do |items|
145
+ return true if items.all? { |val| some?(val) || alias_get(val)&.any? { |_, alt| some?(alt) } }
146
+ end
147
+ false
114
148
  end
115
149
 
116
- def include?(key)
150
+ def base?(key)
117
151
  TASK_BASE.include?(key)
118
152
  end
119
153
 
@@ -135,17 +169,13 @@ module Squared
135
169
 
136
170
  private
137
171
 
138
- def method_missing(key, *)
139
- raise NoMethodError, key unless key?(key)
140
-
141
- self[key]
142
- end
143
-
144
172
  def already_invoked?(list, val)
145
- return list.include?(val) && Common::Task.invoked?(val) if val
173
+ return false unless val && !list.include?(val)
146
174
 
147
- ::Rake::Task.tasks.any? { |item| item.already_invoked && list.include?(item.name) }
175
+ ::Rake::Task.tasks.any? { |obj| obj.already_invoked && (val ? val == obj.name : list.include?(obj.name)) }
148
176
  end
149
177
  end
178
+
179
+ Application.impl_series = Series
150
180
  end
151
181
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'common'
4
-
5
3
  module Squared
6
4
  module Workspace
7
5
  class << self
@@ -23,7 +21,7 @@ module Squared
23
21
  ret = project(name)
24
22
  return ret if ret&.path&.directory?
25
23
 
26
- raise NoMethodError, message('project is not initialized', hint: name)
24
+ raise NoMethodError, "project is not initialized (#{name})"
27
25
  end
28
26
 
29
27
  def dirpath(val, absolute: true)
@@ -45,6 +43,9 @@ module Squared
45
43
  end
46
44
  end
47
45
 
48
- require_relative 'workspace/series'
49
46
  require_relative 'workspace/application'
47
+ require_relative 'workspace/series'
50
48
  require_relative 'workspace/project'
49
+
50
+ Workspace = Squared::Workspace
51
+ Project = Squared::Workspace::Project
data/lib/squared.rb CHANGED
@@ -1,14 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'squared/version'
4
- require_relative 'squared/workspace'
5
-
6
- Workspace = Squared::Workspace
7
- Project = Squared::Workspace::Project
8
-
9
- Workspace::Application.implement(
10
- Project::Git,
11
- Project::Node,
12
- Project::Python,
13
- Project::Ruby
14
- )
4
+ require_relative 'squared/common'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-16 00:00:00.000000000 Z
11
+ date: 2024-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -63,13 +63,16 @@ files:
63
63
  - README.md
64
64
  - README.ruby.md
65
65
  - lib/squared.rb
66
+ - lib/squared/app.rb
66
67
  - lib/squared/common.rb
67
68
  - lib/squared/common/base.rb
68
69
  - lib/squared/common/class.rb
69
70
  - lib/squared/common/format.rb
71
+ - lib/squared/common/prompt.rb
70
72
  - lib/squared/common/shell.rb
71
73
  - lib/squared/common/system.rb
72
74
  - lib/squared/common/task.rb
75
+ - lib/squared/common/utils.rb
73
76
  - lib/squared/config.rb
74
77
  - lib/squared/version.rb
75
78
  - lib/squared/workspace.rb