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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3a03f6fdb1a42bea5c14a87c7faa22623c146fbd
4
- data.tar.gz: b484dc5f2566e0155da8a959a2ae1bf761f1ae10
3
+ metadata.gz: 866f31dd5848df9cc5fdce2188f1de72c04d8863
4
+ data.tar.gz: 5e78e0422f41adbcc320908a4d704429c4f030ff
5
5
  SHA512:
6
- metadata.gz: d783886b984c689ea08f652fae2e909c6a441820c2fa22f0defa657643b736347c5ad5f9d93e6ead8ef8eeed46a39f4864dae03f11d55547c072c9dc19c50b14
7
- data.tar.gz: 9a04dd69660a65a3a802ad1455c54a9c06be9612772f27b695b6b4cc43b90dfebe97467976c7915085afb8280713b4bf39405c1f0ed1b5fc5f80e2a2d65661d6
6
+ metadata.gz: 9807dde1aba8c797b9f9e4db38885ff67f54c132eb022bb2733ec75fcfa09863260332fbd2bcca97a6ec5501d8a718e26350e0a4bb05eb84610f1e7eb0ee755c
7
+ data.tar.gz: 3877767e0e6038f564e01016d378ceae90120c68efc99accf0f3edfe523abd2b32f872fc2768a51872f5277c56e0bfba6d5f6ef0226bf4b1822fe5ad497c400c
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ pkg
6
6
  packaging/vendor
7
7
  packaging/elm-install*
8
8
  packaging/traveling-ruby*
9
+ coverage
data/.reek ADDED
@@ -0,0 +1,4 @@
1
+ TooManyStatements:
2
+ max_statements: 7
3
+ InstanceVariableAssumption:
4
+ enabled: false
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile CHANGED
@@ -4,3 +4,4 @@ gemspec
4
4
  gem 'rspec', '~> 3.5'
5
5
  gem 'rubocop', '~> 0.46.0'
6
6
  gem 'rubycritic', '~> 3.1', '>= 3.1.3'
7
+ gem 'simplecov', '~> 0.12.0'
data/Gemfile.lock CHANGED
@@ -1,11 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- elm_install (0.1.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.6
127
+ 1.13.7
data/Rakefile CHANGED
@@ -3,6 +3,7 @@ require 'bundler/setup'
3
3
  Bundler::GemHelper.install_tasks
4
4
 
5
5
  task :ci do
6
+ sh 'rspec'
6
7
  sh 'rubocop'
7
8
  sh 'rubycritic -m --no-browser -s 90 lib'
8
9
  end
@@ -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
@@ -1,6 +1,7 @@
1
1
  require 'smart_colored/extend'
2
2
  require 'git_clone_url'
3
3
  require 'forwardable'
4
+ require 'indentation'
4
5
  require 'fileutils'
5
6
  require 'hashdiff'
6
7
  require 'solve'
@@ -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
@@ -1,4 +1,4 @@
1
- require_relative './graph_builder'
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
- extend Forwardable
12
-
13
- def_delegators :@cache, :each
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 = { verbose: false })
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
- @cache = Cache.new
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
- begin
25
- populate_elm_stuff
26
- rescue
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
- private
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
- # Resolves and copies a package and it's version to `elm-stuff/packages`
65
- # directory.
66
- #
67
- # :reek:TooManyStatements { max_statements: 9 }
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
- return if Dir.exist?(package_path)
56
+ @git_resolver.clear
57
+ resolver.add_constraints dependencies
80
58
 
81
- copy_package package, package_path
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
- # Copies the given package from it's repository to the given path.
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
- # Returns the exact dependencies from the solution.
100
- def exact_dependencies
101
- @exact_dependencies ||=
102
- solution.each_with_object({}) do |(key, value), memo|
103
- memo[GitCloneUrl.parse(key).path] = value
104
- end
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 solution
114
- @solution ||=
115
- Solve.it!(
116
- GraphBuilder.graph_from_cache(@cache, @options),
117
- resolver.constraints
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,14 @@
1
+ module ElmInstall
2
+ # This is a helper module for logging.
3
+ module Logger
4
+ # :nocov:
5
+ def self.dot(message)
6
+ puts ' ● '.green + message
7
+ end
8
+
9
+ def self.arrow(message)
10
+ puts " ▶ #{message}"
11
+ end
12
+ # :nocov:
13
+ end
14
+ 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
@@ -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 constrains, usually from the `elm-package.json`.
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 |package_slug, constraint|
28
- package = Utils.transform_package(package_slug)
29
-
28
+ dependencies.flat_map do |package, constraint|
30
29
  add_package(package)
31
30
 
32
- if constraint =~ /^(ref|branch):(.*)/
33
- next add_ref_dependency(package, constraint)
34
- end
31
+ constraints = Utils.transform_constraint(constraint)
32
+ next add_ref_dependency(package, constraint) if constraints.empty?
35
33
 
36
- Utils.transform_constraint(constraint).map do |dependency|
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, constraint)
44
- ref = constraint.match(/^(ref|branch):(.*)/)[2]
45
- @cache.repository(package).checkout(ref)
46
- [[package, "= #{elm_package(package)['version']}"]]
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 @cache.package?(package)
59
+ return if @git_resolver.package?(package) && @cache.key?(package)
56
60
 
57
- @cache
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
- @cache
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
- elm_package(package)['dependencies']
85
+ ElmPackage.dependencies elm_package_path(package)
82
86
  rescue
83
87
  []
84
88
  end
85
89
 
86
90
  def elm_package(package)
87
- path = File.join(@cache.repository_path(package), 'elm-package.json')
88
- JSON.parse(File.read(path))
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module ElmInstall
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
@@ -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.0)
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
@@ -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'
@@ -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.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-24 00:00:00.000000000 Z
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: {}