elm_install 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: {}