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,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