elm_install 0.3.1 → 1.0.0

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.
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,100 +1,79 @@
1
1
  module ElmInstall
2
- # This class is responsible for populating the `elm-stuff` directory.
3
- class Populator
4
- # Initializes a new populator.
2
+ # Populator for 'elm-stuff' directory
3
+ class Populator < Base
4
+ Contract ArrayOf[Dependency] => Populator
5
+ # Initializes a new populator
5
6
  #
6
- # @param git_resolver [GitResolver] The git resolver to use.
7
- def initialize(git_resolver)
8
- @git_resolver = git_resolver
9
- end
10
-
11
- # Populates `elm-stuff` from the given solution.
12
- #
13
- # @param solution [Hash] The solution.
14
- #
15
- # @return [void]
16
- def populate(solution)
17
- solution.each do |package, version|
18
- resolve_package package, version
19
- end
20
-
21
- write_exact_dependencies(solution)
22
- end
23
-
24
- # Resolves and copies a package and it's version to `elm-stuff/packages`
25
- # directory.
26
- #
27
- # :reek:TooManyStatements { max_statements: 9 }
7
+ # @param dependencies [Array] The dependencies to populate
28
8
  #
29
- # @param package [String] The package
30
- # @param version_str [String] The resolved version
31
- #
32
- # @return [void]
33
- def resolve_package(package, version_str)
34
- version, ref = self.class.version_and_ref(version_str)
35
-
36
- package_name, package_path = Utils.package_version_path package, version
37
-
38
- @git_resolver.repository(package).checkout(ref)
39
-
40
- Logger.dot "#{package_name.bold} - #{version.bold} (#{ref})"
41
-
42
- FileUtils.rm_rf(package_path) if Dir.exist?(package_path)
43
-
44
- copy_package package, package_path
9
+ # @return Populator The populator instance
10
+ def initialize(dependencies)
11
+ @dependencies = dependencies
12
+ self
45
13
  end
46
14
 
47
- # Copies the given package from it's repository to the given path.
15
+ Contract None => NilClass
16
+ # Populates 'elm-stuff' directory and writes
17
+ # 'elm-stuff/exact-dependencies.json'.
48
18
  #
49
- # @param package [String] The package to copy
50
- # @param package_path [String] The destination
51
- #
52
- # @return [void]
53
- def copy_package(package, package_path)
54
- repository_path = File.join(@git_resolver.repository_path(package), '.')
55
-
56
- FileUtils.mkdir_p(package_path)
57
- FileUtils.cp_r(repository_path, package_path)
58
- FileUtils.rm_rf(File.join(package_path, '.git'))
19
+ # @return nil
20
+ def populate
21
+ copy_dependencies
22
+ write_exact_dependencies
59
23
  end
60
24
 
61
- # Writes the `elm-stuff/exact-dependencies.json` file.
62
- #
63
- # @param solution [Hash] The solution
25
+ Contract None => NilClass
26
+ # Writes the 'elm-stuff/exact-dependencies.json'
64
27
  #
65
- # @return [void]
66
- def write_exact_dependencies(solution)
28
+ # @return nil
29
+ def write_exact_dependencies
67
30
  File.binwrite(
68
31
  File.join('elm-stuff', 'exact-dependencies.json'),
69
- JSON.pretty_generate(self.class.exact_dependencies(solution))
32
+ JSON.pretty_generate(exact_dependencies)
70
33
  )
34
+ nil
71
35
  end
72
36
 
73
- # Returns the exact dependencies from the solution.
37
+ Contract None => HashOf[String => String]
38
+ # Returns the contents for 'elm-stuff/exact-dependencies.json'
74
39
  #
75
- # @param solution [Hash] The solution
40
+ # @return [Hash] The dependencies
41
+ def exact_dependencies
42
+ @dependencies.each_with_object({}) do |dependency, memo|
43
+ memo[dependency.name] = dependency.version.to_simple
44
+ end
45
+ end
46
+
47
+ Contract None => NilClass
48
+ # Copies dependencies to 'elm-stuff/packages/package/version' directory
76
49
  #
77
- # @return [void]
78
- def self.exact_dependencies(solution)
79
- solution.each_with_object({}) do |(key, value), memo|
80
- version, = version_and_ref value
50
+ # @return nil
51
+ def copy_dependencies
52
+ @dependencies.each do |dependency|
53
+ path =
54
+ File.join('elm-stuff', 'packages', dependency.name,
55
+ dependency.version.to_simple)
81
56
 
82
- memo[GitCloneUrl.parse(key).path.sub(%r{^/}, '')] = version
57
+ log_dependency dependency
58
+
59
+ dependency.source.copy_to(dependency.version, Pathname.new(path))
83
60
  end
61
+ nil
84
62
  end
85
63
 
86
- # Retruns the version and the ref from the given string.
64
+ Contract Dependency => NilClass
65
+ # Logs the dependency with a dot
87
66
  #
88
- # @param value [String] The input
67
+ # @param dependency [Dependency] The dependency
89
68
  #
90
- # @return [Array] The version and the ref as an array
91
- def self.version_and_ref(value)
92
- match = value.match(/(.+)\+(.+)/)
93
-
94
- version = match ? match[1] : value
95
- ref = match ? match[2] : value
96
-
97
- [version, ref]
69
+ # @return nil
70
+ def log_dependency(dependency)
71
+ log = "#{dependency.name} - "
72
+ log += dependency.source.to_log.to_s
73
+ log += " (#{dependency.version.to_simple})"
74
+
75
+ Logger.dot log
76
+ nil
98
77
  end
99
78
  end
100
79
  end
@@ -0,0 +1,82 @@
1
+ module ElmInstall
2
+ # Handles git repositories.
3
+ class Repository < Base
4
+ extend Forwardable
5
+
6
+ # The url of the git repository
7
+ # @return [String]
8
+ attr_reader :url
9
+
10
+ # The path to the directory where the repository lives
11
+ # @return [String]
12
+ attr_reader :path
13
+
14
+ def_delegators :repo, :fetch
15
+
16
+ Contract String, String => Repository
17
+ # Initializes a repository.
18
+ #
19
+ # @param url [String] The url
20
+ # @param path [String] The path
21
+ #
22
+ # @return [Repository] The repository instance
23
+ def initialize(url, path)
24
+ @path = path
25
+ @url = url
26
+ self
27
+ end
28
+
29
+ Contract String => Dir
30
+ # Checks out the version and returns it's directory
31
+ #
32
+ # @param ref [String] The reference to checkout
33
+ #
34
+ # @return [Dir] The directory
35
+ def checkout(ref)
36
+ repo.checkout ref
37
+ directory
38
+ end
39
+
40
+ Contract None => Dir
41
+ # Returns the directory of the repository
42
+ #
43
+ # @return [Dir] The directory
44
+ def directory
45
+ # This removes the .git from filename
46
+ Dir.new(File.dirname(repo.repo.path))
47
+ end
48
+
49
+ Contract None => ArrayOf[Semverse::Version]
50
+ # Returns the versions of the repository
51
+ #
52
+ # @return [Array<Semverse::Version>] The versions
53
+ def versions
54
+ repo
55
+ .tags
56
+ .map(&:name)
57
+ .map { |tag| Semverse::Version.try_new tag }
58
+ .compact
59
+ end
60
+
61
+ Contract None => Git::Base
62
+ # Returns the existing repository or clones it if it does not exists.
63
+ #
64
+ # @return [Git::Base]
65
+ def repo
66
+ clone unless Dir.exist?(path)
67
+ @repo ||= Git.open path
68
+ @repo.reset_hard
69
+ @repo
70
+ end
71
+
72
+ Contract None => Git::Base
73
+ # Clones the repository
74
+ #
75
+ # @return [Git::Base]
76
+ def clone
77
+ Logger.arrow "Package: #{url.bold} not found in cache, cloning..."
78
+ FileUtils.mkdir_p path
79
+ @repo = Git.clone(url, path)
80
+ end
81
+ end
82
+ end
@@ -1,145 +1,75 @@
1
- require_relative './cache'
2
- require_relative './utils'
3
-
4
1
  module ElmInstall
5
- # Resolves git dependencies into the cache.
6
- class Resolver
7
- # @return [Array] The constraints
8
- attr_reader :constraints
9
-
10
- # Initializes a resolver with a chace and git resolver.
11
- #
12
- # @param cache [Cache] The cache
13
- # @param git_resolver [GitResolver] The git resolver
14
- def initialize(cache, git_resolver)
15
- @git_resolver = git_resolver
16
- @constraints = []
17
- @cache = cache
18
- end
2
+ # Resolves dependencies
3
+ class Resolver < Base
4
+ # @return [Array<Dependency>] The dependencies
5
+ attr_reader :dependencies
19
6
 
20
- # Add constraints, usually from the `elm-package.json`.
7
+ Contract Identifier => Resolver
8
+ # Initializes a resolver
21
9
  #
22
- # @param constraints [Hash] The constraints
10
+ # @param identifier [Identifier] The identifier
23
11
  #
24
- # @return [void]
25
- def add_constraints(constraints)
26
- @constraints = add_dependencies(constraints) do |package, constraint|
27
- [package, constraint]
28
- end
12
+ # @return [Resolver]
13
+ def initialize(identifier)
14
+ @graph = Solve::Graph.new
15
+ @identifier = identifier
16
+ @dependencies = {}
17
+ self
29
18
  end
30
19
 
31
- # Adds dependencies, usually from any `elm-package.json` file.
32
- #
33
- # :reek:NestedIterators { max_allowed_nesting: 2 }
20
+ Contract None => Solve::Graph
21
+ # Resolves the constraints for a version
34
22
  #
35
- # @param dependencies [Hash] The dependencies
36
- #
37
- # @yieldreturn [Array] A constraint
38
- # @return [void]
39
- def add_dependencies(dependencies)
40
- dependencies.flat_map do |package, constraint|
41
- add_package(package)
42
-
43
- constraints = Utils.transform_constraint(constraint)
44
- next add_ref_dependency(package, constraint) if constraints.empty?
45
-
46
- constraints.map do |dependency|
47
- yield package, dependency
48
- end
23
+ # @return [Solve::Graph] Returns the graph
24
+ def resolve
25
+ @identifier.initial_dependencies.each do |dependency|
26
+ resolve_dependency dependency
49
27
  end
50
- end
51
28
 
52
- # Adds a dependency by git reference.
53
- #
54
- # @param package [String] The package
55
- # @param ref [String] The reference
56
- #
57
- # @return [void]
58
- def add_ref_dependency(package, ref)
59
- @git_resolver.repository(package).checkout(ref)
60
- pkg_version = elm_package(package)['version']
61
- version = "#{pkg_version}+#{ref}"
62
- @cache.ensure_version(package, version)
63
- add_package_dependencies(package, version)
64
- [[package, "= #{version}"]]
29
+ @graph
65
30
  end
66
31
 
67
- # Adds a package to the cache, the following things happens:
68
- # * If there is no local repository it will be cloned
69
- # * Getting all the tags and adding the valid ones to the cache
70
- # * Checking out and getting the `elm-package.json` for each version
71
- # and adding them recursivly
32
+ Contract Dependency => NilClass
33
+ # Resolves the dependencies of a dependency
72
34
  #
73
- # @param package [String] The package
35
+ # @param dependency [Dependency] The dependency
74
36
  #
75
- # @return [void]
76
- def add_package(package)
77
- return if @git_resolver.package?(package) && @cache.key?(package)
37
+ # @return nil
38
+ def resolve_dependency(dependency)
39
+ return if @dependencies[dependency.name]
40
+
41
+ @dependencies[dependency.name] ||= dependency
78
42
 
79
- @git_resolver
80
- .repository(package)
81
- .tags
82
- .map(&:name)
43
+ dependency
44
+ .source
45
+ .versions(dependency.constraints)
83
46
  .each do |version|
84
- @cache.ensure_version(package, version)
85
- add_version(package, version)
47
+ resolve_dependencies(dependency, version)
86
48
  end
87
- end
88
49
 
89
- # Adds a package's dependencies to the cache.
90
- #
91
- # @param package [String] The package
92
- # @param version [String] The version
93
- #
94
- # @return [void]
95
- def add_package_dependencies(package, version)
96
- add_dependencies(elm_dependencies(package)) do |dep_package, constraint|
97
- add_package(dep_package)
98
- @cache.dependency(package, version, [dep_package, constraint])
99
- end
50
+ nil
100
51
  end
101
52
 
102
- # Adds a version and it's dependencies to the cache.
53
+ Contract Dependency, Semverse::Version => NilClass
54
+ # Resolves the dependencies of a dependency and version
103
55
  #
104
- # @param package [String] The package
105
- # @param version [String] The version
56
+ # @param main [Dependency] The dependency
57
+ # @param version [Semverse::Version] The version
106
58
  #
107
- # @return [void]
108
- def add_version(package, version)
109
- @git_resolver
110
- .repository(package)
111
- .checkout(version)
112
-
113
- add_package_dependencies(package, version)
114
- end
59
+ # @return nil
60
+ def resolve_dependencies(main, version)
61
+ dependencies = @identifier.identify(main.source.fetch(version))
62
+ artifact = @graph.artifact main.name, version
115
63
 
116
- # Gets the `elm-package.json` for a package.
117
- #
118
- # @param package [String] The package
119
- #
120
- # @return [Hash] The dependencies
121
- def elm_dependencies(package)
122
- ElmPackage.dependencies elm_package_path(package)
123
- rescue
124
- {}
125
- end
64
+ dependencies.each do |dependency|
65
+ dependency.constraints.each do |constraint|
66
+ artifact.depends dependency.name, constraint
67
+ end
126
68
 
127
- # Retruns the contents of the `elm-pacakge.json` of the given package.
128
- #
129
- # @param package [String] The package
130
- #
131
- # @return [Hash] The contents
132
- def elm_package(package)
133
- ElmPackage.read elm_package_path(package)
134
- end
69
+ resolve_dependency dependency
70
+ end
135
71
 
136
- # Retruns the path of the `elm-pacakge.json` of the given package.
137
- #
138
- # @param package [String] The package
139
- #
140
- # @return [String] The path
141
- def elm_package_path(package)
142
- File.join(@git_resolver.repository_path(package), 'elm-package.json')
72
+ nil
143
73
  end
144
74
  end
145
75
  end
@@ -0,0 +1,18 @@
1
+ module ElmInstall
2
+ # Abstract class for a source
3
+ class Source < Base
4
+ # @overload identifier
5
+ # @return [Identifier] The identifier
6
+ # @overload identifier=(value)
7
+ # Sets the identifier
8
+ # @param [Identifier] The identifier
9
+ attr_accessor :identifier
10
+
11
+ # @overload options
12
+ # @return [Hash] The options
13
+ # @overload options=(value)
14
+ # Sets the options
15
+ # @param [Hash] The options
16
+ attr_accessor :options
17
+ end
18
+ end