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
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module GitCompound
|
4
|
+
class Component
|
5
|
+
# Component destination
|
6
|
+
#
|
7
|
+
class Destination
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
def initialize(path, component)
|
11
|
+
raise CompoundSyntaxError, 'Destination cannot be empty' if
|
12
|
+
path.nil? || path.empty?
|
13
|
+
|
14
|
+
raise CompoundSyntaxError,
|
15
|
+
'Destination should contain at least one directory' unless
|
16
|
+
Pathname.new(path).each_filename.count > 0
|
17
|
+
|
18
|
+
@path = path
|
19
|
+
@component = component
|
20
|
+
end
|
21
|
+
|
22
|
+
def expanded_path
|
23
|
+
pathname = Pathname.new(@path)
|
24
|
+
|
25
|
+
unless pathname.absolute?
|
26
|
+
ancestor_paths = @component.ancestors.map(&:destination_path)
|
27
|
+
pathname = Pathname.new('.').join(*ancestor_paths) + pathname
|
28
|
+
end
|
29
|
+
|
30
|
+
Pathname.new("./#{pathname}").cleanpath.to_s + '/'
|
31
|
+
end
|
32
|
+
|
33
|
+
def exists?
|
34
|
+
FileTest.exist?(expanded_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def repository
|
38
|
+
destination_repository =
|
39
|
+
Repository::RepositoryLocal.new(expanded_path)
|
40
|
+
yield destination_repository if block_given?
|
41
|
+
destination_repository
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module GitCompound
|
4
|
+
class Component
|
5
|
+
# Component source
|
6
|
+
#
|
7
|
+
class Source
|
8
|
+
extend Forwardable
|
9
|
+
delegate [:sha, :ref] => :@version
|
10
|
+
attr_reader :origin, :repository, :version, :options
|
11
|
+
|
12
|
+
def initialize(origin, version, strategy, options, component)
|
13
|
+
raise CompoundSyntaxError, 'Source cannot be empty' if
|
14
|
+
origin.nil? || origin.empty?
|
15
|
+
|
16
|
+
@origin = origin
|
17
|
+
@strategy = strategy
|
18
|
+
@options = options
|
19
|
+
@component = component
|
20
|
+
@repository = Repository.factory(@origin)
|
21
|
+
@version = strategy.new(@repository, version)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Loads manifest from source repository
|
25
|
+
#
|
26
|
+
def manifest
|
27
|
+
raise DependencyError,
|
28
|
+
"Version #{@version} unreachable" unless @version.reachable?
|
29
|
+
|
30
|
+
contents = @repository.files_contents(Manifest::FILENAMES, @version.ref)
|
31
|
+
Manifest.new(contents, @component)
|
32
|
+
rescue FileNotFoundError
|
33
|
+
Manifest.new(nil, @component)
|
34
|
+
end
|
35
|
+
|
36
|
+
def clone(destination)
|
37
|
+
@repository.clone(destination, clone_args)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def clone_args
|
43
|
+
raise CompoundSyntaxError,
|
44
|
+
'`shallow` keyword not available for sha version strategy' if
|
45
|
+
@options.include?(:shallow) && @strategy == Component::Version::SHA
|
46
|
+
|
47
|
+
opts = []
|
48
|
+
opts << "--branch '#{@version.ref}' --depth 1" if @options.include? :shallow
|
49
|
+
opts.join(' ')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module GitCompound
|
2
|
+
class Component
|
3
|
+
module Version
|
4
|
+
# Component version indicated by branch (head of branch)
|
5
|
+
#
|
6
|
+
class Branch < VersionStrategy
|
7
|
+
def initialize(repository, branch)
|
8
|
+
@repository = repository
|
9
|
+
@branch = branch
|
10
|
+
end
|
11
|
+
|
12
|
+
def ref
|
13
|
+
@branch
|
14
|
+
end
|
15
|
+
|
16
|
+
def sha
|
17
|
+
@repository.branches[@branch]
|
18
|
+
end
|
19
|
+
|
20
|
+
def reachable?
|
21
|
+
@repository.branches.key?(@branch)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"branch: #{@branch}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module GitCompound
|
2
|
+
class Component
|
3
|
+
module Version
|
4
|
+
# Component Gem-like version
|
5
|
+
#
|
6
|
+
class GemVersion < VersionStrategy
|
7
|
+
attr_reader :requirement
|
8
|
+
|
9
|
+
def initialize(repository, requirement)
|
10
|
+
raise CompoundSyntaxError, 'Malformed version requirement string' unless
|
11
|
+
requirement =~ Gem::Requirement::PATTERN
|
12
|
+
|
13
|
+
@repository = repository
|
14
|
+
@requirement = requirement
|
15
|
+
end
|
16
|
+
|
17
|
+
def lastest_version
|
18
|
+
matches.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def ref
|
22
|
+
lastest_version.tag
|
23
|
+
end
|
24
|
+
|
25
|
+
def sha
|
26
|
+
lastest_version.sha
|
27
|
+
end
|
28
|
+
|
29
|
+
def matches
|
30
|
+
versions = @repository.versions
|
31
|
+
versions.select! { |version| version.matches?(@requirement) }
|
32
|
+
versions.sort.reverse
|
33
|
+
end
|
34
|
+
|
35
|
+
def reachable?
|
36
|
+
matches.any?
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
"gem version: #{@requirement}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GitCompound
|
2
|
+
class Component
|
3
|
+
module Version
|
4
|
+
# Component version indicated by SHA hash
|
5
|
+
#
|
6
|
+
class SHA < VersionStrategy
|
7
|
+
def initialize(repository, sha)
|
8
|
+
@repository = repository
|
9
|
+
@sha = sha
|
10
|
+
end
|
11
|
+
|
12
|
+
def ref
|
13
|
+
@sha
|
14
|
+
end
|
15
|
+
|
16
|
+
def sha # rubocop:disable Style/TrivialAccessors
|
17
|
+
@sha
|
18
|
+
end
|
19
|
+
|
20
|
+
def reachable?
|
21
|
+
# We assume that SHA is always available as we do not want
|
22
|
+
# to clone repository and check it -- this probably needs
|
23
|
+
# to be changed, so -- TODO
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"sha: #{@sha[0..7]}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module GitCompound
|
2
|
+
class Component
|
3
|
+
module Version
|
4
|
+
# Component version as tag
|
5
|
+
#
|
6
|
+
class Tag < VersionStrategy
|
7
|
+
def initialize(repository, tag)
|
8
|
+
@repository = repository
|
9
|
+
@tag = tag
|
10
|
+
end
|
11
|
+
|
12
|
+
def ref
|
13
|
+
@tag
|
14
|
+
end
|
15
|
+
|
16
|
+
def sha
|
17
|
+
@repository.tags[@tag]
|
18
|
+
end
|
19
|
+
|
20
|
+
def reachable?
|
21
|
+
@repository.tags.key?(@tag)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"tag: #{@tag}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module GitCompound
|
2
|
+
class Component
|
3
|
+
module Version
|
4
|
+
# Abstraction for component versions like
|
5
|
+
# gem version, sha and branch
|
6
|
+
#
|
7
|
+
class VersionStrategy
|
8
|
+
def initialize
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
# Should return git reference (ex branch, tag or sha)
|
13
|
+
# This should not raise exception if unreachable
|
14
|
+
#
|
15
|
+
def ref
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
# Should return sha for specified reference
|
20
|
+
# (ex tagged commit sha or head of specified branch)
|
21
|
+
#
|
22
|
+
def sha
|
23
|
+
raise NotImplementedError
|
24
|
+
end
|
25
|
+
|
26
|
+
# Should return true if this reference in source repository
|
27
|
+
# is reachable
|
28
|
+
#
|
29
|
+
def reachable?
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
# String representation of this version strategy
|
34
|
+
#
|
35
|
+
def to_s
|
36
|
+
raise NotImplementedError
|
37
|
+
end
|
38
|
+
|
39
|
+
def ==(other)
|
40
|
+
to_s == other.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module GitCompound
|
5
|
+
# Component
|
6
|
+
#
|
7
|
+
class Component < Node
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
attr_accessor :source, :destination
|
12
|
+
|
13
|
+
def initialize(name, parent = nil, &block)
|
14
|
+
@name = name
|
15
|
+
@parent = parent
|
16
|
+
DSL::ComponentDSL.new(self, &block) if block
|
17
|
+
raise CompoundSyntaxError, "No block given for component `#{@name}`" unless block
|
18
|
+
raise GitCompoundError, "Component `#{@name}` invalid" unless valid?
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
[@name, @source, @destination].all?
|
23
|
+
end
|
24
|
+
|
25
|
+
def process(*workers)
|
26
|
+
workers.each { |worker| worker.visit_component(self) }
|
27
|
+
@manifest.process(*workers) if manifest
|
28
|
+
end
|
29
|
+
|
30
|
+
def manifest
|
31
|
+
@manifest ||= @source.manifest
|
32
|
+
end
|
33
|
+
|
34
|
+
def build
|
35
|
+
@source.clone(destination_path)
|
36
|
+
@destination.repository do |repo|
|
37
|
+
repo.checkout(@source.ref)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def update
|
42
|
+
@destination.repository do |repo|
|
43
|
+
repo.fetch
|
44
|
+
repo.checkout(@source.ref)
|
45
|
+
repo.merge
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def remove!
|
50
|
+
path = destination_path
|
51
|
+
raise GitCompoundError, 'Risky directory !' if
|
52
|
+
path.start_with?('/') || path.include?('..')
|
53
|
+
raise GitCompoundError, 'Not a directory !' unless
|
54
|
+
File.directory?(path)
|
55
|
+
|
56
|
+
FileUtils.remove_entry_secure(path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def ==(other)
|
60
|
+
origin == other.origin || manifest == other.manifest
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_hash
|
64
|
+
{ name: @name,
|
65
|
+
sha: @source.sha,
|
66
|
+
source: @source.origin,
|
67
|
+
destination: @destination.expanded_path
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
# delegators
|
72
|
+
|
73
|
+
delegate [:sha, :origin, :repository, :version] => :@source
|
74
|
+
def_delegator :@destination, :expanded_path, :destination_path
|
75
|
+
def_delegator :@destination, :exists?, :destination_exists?
|
76
|
+
def_delegator :@destination, :repository, :destination_repository
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module GitCompound
|
2
|
+
# Compound Domain Specific Language
|
3
|
+
#
|
4
|
+
module DSL
|
5
|
+
# DSL for Component
|
6
|
+
#
|
7
|
+
class ComponentDSL
|
8
|
+
def initialize(component, &block)
|
9
|
+
@component = component
|
10
|
+
instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Custom version strategy, also available via DSL
|
14
|
+
#
|
15
|
+
def version_strategy(version, strategy)
|
16
|
+
raise CompoundSyntaxError,
|
17
|
+
'Version strategy already set !' if @version_strategy
|
18
|
+
|
19
|
+
@version = version
|
20
|
+
@version_strategy = strategy
|
21
|
+
end
|
22
|
+
|
23
|
+
def version(component_version)
|
24
|
+
version_strategy(component_version, Component::Version::GemVersion)
|
25
|
+
end
|
26
|
+
|
27
|
+
def branch(component_branch)
|
28
|
+
version_strategy(component_branch, Component::Version::Branch)
|
29
|
+
end
|
30
|
+
|
31
|
+
def tag(component_tag)
|
32
|
+
version_strategy(component_tag, Component::Version::Tag)
|
33
|
+
end
|
34
|
+
|
35
|
+
def sha(component_sha)
|
36
|
+
raise CompoundSyntaxError, 'Invalid SHA1 format' unless
|
37
|
+
component_sha.match(/[0-9a-f]{5,40}/)
|
38
|
+
|
39
|
+
version_strategy(component_sha, Component::Version::SHA)
|
40
|
+
end
|
41
|
+
|
42
|
+
def source(component_source, *source_options)
|
43
|
+
raise CompoundSyntaxError,
|
44
|
+
'Version/branch/tag/sha needed first' unless @version
|
45
|
+
|
46
|
+
@component.source =
|
47
|
+
Component::Source.new(component_source,
|
48
|
+
@version,
|
49
|
+
@version_strategy,
|
50
|
+
source_options,
|
51
|
+
@component)
|
52
|
+
end
|
53
|
+
|
54
|
+
def destination(component_path)
|
55
|
+
@component.destination =
|
56
|
+
Component::Destination.new(component_path, @component)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module GitCompound
|
2
|
+
# Compound Domain Specific Language
|
3
|
+
#
|
4
|
+
module DSL
|
5
|
+
# DSL for Manifest
|
6
|
+
#
|
7
|
+
class ManifestDSL
|
8
|
+
def initialize(manifest, contents)
|
9
|
+
@manifest = manifest
|
10
|
+
instance_eval(contents)
|
11
|
+
end
|
12
|
+
|
13
|
+
def name(component_name)
|
14
|
+
@manifest.name = component_name.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def component(name, &block)
|
18
|
+
@manifest.components.store(name.to_sym, Component.new(name, @manifest, &block))
|
19
|
+
end
|
20
|
+
|
21
|
+
def task(name, type = nil, &block)
|
22
|
+
new_task = Task.factory(name, type, @manifest, &block)
|
23
|
+
@manifest.tasks.store(name.to_sym, new_task) if new_task
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module GitCompound
|
2
|
+
class GitCompoundError < StandardError; end
|
3
|
+
|
4
|
+
class CompoundLoadError < GitCompoundError; end
|
5
|
+
class CompoundSyntaxError < GitCompoundError; end
|
6
|
+
class FileNotFoundError < GitCompoundError; end
|
7
|
+
class FileUnreachableError < GitCompoundError; end
|
8
|
+
class RepositoryUnreachableError < GitCompoundError; end
|
9
|
+
class GitCommandError < GitCompoundError; end
|
10
|
+
class LocalRepositoryNotFoundError < GitCompoundError; end
|
11
|
+
class DependencyError < GitCompoundError; end
|
12
|
+
class CircularDependencyError < GitCompoundError; end
|
13
|
+
class ConflictingDependencyError < GitCompoundError; end
|
14
|
+
class NameConstraintError < GitCompoundError; end
|
15
|
+
class LocalChangesError < GitCompoundError; end
|
16
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module GitCompound
|
4
|
+
# Class that represents lock file
|
5
|
+
#
|
6
|
+
class Lock
|
7
|
+
FILENAME = '.gitcompound.lock'
|
8
|
+
|
9
|
+
def self.exist?
|
10
|
+
File.exist?(FILENAME)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(file = FILENAME)
|
14
|
+
@file = file
|
15
|
+
@locked = YAML.load(File.read(file)) if File.exist?(file)
|
16
|
+
clean unless @locked.is_a? Hash
|
17
|
+
end
|
18
|
+
|
19
|
+
def clean
|
20
|
+
@locked = { manifest: '', components: [] }
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def lock_manifest(manifest)
|
25
|
+
@locked[:manifest] = manifest.md5sum
|
26
|
+
end
|
27
|
+
|
28
|
+
def lock_component(component)
|
29
|
+
@locked[:components] << component.to_hash
|
30
|
+
end
|
31
|
+
|
32
|
+
def manifest
|
33
|
+
@locked[:manifest]
|
34
|
+
end
|
35
|
+
|
36
|
+
def components
|
37
|
+
@locked[:components].to_a.map do |locked|
|
38
|
+
Component.new(locked[:name].to_sym) do
|
39
|
+
sha locked[:sha]
|
40
|
+
source locked[:source]
|
41
|
+
destination locked[:destination]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def contents
|
47
|
+
@locked
|
48
|
+
end
|
49
|
+
|
50
|
+
def find(component)
|
51
|
+
components.find do |locked_component|
|
52
|
+
locked_component.destination_path == component.destination_path
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def process(worker)
|
57
|
+
components.each { |component| worker.visit_component(component) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def write
|
61
|
+
File.open(@file, 'w') { |f| f.puts @locked.to_yaml }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module GitCompound
|
2
|
+
module Logger
|
3
|
+
# Colors module
|
4
|
+
#
|
5
|
+
module Colors
|
6
|
+
def self.included(parent_class)
|
7
|
+
parent_class.extend ClassMethods
|
8
|
+
parent_class.class_eval { create_color_methods }
|
9
|
+
end
|
10
|
+
|
11
|
+
def colorize(params)
|
12
|
+
return self if colors_unavailable?
|
13
|
+
scan_colors.inject('') do |str, match|
|
14
|
+
set_colors(match, params)
|
15
|
+
str << "\033[#{match[0]};#{match[1]};#{match[2]}m#{match[3]}\033[0m"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def colors_unavailable?
|
22
|
+
self.class.disable_colors || RUBY_VERSION < '2.0.0' || RUBY_PLATFORM =~ /win32/
|
23
|
+
end
|
24
|
+
|
25
|
+
def scan_colors
|
26
|
+
scan(/\033\[([0-9;]+)m(.+?)\033\[0m|([^\033]+)/m).map do |match|
|
27
|
+
colors = (match[0] || '').split(';')
|
28
|
+
Array.new(4).tap do |array|
|
29
|
+
array[0], array[1], array[2] = colors if colors.length == 3
|
30
|
+
array[3] = match[1] || match[2]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_colors(match, params)
|
36
|
+
default_colors(match)
|
37
|
+
|
38
|
+
mode = mode(params[:mode])
|
39
|
+
color = color(params[:color])
|
40
|
+
bgcolor = bgcolor(params[:bgcolor])
|
41
|
+
|
42
|
+
match[0] = mode if mode
|
43
|
+
match[1] = color if color
|
44
|
+
match[2] = bgcolor if bgcolor
|
45
|
+
end
|
46
|
+
|
47
|
+
def default_colors(match)
|
48
|
+
match[0] ||= mode(:default)
|
49
|
+
match[1] ||= color(:default)
|
50
|
+
match[2] ||= bgcolor(:default)
|
51
|
+
end
|
52
|
+
|
53
|
+
def color(color)
|
54
|
+
self.class.colors[color] + 30 if self.class.colors[color]
|
55
|
+
end
|
56
|
+
|
57
|
+
def bgcolor(color)
|
58
|
+
self.class.colors[color] + 40 if self.class.colors[color]
|
59
|
+
end
|
60
|
+
|
61
|
+
def mode(mode)
|
62
|
+
self.class.modes[mode] if self.class.modes[mode]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Class methods core ext for String
|
67
|
+
#
|
68
|
+
module ClassMethods
|
69
|
+
def disable_colors=(value)
|
70
|
+
@disable_colors = value && true
|
71
|
+
end
|
72
|
+
|
73
|
+
def disable_colors
|
74
|
+
@disable_colors ||= false
|
75
|
+
end
|
76
|
+
|
77
|
+
def colors
|
78
|
+
{
|
79
|
+
black: 0,
|
80
|
+
red: 1,
|
81
|
+
green: 2,
|
82
|
+
yellow: 3,
|
83
|
+
blue: 4,
|
84
|
+
magenta: 5,
|
85
|
+
cyan: 6,
|
86
|
+
white: 7,
|
87
|
+
default: 9
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def modes
|
92
|
+
{
|
93
|
+
default: 0,
|
94
|
+
bold: 1
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def create_color_methods
|
101
|
+
colors.keys.each do |key|
|
102
|
+
next if key == :default
|
103
|
+
|
104
|
+
define_method key do
|
105
|
+
colorize(color: key)
|
106
|
+
end
|
107
|
+
|
108
|
+
define_method "on_#{key}" do
|
109
|
+
colorize(bgcolor: key)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
modes.keys.each do |key|
|
114
|
+
next if key == :default
|
115
|
+
|
116
|
+
define_method key do
|
117
|
+
colorize(mode: key)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module GitCompound
|
2
|
+
# Logger class
|
3
|
+
#
|
4
|
+
module Logger
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def verbose=(value)
|
8
|
+
@verbose = value && true
|
9
|
+
end
|
10
|
+
|
11
|
+
def verbose
|
12
|
+
@verbose ||= false
|
13
|
+
end
|
14
|
+
|
15
|
+
def inline(inline_message)
|
16
|
+
print inline_message
|
17
|
+
inline_message
|
18
|
+
end
|
19
|
+
|
20
|
+
def debug(debug_message, *params)
|
21
|
+
log(debug_message.cyan, *params) if verbose
|
22
|
+
end
|
23
|
+
|
24
|
+
def info(information_message, *params)
|
25
|
+
log(information_message, *params)
|
26
|
+
end
|
27
|
+
|
28
|
+
def warn(warning_message, *params)
|
29
|
+
log(warning_message.red.bold, *params)
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(error_message, *params)
|
33
|
+
log(error_message.on_red.white.bold, *params)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def log(message, *params)
|
39
|
+
puts message unless params.include?(:quiet)
|
40
|
+
message
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|