git_compound 0.0.9
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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/Compoundfile +4 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +291 -0
- data/Rakefile +13 -0
- data/bin/console +7 -0
- data/bin/setup +5 -0
- data/exe/gitcompound +5 -0
- data/git_compound.gemspec +33 -0
- data/lib/git_compound/builder.rb +93 -0
- data/lib/git_compound/command/options.rb +55 -0
- data/lib/git_compound/command.rb +113 -0
- data/lib/git_compound/component/destination.rb +45 -0
- data/lib/git_compound/component/source.rb +53 -0
- data/lib/git_compound/component/version/branch.rb +30 -0
- data/lib/git_compound/component/version/gem_version.rb +45 -0
- data/lib/git_compound/component/version/sha.rb +33 -0
- data/lib/git_compound/component/version/tag.rb +30 -0
- data/lib/git_compound/component/version/version_strategy.rb +45 -0
- data/lib/git_compound/component.rb +78 -0
- data/lib/git_compound/dsl/component_dsl.rb +60 -0
- data/lib/git_compound/dsl/manifest_dsl.rb +27 -0
- data/lib/git_compound/exceptions.rb +16 -0
- data/lib/git_compound/lock.rb +64 -0
- data/lib/git_compound/logger/colors.rb +123 -0
- data/lib/git_compound/logger/core_ext/string.rb +5 -0
- data/lib/git_compound/logger.rb +43 -0
- data/lib/git_compound/manifest.rb +39 -0
- data/lib/git_compound/node.rb +17 -0
- data/lib/git_compound/repository/git_command.rb +33 -0
- data/lib/git_compound/repository/git_repository.rb +79 -0
- data/lib/git_compound/repository/git_version.rb +43 -0
- data/lib/git_compound/repository/remote_file/git_archive_strategy.rb +30 -0
- data/lib/git_compound/repository/remote_file/github_strategy.rb +54 -0
- data/lib/git_compound/repository/remote_file/remote_file_strategy.rb +27 -0
- data/lib/git_compound/repository/remote_file.rb +34 -0
- data/lib/git_compound/repository/repository_local.rb +81 -0
- data/lib/git_compound/repository/repository_remote.rb +12 -0
- data/lib/git_compound/repository.rb +19 -0
- data/lib/git_compound/task/task.rb +28 -0
- data/lib/git_compound/task/task_all.rb +27 -0
- data/lib/git_compound/task/task_each.rb +18 -0
- data/lib/git_compound/task/task_single.rb +21 -0
- data/lib/git_compound/task.rb +22 -0
- data/lib/git_compound/version.rb +5 -0
- data/lib/git_compound/worker/circular_dependency_checker.rb +31 -0
- data/lib/git_compound/worker/component_builder.rb +30 -0
- data/lib/git_compound/worker/component_replacer.rb +25 -0
- data/lib/git_compound/worker/component_update_dispatcher.rb +64 -0
- data/lib/git_compound/worker/component_updater.rb +24 -0
- data/lib/git_compound/worker/components_collector.rb +20 -0
- data/lib/git_compound/worker/conflicting_dependency_checker.rb +31 -0
- data/lib/git_compound/worker/local_changes_guard.rb +47 -0
- data/lib/git_compound/worker/name_constraint_checker.rb +20 -0
- data/lib/git_compound/worker/pretty_print.rb +18 -0
- data/lib/git_compound/worker/task_runner.rb +12 -0
- data/lib/git_compound/worker/worker.rb +20 -0
- data/lib/git_compound.rb +112 -0
- metadata +193 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 612c6d116fee9bcaaee021484a7679932bb3e675
|
4
|
+
data.tar.gz: cdd8dc429c4481348cbbea8a98f9faeb103c463c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e7dbe4c61f12ccd94571ef2e44c55fce8b35f7c32ac0e9a05bc586d68708728a43157f7441c1d47bfb713e1c19cac367f1229a0177454495ad1a8619749d5fa5
|
7
|
+
data.tar.gz: 8ba2126a8ea301f628bab615f0af411b4b13a1cecc1951cf321eb906d95e8a1ce556ba7175a19a674470641be8635e6fc35acb90b24b28ab92f43907963117d6
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/Compoundfile
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Grzegorz Bizon <grzegorz.bizon@ntsn.pl>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
# Git Compound
|
2
|
+
|
3
|
+
Compose your project using git repositories and ruby tasks
|
4
|
+
|
5
|
+
## Status
|
6
|
+
|
7
|
+
This project is in alpha phase
|
8
|
+
|
9
|
+
## Overview
|
10
|
+
|
11
|
+
Create `Compoundfile` or `.gitcompound` manifest:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
name :base_component
|
15
|
+
|
16
|
+
component :component_1 do
|
17
|
+
version '~>1.1'
|
18
|
+
source 'git@github.com:/user/repository'
|
19
|
+
destination 'src/component_1'
|
20
|
+
end
|
21
|
+
|
22
|
+
component :component_2 do
|
23
|
+
version '>=2.0'
|
24
|
+
source 'git@github.com:/user/repository_2'
|
25
|
+
destination 'src/component_2'
|
26
|
+
end
|
27
|
+
|
28
|
+
component :component_3 do
|
29
|
+
branch 'feature/new-feature'
|
30
|
+
source '/my/component_3/repository'
|
31
|
+
destination 'src/component_3'
|
32
|
+
end
|
33
|
+
|
34
|
+
task 'add components to gitignore', :each do |component_dir|
|
35
|
+
File.open('.gitignore', 'a') { |f| f.write "#{component_dir}\n" }
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
GitCompound will also process similar manifests found in required components in hierarchical way.
|
40
|
+
|
41
|
+
Then run `gitcompound build`.
|
42
|
+
|
43
|
+
|
44
|
+
## Core features
|
45
|
+
|
46
|
+
`GitCompound` is more a distributed packaging system than alternative to Git submodules.
|
47
|
+
|
48
|
+
`GitCompound` makes sure your project composition is the same on all machines,
|
49
|
+
but you can have different composition depending on manifest you are using.
|
50
|
+
|
51
|
+
It has been created with Docker compatiblity in mind.
|
52
|
+
|
53
|
+
Core features:
|
54
|
+
|
55
|
+
* `GitCompound` introduces Domain Specific Language desgined for writing manifests.
|
56
|
+
|
57
|
+
* It is possible to create multiple manifest files (`Compoundfile`, `.gitcompound` or something else)
|
58
|
+
and build them when necessary.
|
59
|
+
|
60
|
+
* Building manifest create lockfile (locking components on specific commit SHA). When lockfile is present if will
|
61
|
+
be used each time `build` command is invoked.
|
62
|
+
|
63
|
+
* Manifests can declare dependencies on different versions of components using different version strategies
|
64
|
+
(Rubygems-like version, tag, branch or explicit SHA).
|
65
|
+
|
66
|
+
* Manifests will be processed in hierarchical way. Manifest that `gitcompound` command is run against
|
67
|
+
is root manifest. `GitCompound` processes all subsequent manifests found in dependencies using depth-first
|
68
|
+
search of dependency graph.
|
69
|
+
|
70
|
+
* Root manifest and manifest of each subsequent component can declare Ruby tasks that will be executed
|
71
|
+
when component is built or updated.
|
72
|
+
|
73
|
+
* It is possible to install dependencies in root directory (`Dir.pwd` where `gitcompound` command is invoked).
|
74
|
+
Each subsequent component can install their dependencies into root directory (see overview for **destination** DSL method).
|
75
|
+
|
76
|
+
* Build process creates lockfile in `.gitcompound.lock`. It locks components on specific commit SHAs.
|
77
|
+
It is then possible to build components directly, depending on versions (SHAs) from lockfile.
|
78
|
+
|
79
|
+
## Commands
|
80
|
+
|
81
|
+
### build
|
82
|
+
|
83
|
+
`gitcompound build [manifest]` -- builds project from manifest or lockfile
|
84
|
+
|
85
|
+
If manifest is not supplied, it uses `Compoundfile` or `.gitcompound`
|
86
|
+
|
87
|
+
### update
|
88
|
+
|
89
|
+
`gitcompound update [manifest]` -- updates project and lockfile
|
90
|
+
|
91
|
+
### check
|
92
|
+
|
93
|
+
`gitcompound check [manifest]` -- checks for circular dependencies, conflicting dependencies
|
94
|
+
and name constraints
|
95
|
+
|
96
|
+
### show
|
97
|
+
|
98
|
+
`gitcompound show [manifest]` -- prints project structure
|
99
|
+
|
100
|
+
### help
|
101
|
+
|
102
|
+
`gitcompound help` -- prints help message
|
103
|
+
|
104
|
+
## Global options
|
105
|
+
|
106
|
+
1. `--verbose` -- turns debug mode on
|
107
|
+
2. `--disable-colors` -- disables ANSI colors in output
|
108
|
+
|
109
|
+
## Details
|
110
|
+
|
111
|
+
1. Use `name` method to specify **name** of manifest or component that this manifest is included in.
|
112
|
+
|
113
|
+
2. Add dependency to required **component** using `component` method.
|
114
|
+
|
115
|
+
This method takes two parameters -- name of component (as symbol) and implicit or explicit block.
|
116
|
+
|
117
|
+
Beware that `GitCompound` checks name constraints, so if you rely on component
|
118
|
+
with name `:component_1`, and this component has `Compoundfile` inside that declares
|
119
|
+
it's name as something else than `:component_1` -- `GitCompound` will raise exception.
|
120
|
+
|
121
|
+
3. Components can use following **version strategies**:
|
122
|
+
|
123
|
+
* `version` -- Rubygems-like **version** strategy
|
124
|
+
|
125
|
+
This strategy uses Git tags to determine available component versions.
|
126
|
+
If tag matches `/^v?#{Gem::Version::VERSION_PATTERN}$/` then it is considered to
|
127
|
+
be version tag and therefore it can be used with Rubygems syntax
|
128
|
+
(like pessimistic version constraint operator)
|
129
|
+
|
130
|
+
* `tag` -- use component sources specified by **tag**
|
131
|
+
|
132
|
+
* `branch` -- use HEAD of given **branch**
|
133
|
+
|
134
|
+
* `sha` -- use explicitly set commit **SHA**
|
135
|
+
|
136
|
+
4. Provide path to **source** repository using `source` method of manifest domain specific language.
|
137
|
+
|
138
|
+
It will be used as source to clone repository into destination directory.
|
139
|
+
|
140
|
+
This can take `:shallow` parameter. When `:shallow` is set, shallow clone will be
|
141
|
+
performed (`--branch #{ref} --depth 1`):
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
component :bootstrap do
|
145
|
+
version '~>3.3.5'
|
146
|
+
source 'git@github.com:twbs/bootstrap', :shallow
|
147
|
+
destination '/vendor/bootstrap
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
However using it is not recommended at all.
|
152
|
+
|
153
|
+
It can be helpful when required component is big and you need to build your project
|
154
|
+
only once, but it will cause issues with update. You will not be able to update it properly.
|
155
|
+
Use it with caution !
|
156
|
+
|
157
|
+
|
158
|
+
5. Use `destination` method to specify **destination** path where component will be cloned into.
|
159
|
+
|
160
|
+
This should be relative path in most cases.
|
161
|
+
|
162
|
+
Relative path is always relative to parent component directory. So if you define
|
163
|
+
`component_1` with destination path `component_1/`, and this component will
|
164
|
+
depend on `component_2` with destination path set to `src/component_2`, you will
|
165
|
+
end with `./component_1/src/component_2` directory after building components.
|
166
|
+
|
167
|
+
When path is absolute -- it will be always relative to `Dir.pwd` where
|
168
|
+
you invoke `gitcompound *` commands. So if you have `component_1` with destination path
|
169
|
+
set to `/component_1` and `component_1` which has manifest that depends on `component_2` with
|
170
|
+
destination path set to `/component_2`, then `GitCompound` will create two separate
|
171
|
+
directories in `Dir.pwd`: `./component_1` and `./component_2`.
|
172
|
+
|
173
|
+
Use absolute paths with caution as it affects how parent projects will be built.
|
174
|
+
Ceraintly components that are libraries should not use it at all. If component is project --
|
175
|
+
it can take benefit from using absolute paths in component destination.
|
176
|
+
|
177
|
+
6. Running tasks
|
178
|
+
|
179
|
+
It is possible to use `task` method to define new **task**. `task` method takes 2 or 3 arguments.
|
180
|
+
First one is task name (symbol). Second one is optional task type that define how, and
|
181
|
+
in which context, task will be executed. Third one is block that will be excuted.
|
182
|
+
|
183
|
+
Currently there are three task types:
|
184
|
+
|
185
|
+
* `:manifest` type (this is default) -- run task in context of current manifest
|
186
|
+
|
187
|
+
Task will be executed only once, in context of current manifest this task is
|
188
|
+
defined in. Example:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
task :print_manifest_name do |dir, manifest|
|
192
|
+
puts "Current manifest name is #{manifest.name} and dir is: #{dir}"
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
* `:each` type -- run task for each component defined in current manifest
|
197
|
+
|
198
|
+
This executes task for all components that are explicitly defined in current manifest.
|
199
|
+
Example:
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
task :print_component_name, :each do |dir, component|
|
203
|
+
puts "Current component name: #{component.name}"
|
204
|
+
puts "Current component source: #{component.origin}
|
205
|
+
puts "Current component destination: #{component.destination_path}
|
206
|
+
|
207
|
+
puts "Component directory: #{dir}"
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
Note that `dir` here is the same as `component.destination_path`.
|
212
|
+
|
213
|
+
* `:all` type -- run task for all child components of this manifest
|
214
|
+
|
215
|
+
Task for `:all` components will be executed in context of every component
|
216
|
+
this manifest is parent of.
|
217
|
+
|
218
|
+
It will be executed for all components defined in manifest itself and for all
|
219
|
+
components that are included in child manifests (obviously child manifests are
|
220
|
+
manifests included in components defined in parent manifest).
|
221
|
+
|
222
|
+
Example:
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
task :print_all_component_names, :all do |dir, component|
|
226
|
+
puts "Component #{component.name} destination dir: #{dir}"
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
By default `GitCompound` executes only tasks defined in root manifest.
|
231
|
+
|
232
|
+
This is default behaviour dictated by security reasons. Since all tasks (also those defined
|
233
|
+
in child component) are visited in reverse order it is possible to execute them too.
|
234
|
+
|
235
|
+
If you know what you are doing and it is your conscious decision to run all tasks in project
|
236
|
+
pass `--allow-nested-subtasks` options to `build` or `update` command.
|
237
|
+
|
238
|
+
It can be beneficial approach, but it has to be done with caution.
|
239
|
+
|
240
|
+
## Other concepts
|
241
|
+
|
242
|
+
1. Accessing manifests
|
243
|
+
|
244
|
+
`GitCompound` tries to be as fast as possible. To achieve this it tries to access
|
245
|
+
manifest of required component without cloning it first. Is uses different strategies to
|
246
|
+
achieve this. Currently only two strategies are available:
|
247
|
+
|
248
|
+
* `GitArchiveStrategy` -- it uses `git archive` command to access single file in remote
|
249
|
+
repository,
|
250
|
+
* `GithubStrategy` -- it uses http request to `raw.githubusercontent.com` to access
|
251
|
+
manifest file at GitHub.
|
252
|
+
|
253
|
+
It is possible to create new strategies by implementing new strategy base on
|
254
|
+
`GitCompound::Repository::RemoteFile::RemoteFileStrategy` abstraction.
|
255
|
+
|
256
|
+
2. Using lockfile (`.gitcompound.lock`)
|
257
|
+
|
258
|
+
If lockfile is present, `gitcompound build` command will ignore manifest, and build
|
259
|
+
components, with versions locked in commit SHA. You can always be sure that your
|
260
|
+
environment will be unchange when building from lockfile.
|
261
|
+
|
262
|
+
3. Building manifest
|
263
|
+
|
264
|
+
Behavior of `build` command depends on whether lockfile exists or not.
|
265
|
+
|
266
|
+
* When lockfile does not exist -- components will be built using versions stored in manifest.
|
267
|
+
|
268
|
+
Then lockfile `.gitcompound.lock` will be created, locking each component on specific commit SHA
|
269
|
+
that component has been checkout on during build process.
|
270
|
+
|
271
|
+
* If lockfile is present it will be used as source for update process (see "Updating manifest" below)
|
272
|
+
|
273
|
+
4. Updating manifest
|
274
|
+
|
275
|
+
When using `gitcompound update` command each subsequent component will be either
|
276
|
+
built, updated or replaced:
|
277
|
+
|
278
|
+
* built (cloned) -- if destination directory does not exist
|
279
|
+
* updated (fetch & checkout) -- if component exists, matches origin and existing SHA != new SHA
|
280
|
+
* replaced (remove & clone) -- if component exists but doesn't match origin remote
|
281
|
+
|
282
|
+
When invoking update process via `gitcompound update` command, versions specified in manifest file
|
283
|
+
will be use.
|
284
|
+
|
285
|
+
## Roadmap
|
286
|
+
|
287
|
+
Take a look at issues at GitHub.
|
288
|
+
|
289
|
+
## License
|
290
|
+
|
291
|
+
This is free software licensed under MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new('spec')
|
6
|
+
RuboCop::RakeTask.new
|
7
|
+
|
8
|
+
task :test do
|
9
|
+
Rake::Task['rubocop'].invoke
|
10
|
+
Rake::Task['spec'].invoke
|
11
|
+
end
|
12
|
+
|
13
|
+
task default: :test
|
data/bin/console
ADDED
data/bin/setup
ADDED
data/exe/gitcompound
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'git_compound/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'git_compound'
|
8
|
+
spec.version = GitCompound::VERSION
|
9
|
+
spec.authors = ['Grzegorz Bizon']
|
10
|
+
spec.email = ['grzegorz.bizon@ntsn.pl']
|
11
|
+
spec.summary = 'Compose you project using git repositories and ruby tasks'
|
12
|
+
spec.homepage = 'https://github.com/grzesiek/git_compound'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(/^spec/) }
|
16
|
+
spec.bindir = 'exe'
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
# rubocop:disable Style/SingleSpaceBeforeFirstArg
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.8'
|
22
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
23
|
+
spec.add_development_dependency 'rubocop', '~> 0.31.0'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.2.0'
|
25
|
+
spec.add_development_dependency 'pry', '~> 0.10.1'
|
26
|
+
spec.add_development_dependency 'simplecov', '~> 0.10.0'
|
27
|
+
# rubocop:enable Style/SingleSpaceBeforeFirstArg
|
28
|
+
|
29
|
+
spec.requirements << 'git scm version > 2'
|
30
|
+
spec.requirements << 'gnu tar'
|
31
|
+
|
32
|
+
spec.required_ruby_version = '>= 2.2'
|
33
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module GitCompound
|
2
|
+
# Builder class, responsible for building project
|
3
|
+
# from manifest or lockfile
|
4
|
+
#
|
5
|
+
class Builder
|
6
|
+
def initialize(manifest, lock, opts)
|
7
|
+
@manifest = manifest
|
8
|
+
@lock = lock
|
9
|
+
@opts = opts
|
10
|
+
end
|
11
|
+
|
12
|
+
def manifest_build
|
13
|
+
Logger.info 'Building components ...'
|
14
|
+
@manifest.process(Worker::ComponentBuilder.new(@lock))
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def manifest_update
|
19
|
+
Logger.info 'Updating components ...'
|
20
|
+
@lock_new = Lock.new.clean
|
21
|
+
@manifest.process(Worker::ComponentUpdateDispatcher.new(@lock_new))
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def manifest_lock
|
26
|
+
lock = @lock_new ? @lock_new : @lock
|
27
|
+
lock.lock_manifest(@manifest)
|
28
|
+
lock.write
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def dependencies_check
|
33
|
+
Logger.info 'Checking dependencies ...'
|
34
|
+
|
35
|
+
@manifest.process(
|
36
|
+
Worker::CircularDependencyChecker.new,
|
37
|
+
Worker::NameConstraintChecker.new,
|
38
|
+
Worker::ConflictingDependencyChecker.new)
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def components_show
|
43
|
+
Logger.info 'Processing components list ...'
|
44
|
+
@manifest.process(
|
45
|
+
Worker::CircularDependencyChecker.new,
|
46
|
+
Worker::PrettyPrint.new)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def tasks_execute
|
51
|
+
Logger.info 'Running tasks ...'
|
52
|
+
|
53
|
+
if @opts.include?(:allow_nested_subtasks)
|
54
|
+
@manifest.process(Worker::TaskRunner.new)
|
55
|
+
else
|
56
|
+
@manifest.tasks.each_value(&:execute)
|
57
|
+
end
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def locked_manifest_verify
|
62
|
+
return self if @manifest.md5sum == @lock.manifest
|
63
|
+
raise GitCompoundError,
|
64
|
+
'Manifest md5sum has changed ! Use `update` command.'
|
65
|
+
end
|
66
|
+
|
67
|
+
def locked_components_build
|
68
|
+
Logger.info 'Building components from lockfile ...'
|
69
|
+
@lock.process(Worker::ComponentUpdateDispatcher.new(@lock))
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def locked_components_guard
|
74
|
+
@lock.process(Worker::LocalChangesGuard.new(@lock))
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def locked_dormant_components_remove
|
79
|
+
raise GitCompoundError, 'No new lockfile !' unless @lock_new
|
80
|
+
|
81
|
+
dormant_components = @lock.components.reject do |component|
|
82
|
+
@lock_new.find(component) ? true : false
|
83
|
+
end
|
84
|
+
|
85
|
+
dormant_components.each do |component|
|
86
|
+
Logger.warn "Removing dormant component `#{component.name}` " \
|
87
|
+
"from `#{component.destination_path}` !"
|
88
|
+
|
89
|
+
component.remove!
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module GitCompound
|
2
|
+
module Command
|
3
|
+
# Class that parses command arguments
|
4
|
+
#
|
5
|
+
class Options
|
6
|
+
GLOBAL_OPTIONS = [:verbose, :disable_colors]
|
7
|
+
|
8
|
+
def initialize(args)
|
9
|
+
@command, @args = parse_options(args)
|
10
|
+
|
11
|
+
set_global_options
|
12
|
+
end
|
13
|
+
|
14
|
+
def global_options
|
15
|
+
@args & GLOBAL_OPTIONS
|
16
|
+
end
|
17
|
+
|
18
|
+
def command_options
|
19
|
+
@args - GLOBAL_OPTIONS
|
20
|
+
end
|
21
|
+
|
22
|
+
def command
|
23
|
+
@command || 'help'
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse
|
27
|
+
[command, command_options]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.verbose=(mode)
|
31
|
+
GitCompound::Logger.verbose = mode
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.disable_colors=(mode)
|
35
|
+
String.disable_colors = mode
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def parse_options(args)
|
41
|
+
opts_dash = args.select { |opt| opt.start_with?('--') }
|
42
|
+
opts_string = args - opts_dash
|
43
|
+
command = opts_string.shift
|
44
|
+
opts_sym = opts_dash.collect { |opt| opt.sub(/^--/, '').gsub('-', '_').to_sym }
|
45
|
+
[command, opts_string + opts_sym]
|
46
|
+
end
|
47
|
+
|
48
|
+
def set_global_options
|
49
|
+
global_options.each do |option|
|
50
|
+
self.class.public_send("#{option}=", true)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module GitCompound
|
2
|
+
# GitCompount command facade
|
3
|
+
#
|
4
|
+
module Command
|
5
|
+
def build(*args)
|
6
|
+
if Lock.exist?
|
7
|
+
builder(args)
|
8
|
+
.locked_manifest_verify
|
9
|
+
.locked_components_build
|
10
|
+
.tasks_execute
|
11
|
+
else
|
12
|
+
builder(args)
|
13
|
+
.dependencies_check
|
14
|
+
.manifest_build
|
15
|
+
.tasks_execute
|
16
|
+
.manifest_lock
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def update(*args)
|
21
|
+
raise GitCompoundError,
|
22
|
+
"Lockfile `#{Lock::FILENAME}` does not exist ! " \
|
23
|
+
'You should use `build` command.' unless Lock.exist?
|
24
|
+
|
25
|
+
builder(args)
|
26
|
+
.locked_components_guard
|
27
|
+
.dependencies_check
|
28
|
+
.manifest_update
|
29
|
+
.tasks_execute
|
30
|
+
.manifest_lock
|
31
|
+
.locked_dormant_components_remove
|
32
|
+
end
|
33
|
+
|
34
|
+
def check(*args)
|
35
|
+
builder(args).dependencies_check
|
36
|
+
Logger.info 'OK'
|
37
|
+
end
|
38
|
+
|
39
|
+
def show(*args)
|
40
|
+
builder(args).components_show
|
41
|
+
end
|
42
|
+
|
43
|
+
def help(*_args)
|
44
|
+
Logger.info(usage)
|
45
|
+
end
|
46
|
+
|
47
|
+
def run(command, args)
|
48
|
+
abort(usage) unless methods.include?(command.to_sym)
|
49
|
+
|
50
|
+
Logger.debug("GitCompound v#{GitCompound::VERSION}")
|
51
|
+
Logger.debug("Running command '#{command}'")
|
52
|
+
|
53
|
+
public_send(command, *args)
|
54
|
+
rescue GitCompoundError => e
|
55
|
+
abort Logger.error("Error: #{e.message}", :quiet)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def builder(args)
|
61
|
+
Builder.new(manifest(args.first), Lock.new, args)
|
62
|
+
end
|
63
|
+
|
64
|
+
def manifest(filename)
|
65
|
+
files = filename ? [filename] : Manifest::FILENAMES
|
66
|
+
found = files.select { |file| File.exist?(file) }
|
67
|
+
|
68
|
+
raise GitCompoundError,
|
69
|
+
"Manifest `#{filename || files.inspect}` not found !" if found.empty?
|
70
|
+
|
71
|
+
contents = File.read(found.first)
|
72
|
+
Manifest.new(contents)
|
73
|
+
end
|
74
|
+
|
75
|
+
# rubocop:disable Metrics/AbcSize
|
76
|
+
def usage
|
77
|
+
<<-EOS
|
78
|
+
#{'GitCompound version'.bold.yellow} #{GitCompound::VERSION.bold}
|
79
|
+
|
80
|
+
Usage: #{'gitcompound'.bold.green} #{
|
81
|
+
'[options]'.green} #{'command'.bold} #{'[manifest_file]'.green}
|
82
|
+
|
83
|
+
Commands:
|
84
|
+
#{'build'.bold}
|
85
|
+
builds project from manifest (or lockfile if present)
|
86
|
+
|
87
|
+
If manifest is not specified it uses one of
|
88
|
+
#{Manifest::FILENAMES.inspect}
|
89
|
+
|
90
|
+
#{'update'.bold}
|
91
|
+
updates project
|
92
|
+
|
93
|
+
#{'check'.bold}
|
94
|
+
detects circular depenencies, conflicting dependencies
|
95
|
+
and checks for name contraints
|
96
|
+
|
97
|
+
#{'show'.bold}
|
98
|
+
prints structure of project
|
99
|
+
|
100
|
+
#{'help'.bold}
|
101
|
+
prints this help
|
102
|
+
|
103
|
+
Options:'
|
104
|
+
#{'--verbose'.bold}
|
105
|
+
prints verbose log info
|
106
|
+
|
107
|
+
#{'--disable-colors'.bold}
|
108
|
+
disable ANSI colors in output
|
109
|
+
EOS
|
110
|
+
end
|
111
|
+
# rubocop:enable Metrics/AbcSize
|
112
|
+
end
|
113
|
+
end
|