elm_install 0.3.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.reek +4 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +4 -0
  5. data/Gemfile.lock +30 -25
  6. data/Rakefile +2 -2
  7. data/Readme.md +85 -23
  8. data/bin/elm-install +5 -2
  9. data/elm_install.gemspec +2 -0
  10. data/lib/elm_install.rb +18 -1
  11. data/lib/elm_install/base.rb +3 -46
  12. data/lib/elm_install/dependency.rb +37 -0
  13. data/lib/elm_install/directory_source.rb +66 -0
  14. data/lib/elm_install/ext.rb +23 -0
  15. data/lib/elm_install/git_source.rb +173 -0
  16. data/lib/elm_install/identifier.rb +133 -0
  17. data/lib/elm_install/installer.rb +38 -96
  18. data/lib/elm_install/populator.rb +54 -75
  19. data/lib/elm_install/repository.rb +82 -0
  20. data/lib/elm_install/resolver.rb +48 -118
  21. data/lib/elm_install/source.rb +18 -0
  22. data/lib/elm_install/types.rb +43 -0
  23. data/lib/elm_install/utils.rb +14 -20
  24. data/lib/elm_install/version.rb +1 -1
  25. data/package.json +1 -1
  26. data/packaging/Gemfile +1 -1
  27. data/packaging/Gemfile.lock +8 -4
  28. data/scripts/install.js +4 -4
  29. data/scripts/run.js +4 -4
  30. data/spec/directory_source_spec.rb +37 -0
  31. data/spec/{eml_install_spec.rb → elm_install_spec.rb} +6 -3
  32. data/spec/git_source_spec.rb +115 -0
  33. data/spec/identifer_spec.rb +53 -0
  34. data/spec/installer_spec.rb +57 -26
  35. data/spec/repository_spec.rb +44 -0
  36. data/spec/resolver_spec.rb +0 -73
  37. data/spec/spec_helper.rb +3 -1
  38. data/spec/utils_spec.rb +10 -15
  39. metadata +43 -17
  40. data/docs/How it works.md +0 -54
  41. data/lib/elm_install/cache.rb +0 -52
  42. data/lib/elm_install/elm_package.rb +0 -119
  43. data/lib/elm_install/git_resolver.rb +0 -129
  44. data/lib/elm_install/graph_builder.rb +0 -73
  45. data/spec/elm_package_spec.rb +0 -73
  46. data/spec/fixtures/cache.json +0 -8
  47. data/spec/fixtures/elm-package.json +0 -12
  48. data/spec/fixtures/invalid-elm-package.json +0 -6
  49. data/spec/fixtures/mismatched-elm-package.json +0 -9
  50. data/spec/fixtures/ref-cache.json +0 -4
  51. data/spec/git_resolver_spec.rb +0 -103
  52. data/spec/graph_builder_spec.rb +0 -36
  53. data/spec/populator_spec.rb +0 -44
@@ -1,129 +0,0 @@
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
- # Initializes a git resolver with the given options.
8
- #
9
- # @param options [Hash] The options
10
- def initialize(options)
11
- @file = 'ref-cache.json'
12
- super options
13
- @check_cache =
14
- @cache.keys.each_with_object({}) { |key, memo| memo[key] = true }
15
- end
16
-
17
- # Returns the refs for a given url.
18
- #
19
- # @param url [String] the url
20
- #
21
- # @return [Hash] The refs
22
- def refs(url)
23
- self.class.refs(url)
24
- end
25
-
26
- # Clears the cache
27
- #
28
- # @return [void]
29
- def clear
30
- @check_cache = {}
31
- end
32
-
33
- # Returns the refs for a given url.
34
- #
35
- # @param url [String] the url
36
- #
37
- # @return [Hash] The refs
38
- def self.refs(url)
39
- refs = Git.ls_remote url
40
- refs.delete 'head'
41
- JSON.parse(refs.to_json)
42
- end
43
-
44
- # Returns if the given package (url) is in the cache.
45
- #
46
- # @param url [String] The url
47
- #
48
- # @return [Boolean] True if exists false if not
49
- def package?(url)
50
- @check_cache.key?(repository_path(url))
51
- end
52
-
53
- # Returns the path of the repository for a given url.
54
- #
55
- # :reek:FeatureEnvy
56
- #
57
- # @param url [String] The url
58
- #
59
- # @return [String] The path
60
- def repository_path(url)
61
- uri = GitCloneUrl.parse(url)
62
- File.join(directory, uri.host, uri.path)
63
- end
64
-
65
- # Returns a git repository object for the given url, cloning it
66
- # if it does not exists.
67
- #
68
- # @param url [String] The url
69
- #
70
- # @return [Git::Base] The repository
71
- def repository(url)
72
- open(url) do |repo|
73
- update_cache repo
74
- end
75
- end
76
-
77
- # Updates a repository checking it's refs and fetching changes if needed.
78
- #
79
- # @param repo [Git::Base] The repository
80
- #
81
- # @return [void]
82
- def update_cache(repo)
83
- directory = File.dirname(repo.repo.path)
84
- url = repo.remote.url
85
- refs = refs(url)
86
-
87
- unless HashDiff.diff(cache[directory], refs).empty?
88
- Logger.arrow "Package: #{url.bold} is outdated, fetching changes..."
89
- repo.fetch
90
- end
91
-
92
- @check_cache[directory] = true
93
- cache[directory] = refs
94
- end
95
-
96
- # Opens a git repository cloning if it's not exists.
97
- #
98
- # @param url [String] The url
99
- #
100
- # @return [Git::Base] The repository
101
- def open(url)
102
- path = repository_path(url)
103
-
104
- return clone url, path unless Dir.exist?(path)
105
-
106
- repo = Git.open path
107
- repo.reset_hard
108
-
109
- yield repo unless @check_cache[path]
110
-
111
- repo
112
- end
113
-
114
- # Clones the repostiry from the given url to the given path.
115
- #
116
- # @param url [String] The url
117
- # @param path [String] The path
118
- #
119
- # @return [Git::Base] The repository
120
- def clone(url, path)
121
- Logger.arrow "Package: #{url.bold} not found in cache, cloning..."
122
- FileUtils.mkdir_p path
123
- repo = Git.clone(url, path)
124
- @check_cache[path] = true
125
- cache[path] = refs url
126
- repo
127
- end
128
- end
129
- end
@@ -1,73 +0,0 @@
1
- module ElmInstall
2
- # This class is for building dependency graphs from a cache.
3
- class GraphBuilder
4
- # @return [Solve::Graph] The graph
5
- attr_reader :graph
6
-
7
- # Returns a graph from a cache and options.
8
- #
9
- # @param cache [Cache] The cache to generate the graph from.
10
- # @param options [Hash] The options to use.
11
- #
12
- # @return [Solve::Graph] The graph
13
- def self.graph_from_cache(cache, options = { verbose: false })
14
- graph = new cache, options
15
- graph.build
16
- graph.graph
17
- end
18
-
19
- # Initialies a graph build with a cache and options.
20
- #
21
- # @param cache [Cache] The cache to generate the graph from.
22
- # @param options [Hash] The options to use.
23
- def initialize(cache, options = { verbose: false })
24
- @graph = Solve::Graph.new
25
- @options = options
26
- @cache = cache
27
- end
28
-
29
- # Builds the graph.
30
- #
31
- # @return [void]
32
- def build
33
- @cache.each do |package, versions|
34
- add_versions package, versions
35
- end
36
- end
37
-
38
- private
39
-
40
- # Adds the given package & version combinations to the graph.
41
- def add_versions(package, versions)
42
- versions.each do |version, dependencies|
43
- add_version package, version, dependencies
44
- end
45
- end
46
-
47
- # Adds the given package, version and dependency
48
- # combinations to the graph.
49
- def add_version(package, version, dependencies)
50
- artifact = @graph.artifact(package, version)
51
-
52
- dependencies.each do |dependency|
53
- add_dependency artifact, *dependency
54
- end
55
- rescue
56
- if @options[:verbose]
57
- puts "WARNING: Could not add version #{version} to #{package}."
58
- end
59
- end
60
-
61
- # Adds the given package version and single dependency to the
62
- # graph.
63
- def add_dependency(artifact, package, version)
64
- artifact.depends package, version
65
- rescue
66
- if @options[:verbose]
67
- puts "
68
- WARNING: Could not add dependency #{package}-#{version} to #{artifact}
69
- ".strip
70
- end
71
- end
72
- end
73
- end
@@ -1,73 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ElmInstall::ElmPackage do
4
- subject { described_class }
5
-
6
- let(:path) { 'spec/fixtures/elm-package.json' }
7
- let(:invalid_path) { 'spec/fixtures/invalid-elm-package.json' }
8
- let(:mismatch_path) { 'spec/fixtures/mismatched-elm-package.json' }
9
-
10
- context 'package mismatch' do
11
- subject { described_class.dependencies(mismatch_path, silent: false) }
12
-
13
- it 'should exit' do
14
- expect(ElmInstall::ElmPackage)
15
- .to receive(:puts)
16
-
17
- expect(Process).to receive(:exit)
18
- subject
19
- end
20
- end
21
-
22
- context 'missing file' do
23
- subject { described_class.dependencies('test', silent: false) }
24
-
25
- it 'should exit' do
26
- expect(ElmInstall::Logger)
27
- .to receive(:arrow)
28
- .with "Could not find file: #{'test'.bold}."
29
-
30
- expect(Process).to receive(:exit)
31
-
32
- expect { subject }.to raise_error(NoMethodError)
33
- end
34
- end
35
-
36
- context 'invalid file' do
37
- subject { described_class.dependencies(invalid_path, silent: false) }
38
-
39
- it 'should exit' do
40
- expect(ElmInstall::Logger)
41
- .to receive(:arrow)
42
- .with "Invalid JSON in file: #{invalid_path.bold}."
43
-
44
- expect(Process).to receive(:exit)
45
-
46
- expect { subject }.to raise_error(NoMethodError)
47
- end
48
- end
49
-
50
- describe '.transform_dependencies' do
51
- subject { described_class.dependencies(path) }
52
-
53
- it 'should return transformed dependencies' do
54
- expect(subject)
55
- .to eq(
56
- 'git@some-domain.com:test/repo' => 'development',
57
- 'https://github.com/base/core' => '2.0.0 <= v < 3.0.0'
58
- )
59
- end
60
- end
61
-
62
- describe '.transform_package' do
63
- it 'should transform normal packages names to github ones' do
64
- expect(subject.transform_package('test/repo'))
65
- .to eq 'https://github.com/test/repo'
66
- end
67
-
68
- it 'should return valid git urls' do
69
- expect(subject.transform_package('git@github.com:test/repo'))
70
- .to eq 'git@github.com:test/repo'
71
- end
72
- end
73
- end
@@ -1,8 +0,0 @@
1
- {
2
- "https://github.com/base/core": {
3
- "1.0.0": []
4
- },
5
- "https://github.com/test/test": {
6
- "1.0.0": [["https://github.com/base/core",">= 1.0.0"]]
7
- }
8
- }
@@ -1,12 +0,0 @@
1
- {
2
- "dependencies": {
3
- "test/repo": "2.0.0 <= v < 3.0.0",
4
- "base/core": "2.0.0 <= v < 3.0.0"
5
- },
6
- "dependency-sources": {
7
- "test/repo": {
8
- "url": "git@some-domain.com:test/repo",
9
- "ref": "development"
10
- }
11
- }
12
- }
@@ -1,6 +0,0 @@
1
- {
2
- "dependencies": {
3
- "test/repo": "2.0.0 <= v < 3.0.0"
4
- "base/core": "2.0.0 <= v < 3.0.0"
5
- }
6
- }
@@ -1,9 +0,0 @@
1
- {
2
- "dependencies": {
3
- "test/repo": "2.0.0 <= v < 3.0.0",
4
- "base/core": "2.0.0 <= v < 3.0.0"
5
- },
6
- "dependency-sources": {
7
- "test/repo": "git@some-domain.com:base/repo"
8
- }
9
- }
@@ -1,4 +0,0 @@
1
- {
2
- "https://github.com/base/core": {},
3
- "https://github.com/test/test": {}
4
- }
@@ -1,103 +0,0 @@
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
- context 'With cache' do
9
- subject { described_class.new directory: 'spec/fixtures' }
10
-
11
- describe '#save' do
12
- it 'should save cache' do
13
- expect(File).to receive(:binwrite)
14
- subject.save
15
- end
16
- end
17
-
18
- describe '#clear' do
19
- it 'should clear the cache' do
20
- expect do
21
- subject.clear
22
- end.to change {
23
- subject.instance_variable_get('@check_cache').keys.count
24
- }.from(2).to(0)
25
- end
26
- end
27
- end
28
-
29
- describe '.repository' do
30
- let(:refs) { {} }
31
- let(:repo) { Git.init CACHE_DIRECTORY }
32
-
33
- context 'with repository' do
34
- let(:directory) { File.join CACHE_DIRECTORY, 'github.com/test/repo' }
35
-
36
- before do
37
- FileUtils.mkdir_p directory
38
- Git.init directory
39
- end
40
-
41
- context 'with cache' do
42
- before do
43
- subject.instance_variable_get('@check_cache')[directory] = {}
44
- subject.cache[directory] = {}
45
- end
46
-
47
- it 'should return repository' do
48
- repo = subject.repository uri
49
- expect(File.dirname(repo.repo.path))
50
- .to eq File.join(Dir.pwd, directory)
51
- end
52
- end
53
-
54
- context 'without cache' do
55
- before do
56
- expect_any_instance_of(Git::Base)
57
- .to receive(:fetch)
58
-
59
- expect_any_instance_of(Git::Remote)
60
- .to receive(:url)
61
- .and_return uri.to_s
62
-
63
- expect(Git)
64
- .to receive(:ls_remote)
65
- .and_return(refs)
66
-
67
- expect(ElmInstall::Logger)
68
- .to receive(:arrow)
69
- .with "Package: #{'git@github.com:test/repo'.bold} is outdated, \
70
- fetching changes...".gsub(/\s+/, ' ')
71
- end
72
-
73
- it 'should fetch refs and update cache' do
74
- subject.repository uri
75
- end
76
- end
77
- end
78
-
79
- context 'without repository' do
80
- before do
81
- expect(Git)
82
- .to receive(:clone)
83
- .and_return(repo)
84
-
85
- expect(Git)
86
- .to receive(:ls_remote)
87
- .and_return(refs)
88
-
89
- expect(ElmInstall::Logger)
90
- .to receive(:arrow)
91
- .with "Package: #{'git@github.com:test/repo'.bold} not found in \
92
- cache, cloning...".gsub(/\s+/, ' ')
93
- end
94
-
95
- it 'should clone a new repository' do
96
- expect { subject.repository uri }
97
- .to change { subject.cache.keys.count }
98
- .from(0)
99
- .to(1)
100
- end
101
- end
102
- end
103
- end
@@ -1,36 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ElmInstall::GraphBuilder do
4
- let(:cache) { ElmInstall::Cache.new(directory: 'spec/fixtures') }
5
-
6
- subject { described_class.new cache, verbose: true }
7
-
8
- describe '.graph_from_cache' do
9
- it 'should generate a graph from cache' do
10
- graph = described_class.graph_from_cache(cache)
11
- names = graph.artifacts.map(&:name)
12
- expect(names)
13
- .to eq(['https://github.com/base/core',
14
- 'https://github.com/test/test'])
15
- end
16
- end
17
-
18
- describe '.add_version' do
19
- it 'should rescue from errors' do
20
- expect(subject).to receive(:puts)
21
-
22
- subject.send(:add_version, 'test', 'asd', {})
23
- end
24
- end
25
-
26
- describe '.add_dependency' do
27
- let(:artifact) { double :artifact }
28
-
29
- it 'should rescue from errors' do
30
- expect(subject).to receive(:puts)
31
- expect(artifact).to receive(:depends).and_raise 'test'
32
-
33
- subject.send(:add_dependency, artifact, 'asd', {})
34
- end
35
- end
36
- end