librarian 0.0.9 → 0.0.10

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