librarian 0.0.9 → 0.0.10

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 (64) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/lib/librarian.rb +5 -178
  3. data/lib/librarian/action.rb +5 -0
  4. data/lib/librarian/action/base.rb +22 -0
  5. data/lib/librarian/action/clean.rb +56 -0
  6. data/lib/librarian/action/ensure.rb +24 -0
  7. data/lib/librarian/action/install.rb +101 -0
  8. data/lib/librarian/action/resolve.rb +81 -0
  9. data/lib/librarian/action/update.rb +76 -0
  10. data/lib/librarian/chef/cli.rb +7 -2
  11. data/lib/librarian/chef/dsl.rb +0 -3
  12. data/lib/librarian/chef/environment.rb +19 -0
  13. data/lib/librarian/chef/extension.rb +1 -16
  14. data/lib/librarian/chef/integration/knife.rb +9 -16
  15. data/lib/librarian/chef/source/git.rb +0 -2
  16. data/lib/librarian/chef/source/local.rb +1 -74
  17. data/lib/librarian/chef/source/local/manifest.rb +82 -0
  18. data/lib/librarian/chef/source/path.rb +0 -2
  19. data/lib/librarian/chef/source/site.rb +9 -89
  20. data/lib/librarian/chef/source/site/manifest.rb +94 -0
  21. data/lib/librarian/cli.rb +56 -17
  22. data/lib/librarian/dependency.rb +2 -2
  23. data/lib/librarian/dsl.rb +15 -5
  24. data/lib/librarian/dsl/receiver.rb +2 -0
  25. data/lib/librarian/dsl/target.rb +13 -1
  26. data/lib/librarian/environment.rb +94 -0
  27. data/lib/librarian/error.rb +4 -0
  28. data/lib/librarian/helpers/debug.rb +6 -6
  29. data/lib/librarian/lockfile.rb +7 -5
  30. data/lib/librarian/lockfile/compiler.rb +5 -4
  31. data/lib/librarian/lockfile/parser.rb +6 -5
  32. data/lib/librarian/manifest.rb +2 -2
  33. data/lib/librarian/mock/cli.rb +6 -1
  34. data/lib/librarian/mock/dsl.rb +0 -3
  35. data/lib/librarian/mock/environment.rb +24 -0
  36. data/lib/librarian/mock/extension.rb +1 -20
  37. data/lib/librarian/mock/source/mock.rb +7 -7
  38. data/lib/librarian/mock/source/mock/registry.rb +16 -12
  39. data/lib/librarian/resolver.rb +5 -116
  40. data/lib/librarian/resolver/implementation.rb +117 -0
  41. data/lib/librarian/source/git.rb +8 -7
  42. data/lib/librarian/source/git/repository.rb +7 -5
  43. data/lib/librarian/source/local.rb +1 -1
  44. data/lib/librarian/source/path.rb +7 -6
  45. data/lib/librarian/spec_change_set.rb +6 -5
  46. data/lib/librarian/specfile.rb +10 -4
  47. data/lib/librarian/version.rb +1 -1
  48. data/librarian.gemspec +1 -0
  49. data/spec/functional/chef/source/git_spec.rb +177 -89
  50. data/spec/functional/chef/source/site_spec.rb +111 -52
  51. data/spec/unit/action/base_spec.rb +18 -0
  52. data/spec/unit/action/clean_spec.rb +133 -0
  53. data/spec/unit/action/ensure_spec.rb +37 -0
  54. data/spec/unit/action/install_spec.rb +113 -0
  55. data/spec/unit/dsl_spec.rb +15 -13
  56. data/spec/unit/environment_spec.rb +9 -0
  57. data/spec/unit/lockfile_spec.rb +15 -4
  58. data/spec/unit/mock/source/mock.rb +22 -0
  59. data/spec/unit/resolver_spec.rb +24 -24
  60. data/spec/unit/spec_change_set_spec.rb +29 -25
  61. metadata +47 -19
  62. data/lib/librarian/chef/particularity.rb +0 -9
  63. data/lib/librarian/mock/particularity.rb +0 -9
  64. data/lib/librarian/particularity.rb +0 -7
@@ -0,0 +1,76 @@
1
+ require "librarian/error"
2
+ require "librarian/manifest_set"
3
+ require "librarian/resolver"
4
+ require "librarian/spec_change_set"
5
+ require "librarian/action/base"
6
+
7
+ module Librarian
8
+ module Action
9
+ class Update < Base
10
+
11
+ def run
12
+ unless lockfile_path.exist?
13
+ raise Error, "Lockfile missing!"
14
+ end
15
+ previous_resolution = lockfile.load(lockfile_path.read)
16
+ partial_manifests = ManifestSet.deep_strip(previous_resolution.manifests, dependency_names)
17
+ spec = specfile.read(previous_resolution.sources)
18
+ spec_changes = spec_change_set(spec, previous_resolution)
19
+ raise Error, "Cannot update when the specfile has been changed." unless spec_changes.same?
20
+ resolution = resolver.resolve(spec, partial_manifests)
21
+ unless resolution.correct?
22
+ raise Error, "Could not resolve the dependencies."
23
+ else
24
+ lockfile_text = lockfile.save(resolution)
25
+ debug { "Bouncing #{lockfile_name}" }
26
+ bounced_lockfile_text = lockfile.save(lockfile.load(lockfile_text))
27
+ unless bounced_lockfile_text == lockfile_text
28
+ debug { "lockfile_text: \n#{lockfile_text}"}
29
+ debug { "bounced_lockfile_text: \n#{bounced_lockfile_text}"}
30
+ raise Error, "Cannot bounce #{lockfile_name}!"
31
+ end
32
+ lockfile_path.open('wb') { |f| f.write(lockfile_text) }
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def dependency_names
39
+ options[:names]
40
+ end
41
+
42
+ def specfile_name
43
+ environment.specfile_name
44
+ end
45
+
46
+ def lockfile_name
47
+ environment.lockfile_name
48
+ end
49
+
50
+ def specfile_path
51
+ environment.specfile_path
52
+ end
53
+
54
+ def lockfile_path
55
+ environment.lockfile_path
56
+ end
57
+
58
+ def specfile
59
+ environment.specfile
60
+ end
61
+
62
+ def lockfile
63
+ environment.lockfile
64
+ end
65
+
66
+ def resolver
67
+ Resolver.new(environment)
68
+ end
69
+
70
+ def spec_change_set(spec, lock)
71
+ SpecChangeSet.new(environment, spec, lock)
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -2,19 +2,24 @@ require 'librarian/helpers'
2
2
 
3
3
  require 'librarian/cli'
4
4
  require 'librarian/chef'
5
- require 'librarian/chef/particularity'
6
5
 
7
6
  module Librarian
8
7
  module Chef
9
8
  class Cli < Librarian::Cli
10
9
 
10
+ module Particularity
11
+ def root_module
12
+ Chef
13
+ end
14
+ end
15
+
11
16
  include Particularity
12
17
  extend Particularity
13
18
 
14
19
  source_root Pathname.new(__FILE__).dirname.join("templates")
15
20
 
16
21
  def init
17
- copy_file root_module.specfile_name
22
+ copy_file environment.specfile_name
18
23
  end
19
24
 
20
25
  end
@@ -1,13 +1,10 @@
1
1
  require 'librarian/dsl'
2
- require 'librarian/chef/particularity'
3
2
  require 'librarian/chef/source'
4
3
 
5
4
  module Librarian
6
5
  module Chef
7
6
  class Dsl < Librarian::Dsl
8
7
 
9
- include Particularity
10
-
11
8
  dependency :cookbook
12
9
 
13
10
  source :site => Source::Site
@@ -0,0 +1,19 @@
1
+ require "librarian/environment"
2
+ require "librarian/chef/dsl"
3
+ require "librarian/chef/source"
4
+
5
+ module Librarian
6
+ module Chef
7
+ class Environment < Environment
8
+
9
+ def specfile_name
10
+ "Cheffile"
11
+ end
12
+
13
+ def install_path
14
+ project_path.join("cookbooks")
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,24 +1,9 @@
1
- require 'librarian/specfile'
2
- require 'librarian/source'
3
- require 'librarian/chef/dsl'
4
- require 'librarian/chef/source'
1
+ require 'librarian/chef/environment'
5
2
 
6
3
  module Librarian
7
4
  module Chef
8
5
  extend self
9
6
  extend Librarian
10
7
 
11
- module Overrides
12
- def specfile_name
13
- 'Cheffile'
14
- end
15
-
16
- def install_path
17
- project_path.join('cookbooks')
18
- end
19
- end
20
-
21
- extend Overrides
22
-
23
8
  end
24
9
  end
@@ -1,13 +1,15 @@
1
+ require 'pathname'
1
2
  require 'securerandom'
2
3
  require 'highline'
3
4
 
4
5
  require 'librarian'
6
+ require 'librarian/action/install'
5
7
  require 'librarian/chef'
6
8
 
7
9
  module Librarian
8
10
  module Chef
9
11
 
10
- module KnifeIntegration
12
+ class Environment
11
13
  def install_path
12
14
  @install_path ||= begin
13
15
  has_home = ENV["HOME"] && File.directory?(ENV["HOME"])
@@ -22,28 +24,19 @@ module Librarian
22
24
  end
23
25
  end
24
26
 
25
- extend KnifeIntegration
26
-
27
- def install_consistent_resolution!
28
- raise Error, "#{specfile_name} missing!" unless specfile_path.exist?
29
- raise Error, "#{lockfile_name} missing!" unless lockfile_path.exist?
27
+ def install_path
28
+ environment.install_path
29
+ end
30
30
 
31
- previous_resolution = lockfile.load(lockfile_path.read)
32
- spec = specfile.read(previous_resolution.sources)
33
- spec_changes = spec_change_set(spec, previous_resolution)
34
- raise Error, "#{specfile_name} and #{lockfile_name} are out of sync!" unless spec_changes.same?
31
+ hl = HighLine.new
35
32
 
36
- previous_resolution.manifests.each do |manifest|
37
- manifest.install!
38
- end
33
+ begin
34
+ Action::Install.new(environment).run
39
35
  rescue Error => e
40
- hl = HighLine.new
41
36
  message = hl.color(e.message, HighLine::RED)
42
37
  hl.say(message)
43
38
  Process.exit!(1)
44
39
  end
45
40
 
46
- install_consistent_resolution!
47
-
48
41
  end
49
42
  end
@@ -1,12 +1,10 @@
1
1
  require 'librarian/source/git'
2
2
  require 'librarian/chef/source/local'
3
- require 'librarian/chef/particularity'
4
3
 
5
4
  module Librarian
6
5
  module Chef
7
6
  module Source
8
7
  class Git < Librarian::Source::Git
9
- include Particularity
10
8
  include Local
11
9
  end
12
10
  end
@@ -1,83 +1,10 @@
1
- require 'fileutils'
2
- require 'pathname'
3
-
4
- require 'librarian/chef/manifest'
1
+ require 'librarian/chef/source/local/manifest'
5
2
 
6
3
  module Librarian
7
4
  module Chef
8
5
  module Source
9
6
  module Local
10
7
 
11
- class Manifest < Manifest
12
-
13
- class << self
14
-
15
- def create(source, dependency, path)
16
- new(source, dependency.name, path)
17
- end
18
-
19
- def manifest?(dependency, path)
20
- path = Pathname.new(path)
21
- !!manifest_path(path)
22
- end
23
-
24
- def check_manifest(dependency, manifest_path)
25
- manifest = read_manifest(dependency.name, manifest_path)
26
- manifest["name"] == dependency.name
27
- end
28
-
29
- end
30
-
31
- attr_reader :path
32
-
33
- def initialize(source, name, path)
34
- super(source, name)
35
- @path = Pathname.new(path)
36
- @found_path = nil
37
- end
38
-
39
- def found_path
40
- @found_path ||= source.manifest_search_paths(self).find{|p| self.class.manifest?(self, p)}
41
- end
42
-
43
- def manifest
44
- @manifest ||= fetch_manifest!
45
- end
46
-
47
- def fetch_manifest!
48
- expect_manifest
49
-
50
- read_manifest(name, manifest_path(found_path))
51
- end
52
-
53
- def fetch_version!
54
- manifest['version']
55
- end
56
-
57
- def fetch_dependencies!
58
- manifest['dependencies']
59
- end
60
-
61
- def install!
62
- debug { "Installing #{name}-#{version}" }
63
- install_path = root_module.install_path.join(name)
64
- if install_path.exist?
65
- debug { "Deleting #{relative_path_to(install_path)}" }
66
- install_path.rmtree
67
- end
68
- debug { "Copying #{relative_path_to(found_path)} to #{relative_path_to(install_path)}" }
69
- FileUtils.cp_r(found_path, install_path)
70
- end
71
-
72
- private
73
-
74
- def expect_manifest
75
- return if found_path && manifest_path(found_path)
76
- raise Error, "No metadata file found for #{name} from #{source}! If this should be a cookbook, you might consider contributing a metadata file upstream or forking the cookbook to add your own metadata file."
77
- end
78
-
79
- end
80
-
81
8
  def manifest_class
82
9
  Manifest
83
10
  end
@@ -0,0 +1,82 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+
4
+ require 'librarian/chef/manifest'
5
+
6
+ module Librarian
7
+ module Chef
8
+ module Source
9
+ module Local
10
+ class Manifest < Manifest
11
+
12
+ class << self
13
+
14
+ def create(source, dependency, path)
15
+ new(source, dependency.name, path)
16
+ end
17
+
18
+ def manifest?(dependency, path)
19
+ path = Pathname.new(path)
20
+ !!manifest_path(path)
21
+ end
22
+
23
+ def check_manifest(dependency, manifest_path)
24
+ manifest = read_manifest(dependency.name, manifest_path)
25
+ manifest["name"] == dependency.name
26
+ end
27
+
28
+ end
29
+
30
+ attr_reader :path
31
+
32
+ def initialize(source, name, path)
33
+ super(source, name)
34
+ @path = Pathname.new(path)
35
+ @found_path = nil
36
+ end
37
+
38
+ def found_path
39
+ @found_path ||= source.manifest_search_paths(self).find{|p| self.class.manifest?(self, p)}
40
+ end
41
+
42
+ def manifest
43
+ @manifest ||= fetch_manifest!
44
+ end
45
+
46
+ def fetch_manifest!
47
+ expect_manifest
48
+
49
+ read_manifest(name, manifest_path(found_path))
50
+ end
51
+
52
+ def fetch_version!
53
+ manifest['version']
54
+ end
55
+
56
+ def fetch_dependencies!
57
+ manifest['dependencies']
58
+ end
59
+
60
+ def install!
61
+ debug { "Installing #{name}-#{version}" }
62
+ install_path = environment.install_path.join(name)
63
+ if install_path.exist?
64
+ debug { "Deleting #{relative_path_to(install_path)}" }
65
+ install_path.rmtree
66
+ end
67
+ debug { "Copying #{relative_path_to(found_path)} to #{relative_path_to(install_path)}" }
68
+ FileUtils.cp_r(found_path, install_path)
69
+ end
70
+
71
+ private
72
+
73
+ def expect_manifest
74
+ return if found_path && manifest_path(found_path)
75
+ raise Error, "No metadata file found for #{name} from #{source}! If this should be a cookbook, you might consider contributing a metadata file upstream or forking the cookbook to add your own metadata file."
76
+ end
77
+
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,12 +1,10 @@
1
1
  require 'librarian/source/path'
2
2
  require 'librarian/chef/source/local'
3
- require 'librarian/chef/particularity'
4
3
 
5
4
  module Librarian
6
5
  module Chef
7
6
  module Source
8
7
  class Path < Librarian::Source::Path
9
- include Particularity
10
8
  include Local
11
9
  end
12
10
  end
@@ -7,111 +7,31 @@ require 'digest'
7
7
 
8
8
  require 'librarian/helpers/debug'
9
9
 
10
- require 'librarian/manifest'
11
- require 'librarian/chef/manifest'
12
- require 'librarian/chef/particularity'
10
+ require 'librarian/chef/source/site/manifest'
13
11
 
14
12
  module Librarian
15
13
  module Chef
16
14
  module Source
17
15
  class Site
18
16
 
19
- class Manifest < Manifest
20
-
21
- attr_reader :version_uri
22
- attr_reader :install_path
23
-
24
- def initialize(source, name, version_uri = nil)
25
- super(source, name)
26
- @version_uri = version_uri
27
-
28
- @cache_path = nil
29
- @metadata_cache_path = nil
30
- @package_cache_path = nil
31
- @install_path = root_module.install_path.join(name)
32
-
33
- @version_metadata = nil
34
- @version_manifest = nil
35
- end
36
-
37
- def fetch_version!
38
- version_metadata['version']
39
- end
40
-
41
- def fetch_dependencies!
42
- version_manifest['dependencies'].map{|k, v| Dependency.new(k, v, nil)}
43
- end
44
-
45
- def version_uri
46
- @version_uri ||= begin
47
- source.cache!([self])
48
- source.manifests(self).find{|m| m.version == version}.version_uri
49
- end
50
- end
51
-
52
- def version_uri=(version_uri)
53
- @version_uri = version_uri
54
- end
55
-
56
- def cache_path
57
- @cache_path ||= source.version_cache_path(self, version_uri)
58
- end
59
- def metadata_cache_path
60
- @metadata_cache_path ||= cache_path.join('version.json')
61
- end
62
- def package_cache_path
63
- @package_cache_path ||= cache_path.join('package')
64
- end
65
-
66
- def version_metadata
67
- @version_metadata ||= fetch_version_metadata!
68
- end
69
-
70
- def fetch_version_metadata!
71
- source.cache_version_metadata!(self, version_uri)
72
- JSON.parse(metadata_cache_path.read)
73
- end
74
-
75
- def version_manifest
76
- @version_manifest ||= fetch_version_manifest!
77
- end
78
-
79
- def fetch_version_manifest!
80
- source.cache_version_package!(self, version_uri, version_metadata['file'])
81
- manifest_path = manifest_path(package_cache_path)
82
- read_manifest(name, manifest_path)
83
- end
84
-
85
- def install!
86
- debug { "Installing #{self}" }
87
- version_manifest # make sure it's cached
88
- if install_path.exist?
89
- debug { "Deleting #{relative_path_to(install_path)}" }
90
- install_path.rmtree
91
- end
92
- package_cache_path = source.version_package_cache_path(self, version_uri)
93
- debug { "Copying #{relative_path_to(package_cache_path)} to #{relative_path_to(install_path)}" }
94
- FileUtils.cp_r(package_cache_path, install_path)
95
- end
96
-
97
- end
98
-
99
17
  include Helpers::Debug
100
- include Particularity
101
18
 
102
19
  class << self
103
20
  LOCK_NAME = 'SITE'
104
21
  def lock_name
105
22
  LOCK_NAME
106
23
  end
107
- def from_lock_options(options)
108
- new(options[:remote], options.reject{|k, v| k == :remote})
24
+ def from_lock_options(environment, options)
25
+ new(environment, options[:remote], options.reject{|k, v| k == :remote})
109
26
  end
110
27
  end
111
28
 
29
+ attr_accessor :environment
30
+ private :environment=
112
31
  attr_reader :uri
113
32
 
114
- def initialize(uri, options = {})
33
+ def initialize(environment, uri, options = {})
34
+ self.environment = environment
115
35
  @uri = uri
116
36
  @cache_path = nil
117
37
  end
@@ -156,13 +76,13 @@ module Librarian
156
76
  end
157
77
 
158
78
  def install_path(dependency)
159
- root_module.install_path.join(dependency.name)
79
+ environment.install_path.join(dependency.name)
160
80
  end
161
81
 
162
82
  def cache_path
163
83
  @cache_path ||= begin
164
84
  dir = Digest::MD5.hexdigest(uri)
165
- root_module.cache_path.join("source/chef/site/#{dir}")
85
+ environment.cache_path.join("source/chef/site/#{dir}")
166
86
  end
167
87
  end
168
88