elm_install 0.1.1 → 0.1.2
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/.gitignore +1 -0
- data/.reek +4 -0
- data/.rspec +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +12 -2
- data/Rakefile +1 -0
- data/docs/How it works.md +48 -0
- data/elm_install.gemspec +1 -0
- data/lib/elm_install.rb +1 -0
- data/lib/elm_install/base.rb +37 -0
- data/lib/elm_install/cache.rb +5 -90
- data/lib/elm_install/elm_package.rb +36 -0
- data/lib/elm_install/git_resolver.rb +80 -0
- data/lib/elm_install/installer.rb +47 -82
- data/lib/elm_install/logger.rb +14 -0
- data/lib/elm_install/populator.rb +81 -0
- data/lib/elm_install/resolver.rb +26 -19
- data/lib/elm_install/utils.rb +1 -16
- data/lib/elm_install/version.rb +1 -1
- data/packaging/Gemfile.lock +5 -3
- data/spec/elm_package_spec.rb +31 -0
- data/spec/git_resolver_spec.rb +82 -0
- data/spec/resolver_spec.rb +65 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/utils_spec.rb +34 -0
- metadata +29 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 866f31dd5848df9cc5fdce2188f1de72c04d8863
|
4
|
+
data.tar.gz: 5e78e0422f41adbcc320908a4d704429c4f030ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9807dde1aba8c797b9f9e4db38885ff67f54c132eb022bb2733ec75fcfa09863260332fbd2bcca97a6ec5501d8a718e26350e0a4bb05eb84610f1e7eb0ee755c
|
7
|
+
data.tar.gz: 3877767e0e6038f564e01016d378ceae90120c68efc99accf0f3edfe523abd2b32f872fc2768a51872f5277c56e0bfba6d5f6ef0226bf4b1822fe5ad497c400c
|
data/.gitignore
CHANGED
data/.reek
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
elm_install (0.1.
|
4
|
+
elm_install (0.1.2)
|
5
5
|
commander (~> 4.4, >= 4.4.2)
|
6
6
|
git (~> 1.3)
|
7
7
|
git_clone_url (~> 2.0)
|
8
8
|
hashdiff (~> 0.3.1)
|
9
|
+
indentation (~> 0.1.1)
|
9
10
|
smart_colored (~> 1.1, >= 1.1.1)
|
10
11
|
solve (~> 3.1)
|
11
12
|
|
@@ -28,6 +29,7 @@ GEM
|
|
28
29
|
descendants_tracker (0.0.4)
|
29
30
|
thread_safe (~> 0.3, >= 0.3.1)
|
30
31
|
diff-lcs (1.2.5)
|
32
|
+
docile (1.1.5)
|
31
33
|
equalizer (0.0.11)
|
32
34
|
erubis (2.7.0)
|
33
35
|
flay (2.8.1)
|
@@ -45,6 +47,8 @@ GEM
|
|
45
47
|
hashdiff (0.3.1)
|
46
48
|
highline (1.7.8)
|
47
49
|
ice_nine (0.11.2)
|
50
|
+
indentation (0.1.1)
|
51
|
+
json (2.0.2)
|
48
52
|
launchy (2.4.3)
|
49
53
|
addressable (~> 2.3)
|
50
54
|
molinillo (0.5.4)
|
@@ -91,6 +95,11 @@ GEM
|
|
91
95
|
virtus (~> 1.0)
|
92
96
|
semverse (2.0.0)
|
93
97
|
sexp_processor (4.7.0)
|
98
|
+
simplecov (0.12.0)
|
99
|
+
docile (~> 1.1.0)
|
100
|
+
json (>= 1.8, < 3)
|
101
|
+
simplecov-html (~> 0.10.0)
|
102
|
+
simplecov-html (0.10.0)
|
94
103
|
smart_colored (1.1.1)
|
95
104
|
solve (3.1.0)
|
96
105
|
molinillo (>= 0.5)
|
@@ -112,6 +121,7 @@ DEPENDENCIES
|
|
112
121
|
rspec (~> 3.5)
|
113
122
|
rubocop (~> 0.46.0)
|
114
123
|
rubycritic (~> 3.1, >= 3.1.3)
|
124
|
+
simplecov (~> 0.12.0)
|
115
125
|
|
116
126
|
BUNDLED WITH
|
117
|
-
1.13.
|
127
|
+
1.13.7
|
data/Rakefile
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
Program flow
|
2
|
+
------------
|
3
|
+
|
4
|
+
1. Try to load the cache of dependencies from `~/.elm-install/cache.json` and
|
5
|
+
load the cache of references from `~/.elm-install/ref-cache.json`. If no
|
6
|
+
cache files found initialize empty caches.
|
7
|
+
|
8
|
+
2. Read `dependencies` and `dependency-sources` from `elm-package.json` and
|
9
|
+
transform them from:
|
10
|
+
|
11
|
+
```
|
12
|
+
{
|
13
|
+
"dependencies": {
|
14
|
+
"elm-lang/core": "5.0.0 <= 6.0.0",
|
15
|
+
"gdotdesign/elm-ui": "1.0.0 <= 2.0.0"
|
16
|
+
},
|
17
|
+
"dependency-sources": {
|
18
|
+
"gdotdesign/elm-ui": {
|
19
|
+
"url": "git@bitbucket.com:gdotdesign/elm-ui",
|
20
|
+
"ref": "development"
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
```
|
25
|
+
|
26
|
+
to:
|
27
|
+
|
28
|
+
```
|
29
|
+
{
|
30
|
+
"git@github.com:elm-lang/core": "5.0.0 <= 6.0.0",
|
31
|
+
"git@bitbucket.com:gdotdesign/elm-ui": "development"
|
32
|
+
}
|
33
|
+
```
|
34
|
+
|
35
|
+
3. Add dependencies to the cache, skipping if the package is already added.
|
36
|
+
|
37
|
+
4. Solved dependencies from the cache.
|
38
|
+
|
39
|
+
5. (If no solution found) Go through the packages from the cache and update
|
40
|
+
their references and if it changed update the repository (fetching new
|
41
|
+
content)
|
42
|
+
|
43
|
+
6. (If no solution found) Solve dependencies from the updated cache.
|
44
|
+
|
45
|
+
7. Save cache.
|
46
|
+
|
47
|
+
7. (If solution found) Populate `elm-stuff` and write
|
48
|
+
`elm-stuff/exact-dependecies.json`
|
data/elm_install.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_dependency 'commander', '~> 4.4', '>= 4.4.2'
|
25
25
|
s.add_dependency 'smart_colored', '~> 1.1', '>= 1.1.1'
|
26
26
|
s.add_dependency 'hashdiff', '~> 0.3.1'
|
27
|
+
s.add_dependency 'indentation', '~> 0.1.1'
|
27
28
|
|
28
29
|
s.extra_rdoc_files = ['Readme.md']
|
29
30
|
end
|
data/lib/elm_install.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
module ElmInstall
|
2
|
+
# This class is the base for the Cache and GitResolver packages.
|
3
|
+
class Base
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
attr_reader :cache
|
7
|
+
|
8
|
+
def_delegators :@cache, :each, :key?
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
@cache = {}
|
13
|
+
load
|
14
|
+
end
|
15
|
+
|
16
|
+
# Saves the cache into the json file.
|
17
|
+
def save
|
18
|
+
File.binwrite(file, JSON.pretty_generate(@cache))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Loads a cache from the json file.
|
22
|
+
def load
|
23
|
+
@cache = JSON.parse(File.read(file))
|
24
|
+
rescue
|
25
|
+
@cache = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def file
|
29
|
+
File.join(directory, @file)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the directory where the cache is stored.
|
33
|
+
def directory
|
34
|
+
@options[:directory]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/elm_install/cache.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative './
|
1
|
+
require_relative './base'
|
2
2
|
|
3
3
|
module ElmInstall
|
4
4
|
# This class is responsible for maintaining a cache
|
@@ -7,46 +7,10 @@ module ElmInstall
|
|
7
7
|
# By default the clones of the repositories live in the users
|
8
8
|
# home directory (~/.elm-install), this can be changed with
|
9
9
|
# the `directory` option.
|
10
|
-
class Cache
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# Initializes a new cache with the given options.
|
16
|
-
def initialize(options = {})
|
17
|
-
@options = options
|
18
|
-
@ref_cache = {}
|
19
|
-
@cache = {}
|
20
|
-
load
|
21
|
-
end
|
22
|
-
|
23
|
-
# Saves the cache into the json file.
|
24
|
-
def save
|
25
|
-
File.binwrite(ref_file, JSON.pretty_generate(@ref_cache))
|
26
|
-
File.binwrite(file, JSON.pretty_generate(@cache))
|
27
|
-
end
|
28
|
-
|
29
|
-
# Loads a cache from the json file.
|
30
|
-
def load
|
31
|
-
@ref_cache = JSON.parse(File.read(ref_file))
|
32
|
-
@cache = JSON.parse(File.read(file))
|
33
|
-
rescue
|
34
|
-
@ref_cache = {}
|
35
|
-
@cache = {}
|
36
|
-
end
|
37
|
-
|
38
|
-
def clear
|
39
|
-
@ref_cache = {}
|
40
|
-
end
|
41
|
-
|
42
|
-
# Returns the directory where the cache is stored.
|
43
|
-
def directory
|
44
|
-
@options[:directory] || File.join(Dir.home, '.elm-install')
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns if there is a package in the cache (with at least one version).
|
48
|
-
def package?(package)
|
49
|
-
@ref_cache.key?(package) && @cache.key?(package)
|
10
|
+
class Cache < Base
|
11
|
+
def initialize(options)
|
12
|
+
@file = 'cache.json'
|
13
|
+
super options
|
50
14
|
end
|
51
15
|
|
52
16
|
# Adds a new dependency to the cache for a given package & version
|
@@ -66,54 +30,5 @@ module ElmInstall
|
|
66
30
|
def ensure_package(package)
|
67
31
|
@cache[package] ||= {}
|
68
32
|
end
|
69
|
-
|
70
|
-
# Returns the path to the repository of the given package.
|
71
|
-
def repository_path(package)
|
72
|
-
File.join(directory, package)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Returns the Git repository of the given package in a ready to use state.
|
76
|
-
def repository(path)
|
77
|
-
repo_path = repository_path(path)
|
78
|
-
|
79
|
-
if Dir.exist?(repo_path)
|
80
|
-
repo = Git.open(repo_path)
|
81
|
-
repo.reset_hard
|
82
|
-
|
83
|
-
unless @ref_cache[path]
|
84
|
-
refs = refs_for(repo_path)
|
85
|
-
|
86
|
-
if HashDiff.diff(@ref_cache[path], refs).empty?
|
87
|
-
Utils.log_with_arrow "Package: #{path.bold} is outdated fetching changes..."
|
88
|
-
repo.fetch
|
89
|
-
end
|
90
|
-
|
91
|
-
@ref_cache[path] = refs
|
92
|
-
end
|
93
|
-
|
94
|
-
repo
|
95
|
-
else
|
96
|
-
Utils.log_with_arrow "Package: #{path.bold} not found in cache, cloning..."
|
97
|
-
repo = Git.clone(path, repo_path)
|
98
|
-
@ref_cache[path] = refs_for(repo_path)
|
99
|
-
repo
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def refs_for(repo_path)
|
106
|
-
refs = Git.ls_remote(repo_path)
|
107
|
-
refs.delete('head')
|
108
|
-
end
|
109
|
-
|
110
|
-
def ref_file
|
111
|
-
File.join(directory, 'ref-cache.json')
|
112
|
-
end
|
113
|
-
|
114
|
-
# Returns the path to the json file.
|
115
|
-
def file
|
116
|
-
File.join(directory, 'cache.json')
|
117
|
-
end
|
118
33
|
end
|
119
34
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ElmInstall
|
2
|
+
# This is a class for reading the `elm-package`.json file and
|
3
|
+
# transform it's `dependecies` field to a unified format.
|
4
|
+
module ElmPackage
|
5
|
+
# TODO: Error handling
|
6
|
+
def self.dependencies(path)
|
7
|
+
json = read path
|
8
|
+
transform_dependencies(
|
9
|
+
json['dependencies'],
|
10
|
+
json['dependency-sources'].to_h
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.read(path)
|
15
|
+
JSON.parse(File.read(path))
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.transform_dependencies(raw_dependencies, sources)
|
19
|
+
raw_dependencies.each_with_object({}) do |(package, constraint), memo|
|
20
|
+
value = sources.fetch(package, package)
|
21
|
+
|
22
|
+
if value.is_a?(Hash)
|
23
|
+
memo[value['url']] = value['ref']
|
24
|
+
else
|
25
|
+
memo[transform_package(value)] = constraint
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.transform_package(key)
|
31
|
+
GitCloneUrl.parse(key).to_s
|
32
|
+
rescue
|
33
|
+
"git@github.com:#{key}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative './logger'
|
2
|
+
|
3
|
+
module ElmInstall
|
4
|
+
# This class if for cloning and fetching repositories based
|
5
|
+
# on a cache.
|
6
|
+
class GitResolver < Base
|
7
|
+
def initialize(options)
|
8
|
+
@file = 'ref-cache.json'
|
9
|
+
super options
|
10
|
+
@check_cache =
|
11
|
+
@cache.keys.each_with_object({}) { |key, memo| memo[key] = true }
|
12
|
+
end
|
13
|
+
|
14
|
+
def refs(url)
|
15
|
+
self.class.refs(url)
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear
|
19
|
+
@check_cache = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.refs(url)
|
23
|
+
refs = Git.ls_remote url
|
24
|
+
refs.delete 'head'
|
25
|
+
JSON.parse(refs.to_json)
|
26
|
+
end
|
27
|
+
|
28
|
+
def package?(url)
|
29
|
+
@check_cache.key?(repository_path(url))
|
30
|
+
end
|
31
|
+
|
32
|
+
# :reek:FeatureEnvy
|
33
|
+
def repository_path(url)
|
34
|
+
uri = GitCloneUrl.parse(url)
|
35
|
+
File.join(directory, uri.host, uri.path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def repository(url)
|
39
|
+
open(url) do |repo|
|
40
|
+
update_cache repo
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_cache(repo)
|
45
|
+
directory = File.dirname(repo.repo.path)
|
46
|
+
url = repo.remote.url
|
47
|
+
refs = refs(url)
|
48
|
+
|
49
|
+
unless HashDiff.diff(cache[directory], refs).empty?
|
50
|
+
Logger.arrow "Package: #{url.bold} is outdated, fetching changes..."
|
51
|
+
repo.fetch
|
52
|
+
end
|
53
|
+
|
54
|
+
@check_cache[directory] = true
|
55
|
+
cache[directory] = refs
|
56
|
+
end
|
57
|
+
|
58
|
+
def open(url)
|
59
|
+
path = repository_path(url)
|
60
|
+
|
61
|
+
return clone url, path unless Dir.exist?(path)
|
62
|
+
|
63
|
+
repo = Git.open path
|
64
|
+
repo.reset_hard
|
65
|
+
|
66
|
+
yield repo unless @check_cache[path]
|
67
|
+
|
68
|
+
repo
|
69
|
+
end
|
70
|
+
|
71
|
+
def clone(url, path)
|
72
|
+
Logger.arrow "Package: #{url.bold} not found in cache, cloning..."
|
73
|
+
FileUtils.mkdir_p path
|
74
|
+
repo = Git.clone(url, path)
|
75
|
+
@check_cache[path] = true
|
76
|
+
cache[path] = refs url
|
77
|
+
repo
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -1,4 +1,8 @@
|
|
1
1
|
require_relative './resolver'
|
2
|
+
require_relative './elm_package'
|
3
|
+
require_relative './git_resolver'
|
4
|
+
require_relative './graph_builder'
|
5
|
+
require_relative './populator'
|
2
6
|
|
3
7
|
module ElmInstall
|
4
8
|
# This class is responsible getting a solution for the `elm-package.json`
|
@@ -8,9 +12,21 @@ module ElmInstall
|
|
8
12
|
extend Forwardable
|
9
13
|
|
10
14
|
# Initializes a new installer with the given options.
|
11
|
-
def initialize(options
|
15
|
+
def initialize(options)
|
16
|
+
init_options options
|
17
|
+
@git_resolver = GitResolver.new directory: cache_directory
|
18
|
+
@cache = Cache.new directory: cache_directory
|
19
|
+
@populator = Populator.new @git_resolver
|
12
20
|
@options = options
|
13
|
-
|
21
|
+
end
|
22
|
+
|
23
|
+
def init_options(options = { verbose: false })
|
24
|
+
options[:cache_directory] ||= File.join(Dir.home, '.elm-install')
|
25
|
+
@options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
def cache_directory
|
29
|
+
@options[:cache_directory]
|
14
30
|
end
|
15
31
|
|
16
32
|
# Executes the installation
|
@@ -21,107 +37,56 @@ module ElmInstall
|
|
21
37
|
resolver.add_constraints dependencies
|
22
38
|
|
23
39
|
puts 'Solving dependencies...'
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
puts ' ▶ Could not find a solution in local cache, refreshing packages...'
|
28
|
-
|
29
|
-
@cache.clear
|
30
|
-
resolver.add_constraints dependencies
|
31
|
-
|
32
|
-
begin
|
33
|
-
populate_elm_stuff
|
34
|
-
rescue Solve::Errors::NoSolutionError => e
|
35
|
-
puts 'Could not find a solution:'
|
36
|
-
puts indent(e.to_s)
|
37
|
-
end
|
38
|
-
end
|
40
|
+
populate_elm_stuff
|
41
|
+
rescue
|
42
|
+
retry_install
|
39
43
|
end
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
def indent(str)
|
44
|
-
str.split("\n").map { |s| " #{s}" }.join("\n")
|
45
|
-
end
|
46
|
-
|
47
|
-
def end_sucessfully
|
45
|
+
def save
|
48
46
|
puts 'Saving package cache...'
|
47
|
+
@git_resolver.save
|
49
48
|
@cache.save
|
50
|
-
|
51
|
-
puts 'Packages configured successfully!'
|
52
|
-
end
|
53
|
-
# Populates the `elm-stuff` directory with the packages from
|
54
|
-
# the solution.
|
55
|
-
def populate_elm_stuff
|
56
|
-
solution.each do |package, version|
|
57
|
-
resolve_package package, version
|
58
|
-
end
|
59
|
-
|
60
|
-
write_exact_dependencies
|
61
|
-
end_sucessfully
|
62
49
|
end
|
63
50
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
def resolve_package(package, version)
|
69
|
-
package_name, package_path = Utils.package_version_path package, version
|
70
|
-
|
71
|
-
matches = dependencies[package_name].to_s.match(/^(ref|branch):(.*)/)
|
72
|
-
|
73
|
-
ref = (matches && matches[2]) || version
|
74
|
-
@cache.repository(package).checkout(ref)
|
75
|
-
|
76
|
-
version_str = ref == version ? ref : "#{ref}(#{version})"
|
77
|
-
Utils.log_with_dot "#{package_name.bold} - #{version_str.bold}"
|
51
|
+
def retry_install
|
52
|
+
Logger.arrow(
|
53
|
+
'Could not find a solution in local cache, refreshing packages...'
|
54
|
+
)
|
78
55
|
|
79
|
-
|
56
|
+
@git_resolver.clear
|
57
|
+
resolver.add_constraints dependencies
|
80
58
|
|
81
|
-
|
59
|
+
populate_elm_stuff
|
60
|
+
rescue Solve::Errors::NoSolutionError => error
|
61
|
+
puts 'Could not find a solution:'
|
62
|
+
puts error.to_s.indent(2)
|
82
63
|
end
|
83
64
|
|
84
|
-
|
85
|
-
def copy_package(package, package_path)
|
86
|
-
FileUtils.mkdir_p(package_path)
|
87
|
-
FileUtils.cp_r(
|
88
|
-
File.join(@cache.repository_path(package), '.'), package_path
|
89
|
-
)
|
90
|
-
FileUtils.rm_rf(File.join(package_path, '.git'))
|
91
|
-
end
|
92
|
-
|
93
|
-
# Writes the `elm-stuff/exact-dependencies.json` file.
|
94
|
-
def write_exact_dependencies
|
95
|
-
path = File.join('elm-stuff', 'exact-dependencies.json')
|
96
|
-
File.binwrite(path, JSON.pretty_generate(exact_dependencies))
|
97
|
-
end
|
65
|
+
private
|
98
66
|
|
99
|
-
#
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
67
|
+
# Populates the `elm-stuff` directory with the packages from
|
68
|
+
# the solution.
|
69
|
+
def populate_elm_stuff
|
70
|
+
save
|
71
|
+
@populator.populate calculate_solution
|
72
|
+
puts 'Packages configured successfully!'
|
105
73
|
end
|
106
74
|
|
107
75
|
# Returns the resolver to calculate the solution.
|
108
76
|
def resolver
|
109
|
-
@resolver ||= Resolver.new @cache
|
77
|
+
@resolver ||= Resolver.new @cache, @git_resolver
|
110
78
|
end
|
111
79
|
|
112
80
|
# Returns the solution for the given `elm-package.json` file.
|
113
|
-
def
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
)
|
81
|
+
def calculate_solution
|
82
|
+
Solve.it!(
|
83
|
+
GraphBuilder.graph_from_cache(@cache, @options),
|
84
|
+
resolver.constraints
|
85
|
+
)
|
119
86
|
end
|
120
87
|
|
121
|
-
# Returns the dependencies from the `elm-package.json` file.
|
122
88
|
def dependencies
|
123
|
-
@dependencies ||=
|
124
|
-
JSON.parse(File.read('elm-package.json'))['dependencies']
|
89
|
+
@dependencies ||= ElmPackage.dependencies 'elm-package.json'
|
125
90
|
end
|
126
91
|
end
|
127
92
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ElmInstall
|
2
|
+
# This class is responsible for populating the `elm-stuff` directory.
|
3
|
+
class Populator
|
4
|
+
def initialize(git_resolver)
|
5
|
+
@git_resolver = git_resolver
|
6
|
+
end
|
7
|
+
|
8
|
+
def populate(solution)
|
9
|
+
solution.each do |package, version|
|
10
|
+
resolve_package package, version
|
11
|
+
end
|
12
|
+
|
13
|
+
write_exact_dependencies(solution)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Resolves and copies a package and it's version to `elm-stuff/packages`
|
17
|
+
# directory.
|
18
|
+
#
|
19
|
+
# :reek:TooManyStatements { max_statements: 9 }
|
20
|
+
def resolve_package(package, version_str)
|
21
|
+
match = version_str.match /(.+)\+(.+)/
|
22
|
+
|
23
|
+
version =
|
24
|
+
if match
|
25
|
+
match[1]
|
26
|
+
else
|
27
|
+
version_str
|
28
|
+
end
|
29
|
+
|
30
|
+
ref =
|
31
|
+
if match
|
32
|
+
match[2]
|
33
|
+
else
|
34
|
+
version_str
|
35
|
+
end
|
36
|
+
|
37
|
+
package_name, package_path = Utils.package_version_path package, version
|
38
|
+
|
39
|
+
@git_resolver.repository(package).checkout(ref)
|
40
|
+
|
41
|
+
Logger.dot "#{package_name.bold} - #{version.bold} (#{ref})"
|
42
|
+
|
43
|
+
FileUtils.rm_rf(package_path) if Dir.exist?(package_path)
|
44
|
+
|
45
|
+
copy_package package, package_path
|
46
|
+
end
|
47
|
+
|
48
|
+
# Copies the given package from it's repository to the given path.
|
49
|
+
def copy_package(package, package_path)
|
50
|
+
repository_path = File.join(@git_resolver.repository_path(package), '.')
|
51
|
+
|
52
|
+
FileUtils.mkdir_p(package_path)
|
53
|
+
FileUtils.cp_r(repository_path, package_path)
|
54
|
+
FileUtils.rm_rf(File.join(package_path, '.git'))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Writes the `elm-stuff/exact-dependencies.json` file.
|
58
|
+
def write_exact_dependencies(solution)
|
59
|
+
File.binwrite(
|
60
|
+
File.join('elm-stuff', 'exact-dependencies.json'),
|
61
|
+
JSON.pretty_generate(self.class.exact_dependencies(solution))
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the exact dependencies from the solution.
|
66
|
+
def self.exact_dependencies(solution)
|
67
|
+
solution.each_with_object({}) do |(key, value), memo|
|
68
|
+
match = value.match /(.+)\+(.+)/
|
69
|
+
|
70
|
+
version =
|
71
|
+
if match
|
72
|
+
match[1]
|
73
|
+
else
|
74
|
+
value
|
75
|
+
end
|
76
|
+
|
77
|
+
memo[GitCloneUrl.parse(key).path.sub(%r{^/}, '')] = version
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/elm_install/resolver.rb
CHANGED
@@ -7,12 +7,13 @@ module ElmInstall
|
|
7
7
|
attr_reader :constraints
|
8
8
|
|
9
9
|
# Initializes a resolver for a chace.
|
10
|
-
def initialize(cache)
|
10
|
+
def initialize(cache, git_resolver)
|
11
|
+
@git_resolver = git_resolver
|
11
12
|
@constraints = []
|
12
13
|
@cache = cache
|
13
14
|
end
|
14
15
|
|
15
|
-
# Add
|
16
|
+
# Add constraints, usually from the `elm-package.json`.
|
16
17
|
def add_constraints(constraints)
|
17
18
|
@constraints = add_dependencies(constraints) do |package, constraint|
|
18
19
|
[package, constraint]
|
@@ -24,26 +25,29 @@ module ElmInstall
|
|
24
25
|
# :reek:NestedIterators { max_allowed_nesting: 2 }
|
25
26
|
# :reek:TooManyStatements { max_statements: 6 }
|
26
27
|
def add_dependencies(dependencies)
|
27
|
-
dependencies.flat_map do |
|
28
|
-
package = Utils.transform_package(package_slug)
|
29
|
-
|
28
|
+
dependencies.flat_map do |package, constraint|
|
30
29
|
add_package(package)
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
end
|
31
|
+
constraints = Utils.transform_constraint(constraint)
|
32
|
+
next add_ref_dependency(package, constraint) if constraints.empty?
|
35
33
|
|
36
|
-
|
34
|
+
constraints.map do |dependency|
|
37
35
|
yield package, dependency
|
38
36
|
end
|
39
37
|
end
|
40
38
|
end
|
41
39
|
|
42
40
|
# Adds a dependency by git reference.
|
43
|
-
def add_ref_dependency(package,
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
def add_ref_dependency(package, ref)
|
42
|
+
@git_resolver.repository(package).checkout(ref)
|
43
|
+
pkg_version = elm_package(package)['version']
|
44
|
+
version = "#{pkg_version}+#{ref}"
|
45
|
+
@cache.ensure_version(package, version)
|
46
|
+
add_dependencies(elm_dependencies(package)) do |dep_package, constraint|
|
47
|
+
add_package(dep_package)
|
48
|
+
@cache.dependency(package, version, [dep_package, constraint])
|
49
|
+
end
|
50
|
+
[[package, "= #{version}"]]
|
47
51
|
end
|
48
52
|
|
49
53
|
# Adds a package to the cache, the following things happens:
|
@@ -52,9 +56,9 @@ module ElmInstall
|
|
52
56
|
# * Checking out and getting the `elm-package.json` for each version
|
53
57
|
# and adding them recursivly
|
54
58
|
def add_package(package)
|
55
|
-
return if @
|
59
|
+
return if @git_resolver.package?(package) && @cache.key?(package)
|
56
60
|
|
57
|
-
@
|
61
|
+
@git_resolver
|
58
62
|
.repository(package)
|
59
63
|
.tags
|
60
64
|
.map(&:name)
|
@@ -66,7 +70,7 @@ module ElmInstall
|
|
66
70
|
|
67
71
|
# Adds a version and it's dependencies to the cache.
|
68
72
|
def add_version(package, version)
|
69
|
-
@
|
73
|
+
@git_resolver
|
70
74
|
.repository(package)
|
71
75
|
.checkout(version)
|
72
76
|
|
@@ -78,14 +82,17 @@ module ElmInstall
|
|
78
82
|
|
79
83
|
# Gets the `elm-package.json` for a package.
|
80
84
|
def elm_dependencies(package)
|
81
|
-
|
85
|
+
ElmPackage.dependencies elm_package_path(package)
|
82
86
|
rescue
|
83
87
|
[]
|
84
88
|
end
|
85
89
|
|
86
90
|
def elm_package(package)
|
87
|
-
|
88
|
-
|
91
|
+
ElmPackage.read elm_package_path(package)
|
92
|
+
end
|
93
|
+
|
94
|
+
def elm_package_path(package)
|
95
|
+
File.join(@git_resolver.repository_path(package), 'elm-package.json')
|
89
96
|
end
|
90
97
|
end
|
91
98
|
end
|
data/lib/elm_install/utils.rb
CHANGED
@@ -19,24 +19,9 @@ module ElmInstall
|
|
19
19
|
end.compact
|
20
20
|
end
|
21
21
|
|
22
|
-
def log_with_dot(message)
|
23
|
-
puts ' ● '.green + message
|
24
|
-
end
|
25
|
-
|
26
|
-
def log_with_arrow(message)
|
27
|
-
puts " ▶ #{message}"
|
28
|
-
end
|
29
|
-
|
30
22
|
def package_version_path(package, version)
|
31
|
-
package_name = GitCloneUrl.parse(package).path
|
23
|
+
package_name = GitCloneUrl.parse(package).path.sub(%r{^/}, '')
|
32
24
|
[package_name, File.join('elm-stuff', 'packages', package_name, version)]
|
33
25
|
end
|
34
|
-
|
35
|
-
def transform_package(key)
|
36
|
-
GitCloneUrl.parse(key)
|
37
|
-
key
|
38
|
-
rescue
|
39
|
-
"git@github.com:#{key}"
|
40
|
-
end
|
41
26
|
end
|
42
27
|
end
|
data/lib/elm_install/version.rb
CHANGED
data/packaging/Gemfile.lock
CHANGED
@@ -1,21 +1,23 @@
|
|
1
1
|
GEM
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
-
colorize (0.8.1)
|
5
4
|
commander (4.4.2)
|
6
5
|
highline (~> 1.7.2)
|
7
|
-
elm_install (0.1.
|
8
|
-
colorize (~> 0.8.1)
|
6
|
+
elm_install (0.1.1)
|
9
7
|
commander (~> 4.4, >= 4.4.2)
|
10
8
|
git (~> 1.3)
|
11
9
|
git_clone_url (~> 2.0)
|
10
|
+
hashdiff (~> 0.3.1)
|
11
|
+
smart_colored (~> 1.1, >= 1.1.1)
|
12
12
|
solve (~> 3.1)
|
13
13
|
git (1.3.0)
|
14
14
|
git_clone_url (2.0.0)
|
15
15
|
uri-ssh_git (>= 2.0)
|
16
|
+
hashdiff (0.3.1)
|
16
17
|
highline (1.7.8)
|
17
18
|
molinillo (0.5.4)
|
18
19
|
semverse (2.0.0)
|
20
|
+
smart_colored (1.1.1)
|
19
21
|
solve (3.1.0)
|
20
22
|
molinillo (>= 0.5)
|
21
23
|
semverse (>= 1.1, < 3.0)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElmInstall::ElmPackage do
|
4
|
+
subject { described_class }
|
5
|
+
|
6
|
+
let(:path) { 'spec/fixtures/elm-package.json' }
|
7
|
+
|
8
|
+
describe '.transform_dependencies' do
|
9
|
+
subject { described_class.dependencies(path) }
|
10
|
+
|
11
|
+
it 'should return transformed dependencies' do
|
12
|
+
expect(subject)
|
13
|
+
.to eq(
|
14
|
+
'git@some-domain.com:test/repo' => 'development',
|
15
|
+
'git@github.com:base/core' => '2.0.0 <= v < 3.0.0'
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.transform_package' do
|
21
|
+
it 'should transform normal packages names to github ones' do
|
22
|
+
expect(subject.transform_package('test/repo'))
|
23
|
+
.to eq 'git@github.com:test/repo'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should return valid git urls' do
|
27
|
+
expect(subject.transform_package('git@github.com:test/repo'))
|
28
|
+
.to eq 'git@github.com:test/repo'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElmInstall::GitResolver do
|
4
|
+
subject { described_class.new directory: CACHE_DIRECTORY }
|
5
|
+
|
6
|
+
let(:uri) { 'git@github.com:test/repo' }
|
7
|
+
|
8
|
+
describe '.repository' do
|
9
|
+
let(:refs) { {} }
|
10
|
+
let(:repo) { Git.init CACHE_DIRECTORY }
|
11
|
+
|
12
|
+
context 'with repository' do
|
13
|
+
let(:directory) { File.join CACHE_DIRECTORY, 'github.com/test/repo' }
|
14
|
+
|
15
|
+
before do
|
16
|
+
FileUtils.mkdir_p directory
|
17
|
+
Git.init directory
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with cache' do
|
21
|
+
before do
|
22
|
+
subject.instance_variable_get('@check_cache')[directory] = {}
|
23
|
+
subject.cache[directory] = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should return repository' do
|
27
|
+
repo = subject.repository uri
|
28
|
+
expect(File.dirname(repo.repo.path))
|
29
|
+
.to eq File.join(Dir.pwd, directory)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'without cache' do
|
34
|
+
before do
|
35
|
+
expect_any_instance_of(Git::Base)
|
36
|
+
.to receive(:fetch)
|
37
|
+
|
38
|
+
expect_any_instance_of(Git::Remote)
|
39
|
+
.to receive(:url)
|
40
|
+
.and_return uri.to_s
|
41
|
+
|
42
|
+
expect(Git)
|
43
|
+
.to receive(:ls_remote)
|
44
|
+
.and_return(refs)
|
45
|
+
|
46
|
+
expect(ElmInstall::Logger)
|
47
|
+
.to receive(:arrow)
|
48
|
+
.with "Package: #{'git@github.com:test/repo'.bold} is outdated, \
|
49
|
+
fetching changes...".gsub(/\s+/, ' ')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should fetch refs and update cache' do
|
53
|
+
subject.repository uri
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'without repository' do
|
59
|
+
before do
|
60
|
+
expect(Git)
|
61
|
+
.to receive(:clone)
|
62
|
+
.and_return(repo)
|
63
|
+
|
64
|
+
expect(Git)
|
65
|
+
.to receive(:ls_remote)
|
66
|
+
.and_return(refs)
|
67
|
+
|
68
|
+
expect(ElmInstall::Logger)
|
69
|
+
.to receive(:arrow)
|
70
|
+
.with "Package: #{'git@github.com:test/repo'.bold} not found in \
|
71
|
+
cache, cloning...".gsub(/\s+/, ' ')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should clone a new repository' do
|
75
|
+
expect { subject.repository uri }
|
76
|
+
.to change { subject.cache.keys.count }
|
77
|
+
.from(0)
|
78
|
+
.to(1)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElmInstall::Resolver do
|
4
|
+
subject { described_class.new cache, git_resolver }
|
5
|
+
|
6
|
+
let(:git_resolver) { ElmInstall::GitResolver.new directory: CACHE_DIRECTORY }
|
7
|
+
let(:cache) { ElmInstall::Cache.new directory: CACHE_DIRECTORY }
|
8
|
+
|
9
|
+
let(:directory) { File.join CACHE_DIRECTORY, 'github.com/test/repo' }
|
10
|
+
let(:core_directory) { File.join CACHE_DIRECTORY, 'github.com/base/core' }
|
11
|
+
|
12
|
+
let(:package_json) do
|
13
|
+
{ dependencies: { 'base/core' => '1.0.0 <= v < 2.0.0' } }.to_json
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
FileUtils.mkdir_p directory
|
18
|
+
File.binwrite File.join(directory, 'elm-package.json'), package_json
|
19
|
+
Git.init directory
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:url) { 'git@github.com:test/repo' }
|
23
|
+
|
24
|
+
let(:core_repo) do
|
25
|
+
repo = Git.init core_directory
|
26
|
+
File.binwrite File.join(core_directory, 'elm-package.json'), '{}'
|
27
|
+
repo
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should resolve packages' do
|
31
|
+
expect(Git)
|
32
|
+
.to receive(:clone) { core_repo }
|
33
|
+
|
34
|
+
expect(Git)
|
35
|
+
.to receive(:ls_remote)
|
36
|
+
.and_return(tags: { name: '1.0.0' })
|
37
|
+
|
38
|
+
expect(ElmInstall::Logger)
|
39
|
+
.to receive(:arrow)
|
40
|
+
.with "Package: #{'git@github.com:base/core'.bold} not found in \
|
41
|
+
cache, cloning...".gsub(/\s+/, ' ')
|
42
|
+
|
43
|
+
allow_any_instance_of(Git::Remote)
|
44
|
+
.to receive(:url)
|
45
|
+
.and_return url
|
46
|
+
|
47
|
+
allow_any_instance_of(Git::Base)
|
48
|
+
.to receive(:tags)
|
49
|
+
.and_return [double(name: '1.0.0')]
|
50
|
+
|
51
|
+
allow_any_instance_of(Git::Base)
|
52
|
+
.to receive(:checkout)
|
53
|
+
|
54
|
+
subject
|
55
|
+
.instance_variable_get('@git_resolver')
|
56
|
+
.instance_variable_get('@check_cache')[directory] = {}
|
57
|
+
|
58
|
+
subject.instance_variable_get('@git_resolver').cache[directory] = {}
|
59
|
+
|
60
|
+
subject.add_constraints(
|
61
|
+
url => 'development',
|
62
|
+
'git@github.com:base/core' => '1.0.0 <= v < 2.0.0'
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
CACHE_DIRECTORY = 'spec/fixtures/cache'.freeze
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.before do
|
7
|
+
FileUtils.mkdir CACHE_DIRECTORY
|
8
|
+
end
|
9
|
+
|
10
|
+
config.after do
|
11
|
+
FileUtils.rm_rf CACHE_DIRECTORY
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
SimpleCov.start do
|
16
|
+
add_filter '/spec/'
|
17
|
+
end
|
18
|
+
|
19
|
+
require_relative '../lib/elm_install'
|
data/spec/utils_spec.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElmInstall::Utils do
|
4
|
+
subject { described_class }
|
5
|
+
|
6
|
+
let(:package_variations) do
|
7
|
+
[
|
8
|
+
'git@github.com:test/repo',
|
9
|
+
'https://github.com/test/repo',
|
10
|
+
'git://github.com/test/repo'
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.package_version_path' do
|
15
|
+
it 'should return the path for a package in elm-stuff' do
|
16
|
+
package_variations.each do |package|
|
17
|
+
expect(subject.package_version_path(package, '1.0.0'))
|
18
|
+
.to eq(['test/repo', 'elm-stuff/packages/test/repo/1.0.0'])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.transform_constraint' do
|
24
|
+
it 'should convert basic constraint' do
|
25
|
+
expect(subject.transform_constraint('0.1.0 <= v < 1.0.0'))
|
26
|
+
.to eq(['< 1.0.0', '>= 0.1.0'])
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should convert advanced constraint' do
|
30
|
+
expect(subject.transform_constraint('0.1.0 < v <= 1.0.0'))
|
31
|
+
.to eq(['<= 1.0.0', '> 0.1.0'])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elm_install
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gusztáv Szikszai
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: git
|
@@ -106,6 +106,20 @@ dependencies:
|
|
106
106
|
- - "~>"
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: 0.3.1
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: indentation
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 0.1.1
|
116
|
+
type: :runtime
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 0.1.1
|
109
123
|
description:
|
110
124
|
email: gusztav.szikszai@digitalnatives.hu
|
111
125
|
executables:
|
@@ -115,6 +129,8 @@ extra_rdoc_files:
|
|
115
129
|
- Readme.md
|
116
130
|
files:
|
117
131
|
- ".gitignore"
|
132
|
+
- ".reek"
|
133
|
+
- ".rspec"
|
118
134
|
- ".rubocop.yml"
|
119
135
|
- ".ruby-gemset"
|
120
136
|
- ".ruby-version"
|
@@ -123,11 +139,17 @@ files:
|
|
123
139
|
- Rakefile
|
124
140
|
- Readme.md
|
125
141
|
- bin/elm-install
|
142
|
+
- docs/How it works.md
|
126
143
|
- elm_install.gemspec
|
127
144
|
- lib/elm_install.rb
|
145
|
+
- lib/elm_install/base.rb
|
128
146
|
- lib/elm_install/cache.rb
|
147
|
+
- lib/elm_install/elm_package.rb
|
148
|
+
- lib/elm_install/git_resolver.rb
|
129
149
|
- lib/elm_install/graph_builder.rb
|
130
150
|
- lib/elm_install/installer.rb
|
151
|
+
- lib/elm_install/logger.rb
|
152
|
+
- lib/elm_install/populator.rb
|
131
153
|
- lib/elm_install/resolver.rb
|
132
154
|
- lib/elm_install/utils.rb
|
133
155
|
- lib/elm_install/version.rb
|
@@ -137,6 +159,11 @@ files:
|
|
137
159
|
- packaging/Rakefile
|
138
160
|
- packaging/bundler-config
|
139
161
|
- packaging/wrapper.sh
|
162
|
+
- spec/elm_package_spec.rb
|
163
|
+
- spec/git_resolver_spec.rb
|
164
|
+
- spec/resolver_spec.rb
|
165
|
+
- spec/spec_helper.rb
|
166
|
+
- spec/utils_spec.rb
|
140
167
|
homepage: https://github.com/gdotdesign/elm-github-install
|
141
168
|
licenses: []
|
142
169
|
metadata: {}
|