librarian 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.0.15
2
+
3
+ * Rewrite the README.
4
+
5
+ * \#44, \#49. Better updating of cached git sources without using local merges.
6
+
1
7
  ## 0.0.14
2
8
 
3
9
  * \#39 Fixes a regression induced by using `git reset --hard SHA`.
data/README.md CHANGED
@@ -1,42 +1,160 @@
1
1
  Librarian
2
2
  =========
3
3
 
4
- A tool to resolve recursively a set of specifications and fetch and install the fully resolved specifications.
4
+ Librarian is a framework for writing bundlers, which are tools that resolve,
5
+ fetch, install, and isolate a project's dependencies, in Ruby.
5
6
 
6
- Librarian::Mock
7
- ---------------
7
+ Librarian ships with Librarian-Chef, which is a bundler for your Chef-based
8
+ infrastructure repositories. In the future, Librarian-Chef will be a separate
9
+ project.
8
10
 
9
- An adapter for Librarian for unit testing the general features.
10
- The mock source is in-process and in-memory and does not touch the filesystem or the network.
11
+ A bundler written with Librarian will expect you to provide a specfile listing
12
+ your project's declared dependencies, including any version constraints and
13
+ including the upstream sources for finding them. Librarian can resolve the spec,
14
+ write a lockfile listing the full resolution, fetch the resolved dependencies,
15
+ install them, and isolate them in your project. This is what Bundler does for
16
+ projects that depend on Ruby gems.
11
17
 
12
- Librarian::Chef
18
+ Librarian-Chef
13
19
  ---------------
14
20
 
15
- An adapter for Librarian applying to Chef cookbooks in a Chef Repository. When used with Chef, Librarian is really for pulling in the 50 or so finished third-party cookbooks that you're using, not the 1 or 2 cookbooks you're actively working on.
21
+ Librarian-Chef is a bundler for infrastructure repositories using Chef. You can
22
+ use Librarian-Chef to resolve your infrastructure's cookbook dependencies and
23
+ fetch them and install them into your infrastructure.
16
24
 
17
- ## Install librarian:
25
+ Librarian-Chef is for resolving and fetching third-party, publicly-released
26
+ cookbooks, and installing them into your infrastructure repository. It is not
27
+ for dealing with the cookbooks you're actively working on within your
28
+ infrastructure repository.
18
29
 
19
- $ gem install librarian
30
+ Librarian-Chef *takes over* your `cookbooks/` directory and manages it for you
31
+ based on your `Cheffile`. Your `Cheffile` becomes the authoritative source for
32
+ what cookbooks your infrastructure repository depends on. You should not modify
33
+ the contents of your `cookbooks/` directory when using Librarian-Chef. If you
34
+ have custom cookbooks specific to your infrastructure repository that you need,
35
+ those should go in your `site-cookbooks/` directory.
36
+
37
+ ### The Cheffile
38
+
39
+ Every infrastruture repository that uses Librarian-Chef will have a file named
40
+ `Cheffile` in the root directory of the repository. The full specification for
41
+ which third-party, publicly-rleased cookbooks your infrastructure repository
42
+ depends will go here.
43
+
44
+ Here's an example `Cheffile`:
45
+
46
+ site "http://community.opscode.com/api/v1"
47
+
48
+ cookbook "ntp"
49
+ cookbook "timezone", "0.0.1"
50
+
51
+ cookbook "rvm",
52
+ :git => "https://github.com/fnichol/chef-rvm",
53
+ :ref => "v0.7.1"
54
+
55
+ cookbook "cloudera",
56
+ :path => "vendor/cookbooks/cloudera-cookbook"
57
+
58
+ Here's how it works:
59
+
60
+ We start off by declaring the *default source* for this `Cheffile`.
61
+
62
+ site "http://community.opscode.com/api/v1"
63
+
64
+ This default source in this example is the Opscode Community Site API. This is
65
+ most likely what you will want for your default source. However, you can
66
+ certainly set up your own API-compatible HTTP endpoint if you want more control.
67
+
68
+ Any time we declare a cookbook dependency without also declaring a source for
69
+ that cookbook dependency, Librarian-Chef assumes we want it to look for that
70
+ cookbook in the default source.
71
+
72
+ Any time we declare a cookbook dependency that has subsidiary cookbook
73
+ dependencies of its own, Librarian-Chef assumes we want it to look for the
74
+ subsidiary cookbook dependencies in the default source.
75
+
76
+ cookbook "ntp"
77
+
78
+ Our infrastructure repository depends on the `ntp` cookbook from the default
79
+ source. Any version of the `ntp` cookbook will fulfill our requirements.
80
+
81
+ cookbook "timezone", "0.0.1"
82
+
83
+ Our infrastructure repository depends on the `timezone` cookbook from the
84
+ default source. But only version `0.0.1` of that cookbook will do.
85
+
86
+ cookbook "rvm",
87
+ :git => "https://github.com/fnichol/chef-rvm",
88
+ :ref => "v0.7.1"
89
+
90
+ Our infrastructure repository depends on the `rvm` cookbook, but not the one
91
+ from the default source. Instead, the cookbook is to be fetched from the
92
+ specified Git repository and from the specified Git tag only.
93
+
94
+ We do not have to use a `:ref =>`. If we do not, then Librarian-Chef will assume
95
+ we meant the branch `master`. (In the future, this will be changed to whatever
96
+ branch is the default branch according to the Git remote, which may not be
97
+ `master`.)
98
+
99
+ If we use a `:ref =>`, we can use anything that Git will recognize as a ref.
100
+ This includes any branch name, tag name, SHA, or SHA unique prefix. If we use a
101
+ branch, we can later ask Librarian-Chef to update the cookbook by fetching the
102
+ most recent version of the cookbook from that same branch.
103
+
104
+ The Git source also supports a `:path =>` option. If we use the path option,
105
+ Librarian-Chef will navigate down into the Git repository and only use the
106
+ specified subdirectory. Many people have the havit of having a single repository
107
+ with many cookbooks in it. If we need a cookbook from such a repository, we can
108
+ use the `:path =>` option here to help Librarian-Chef drill down and find the
109
+ cookbook subdirectory.
20
110
 
111
+ cookbook "cloudera",
112
+ :path => "vendor/cookbooks/cloudera-cookbook"
21
113
 
22
- __Make sure your cookbooks directory is gitignored__
114
+ Our infrastructure repository depends on the `cloudera` cookbook, which we have
115
+ downloaded and copied into our repository. In this example, `vendor/cookbooks/`
116
+ is only for use with Librarian-Chef. This directory should not appear in the
117
+ `.chef/knife.rb`. Librarian-Chef will, instead, copy this cookbook from where
118
+ we vendored it in our repository into the `cookbooks/` directory for us.
119
+
120
+ The `:path =>` source won't be confused with the `:git =>` source's `:path =>`
121
+ option.
122
+
123
+ ### How to Use
124
+
125
+ Install librarian-chef:
126
+
127
+ $ gem install librarian
128
+
129
+ Prepare your infrastructure repository:
23
130
 
24
131
  $ cd ~/path/to/chef-repo
25
- $ git rm -r cookbooks # if the directory is present
132
+ $ git rm -r cookbooks
26
133
  $ echo cookbooks >> .gitignore
27
134
  $ echo tmp >> .gitignore
28
135
 
29
- Note that librarian *takes over* your cookbooks directory
30
- and manages it for you based on your Cheffile. Your
31
- Cheffile becomes the authoritative source for what
32
- cookbooks you have, rather than the directories in your
33
- cookbooks directory.
136
+ Librarian-Chef takes over your `cookbooks/` directory, and will always reinstall
137
+ the cookbooks listed the `Cheffile.lock` into your `cookbooks/` directory. Hence
138
+ you do not need your `cookbooks/` directory to be tracked in Git. If you
139
+ nevertheless want your `cookbooks/` directory to be tracked in Git, simple don't
140
+ `.gitignore` the directory.
34
141
 
35
- __Make a Cheffile__
142
+ If you are manually tracking/vendoring outside cookbooks within the repository,
143
+ put them in another directory such as `vendor/cookbooks/` and use the `:path =>`
144
+ source when declaring these cookbooks in your `Cheffile`. Most people will
145
+ typically not be manually tracking/vendoring outside cookbooks.
146
+
147
+ Librarian-Chef uses your `tmp/` directory for tempfiles and caches. You do not
148
+ need to track this directory in Git.
149
+
150
+ Make a Cheffile:
36
151
 
37
152
  $ librarian-chef init
38
153
 
39
- __Add dependencies and their sources to Cheffile__
154
+ This creates an empty `Cheffile` with the Opscode Community Site API as the
155
+ default source.
156
+
157
+ Add dependencies and their sources to the `Cheffile`:
40
158
 
41
159
  $ cat Cheffile
42
160
  site 'http://community.opscode.com/api/v1'
@@ -45,17 +163,41 @@ __Add dependencies and their sources to Cheffile__
45
163
  cookbook 'rvm',
46
164
  :git => 'https://github.com/fnichol/chef-rvm',
47
165
  :ref => 'v0.7.1'
166
+ cookbook 'cloudera',
167
+ :path => 'vendor/cookbooks/cloudera-cookbook'
48
168
 
49
- __install dependencies into ./cookbooks__
169
+ This is the same `Cheffile` we saw above.
50
170
 
51
171
  $ librarian-chef install [--clean] [--verbose]
52
172
 
53
- __Check your Cheffile.lock into version control__
173
+ This command looks at each `cookbook` declaration and fetches the cookbook from
174
+ the source specified for that cookbook, or from the default source if none is
175
+ provided for that cookbook.
176
+
177
+ Each cookbook is inspected and its dependencies determined, and each dependency
178
+ is also fetched. For example, if you declare `cookbook 'nagios'`, and that
179
+ cookbook depends on other cookbooks such as `'php'`, then those other cookbooks
180
+ including `'php'` will be fetched. This goes all the way down the chain of
181
+ dependencies.
182
+
183
+ This command writes the complete resolution into `Cheffile.lock`.
54
184
 
185
+ This command then copies all of the fetched cookbooks into your `cookbooks/`
186
+ directory, overwriting whatever was there before. You can then use `knife
187
+ cookbook upload -all` to upload the cookbooks to your chef-server, if you are
188
+ using the client-server model.
189
+
190
+ Check your `Cheffile` and `Cheffile.lock` into version control:
191
+
192
+ $ git add Cheffile
55
193
  $ git add Cheffile.lock
56
194
  $ git commit -m "I want these particular versions of these particular cookbooks from these particular."
57
195
 
58
- __Update your cheffile with new/changed/removed constraints/sources/dependencies__
196
+ Make sure you check your Cheffile.lock into version control. This will ensure
197
+ dependencies do not need to be resolved every run, greatly reducing dependency
198
+ resolution time.
199
+
200
+ Update your cheffile with new/changed/removed constraints/sources/dependencies:
59
201
 
60
202
  $ cat Cheffile
61
203
  site 'http://community.opscode.com/api/v1'
@@ -72,43 +214,56 @@ __Update your cheffile with new/changed/removed constraints/sources/dependencies
72
214
  $ git add Cheffile.lock
73
215
  $ git commit -m "I also want these additional cookbooks."
74
216
 
75
- __Update the version of a dependency__
217
+ Update the version of a dependency:
76
218
 
77
219
  $ librarian-chef update ntp timezone monit [--verbose]
78
220
  $ git diff Cheffile.lock
79
221
  $ git add Cheffile.lock
80
222
  $ git commit -m "I want updated versions of these cookbooks."
81
223
 
82
- __Push your changes to the git repository__
224
+ Push your changes to the git repository:
83
225
 
84
226
  $ git push origin master
85
227
 
86
- __Upload the cookbooks to your chef-server__
228
+ Upload the cookbooks to your chef-server:
87
229
 
88
230
  $ knife cookbook upload --all
89
231
 
90
- You should `.gitignore` your `./cookbooks` directory.
91
- If you are manually tracking/vendoring outside cookbooks within the repository,
92
- put them in another directory such as `./cookbooks-sources` and use the `:path` source.
93
- You should typically not need to do this.
232
+ ### Knife Integration
233
+
234
+ You can integrate your `knife.rb` with Librarian-Chef.
94
235
 
95
- You can integrate your `knife.rb` with Librarian. Stick the following in your `knife.rb`:
236
+ Stick the following in your `knife.rb`:
96
237
 
97
238
  require 'librarian/chef/integration/knife'
98
- cookbook_path Librarian::Chef.install_path, "chef-repo/site-cookbooks"
239
+ cookbook_path Librarian::Chef.install_path,
240
+ "/path/to/chef-repo/site-cookbooks"
241
+
242
+ In the above, do *not* to include the path to your `cookbooks/` directory. If
243
+ you have additional cookbooks directories in your chef-repo that you use for
244
+ vendored cookbooks (where you use the `:path =>` source in your `Cheffile`),
245
+ make sure *not* to include the paths to those additional cookbooks directories
246
+ either.
247
+
248
+ You still need to include your `site-cookbooks/` directory in the above list.
249
+
250
+ What this integration does is whenever you use any `knife` command, it will:
251
+
252
+ * Enforce that your `Cheffile` and `Cheffile.lock` are in sync
253
+ * Install the resolved cookbooks to a temporary directory
254
+ * Configure Knife to look in the temporary directory for the installed cookbooks
255
+ and not in the normal `cookbooks/` directory.
256
+
257
+ When you use this integration, any changes you make to anything in the
258
+ `cookbooks/` directory will be ignored by Knife, because Knife won't look in
259
+ that directory for your cookbooks.
99
260
 
100
- In the above, make sure *not* to include the path to your `chef-repo/cookbooks`. If you
101
- have additional cookbooks directories in your chef-repo that you use for `:path`-sourced
102
- cookbooks in your `Cheffile`, make sure *not* to include the paths to those additional
103
- cookbooks directories either in your chef-repo. Since your `chef-repo/site-cookbooks`
104
- directory is for overrides (monkey-patches) to external cookbooks, and since you should
105
- not have any `:path`-sourced cookbooks in your `Cheffile` sourced from that directory,
106
- you still need to include your `chef-repo/site-cookbooks` directory in the above list.
261
+ Reporting Issues
262
+ ----------------
107
263
 
108
- What this integration does is when you use `knife`, it will enforce that your `Cheffile`
109
- and `Cheffile.lock` are in sync. When you `knife cookbook upload`, it will be sure to
110
- upload the same cookbook as is in your `Cheffile.lock`, regardless of what you've done
111
- to your `chef-repo/cookbooks` directory.
264
+ Please include relevant `Cheffile` and `Cheffile.lock` files. Please run the
265
+ `librarian-chef` commands in verbose mode by using the `--verbose` flag, and
266
+ include the verbose output in the bug report as well.
112
267
 
113
268
  License
114
269
  -------
@@ -117,4 +272,5 @@ Written by Jay Feldblum.
117
272
 
118
273
  Copyright (c) 2011 ApplicationsOnline, LLC.
119
274
 
120
- Released under the terms of the MIT License.
275
+ Released under the terms of the MIT License. For further information, please see
276
+ the file `MIT-LICENSE`.
@@ -79,12 +79,16 @@ module Librarian
79
79
  repository.path.mkpath
80
80
  repository.clone!(uri)
81
81
  end
82
+ repository.reset_hard!
82
83
  unless sha == repository.current_commit_hash
83
- repository.fetch!(:tags => true)
84
- repository.fetch!
85
- repository.merge_all_remote_branches!
86
- repository.checkout!(repository.hash_from(sha || ref), :force => true)
87
- @sha ||= repository.current_commit_hash
84
+ remote = repository.default_remote
85
+ repository.fetch!(remote)
86
+ repository.fetch!(remote, :tags => true)
87
+
88
+ new_sha = repository.hash_from(remote, sha || ref)
89
+ repository.checkout!(new_sha)
90
+
91
+ @sha ||= new_sha
88
92
  end
89
93
  end
90
94
 
@@ -33,6 +33,10 @@ module Librarian
33
33
  path.join('.git').exist?
34
34
  end
35
35
 
36
+ def default_remote
37
+ "origin"
38
+ end
39
+
36
40
  def clone!(repository_url)
37
41
  within do
38
42
  command = "clone #{repository_url} ."
@@ -48,48 +52,61 @@ module Librarian
48
52
  end
49
53
  end
50
54
 
51
- def fetch!(options = { })
55
+ def fetch!(remote, options = { })
52
56
  within do
53
- command = "fetch"
57
+ command = "fetch #{remote}"
54
58
  command << " --tags" if options[:tags]
55
59
  run!(command)
56
60
  end
57
61
  end
58
62
 
59
- def merge!(reference)
63
+ def reset_hard!
60
64
  within do
61
- command = "merge #{reference}"
65
+ command = "reset --hard"
62
66
  run!(command)
63
67
  end
64
68
  end
65
69
 
66
- def hash_from(reference)
70
+ def remote_names
67
71
  within do
68
- command = "rev-parse #{reference}"
69
- run!(command).strip
72
+ command = "remote"
73
+ run!(command, false).strip.lines.map(&:strip)
70
74
  end
71
75
  end
72
76
 
73
- def current_commit_hash
77
+ def remote_branch_names
78
+ remotes = remote_names.sort_by(&:length).reverse
79
+
74
80
  within do
75
- command = "rev-parse HEAD"
76
- run!(command).strip!
81
+ command = "branch -r"
82
+ names = run!(command, false).strip.lines.map(&:strip).to_a
83
+ names.each{|n| n.gsub!(/\s*->.*$/, "")}
84
+ names.reject!{|n| n =~ /\/HEAD$/}
85
+ Hash[remotes.map do |r|
86
+ matching_names = names.select{|n| n.start_with?("#{r}/")}
87
+ matching_names.each{|n| names.delete(n)}
88
+ matching_names.each{|n| n.slice!(0, r.size + 1)}
89
+ [r, matching_names]
90
+ end]
77
91
  end
78
92
  end
79
93
 
80
- def merge_all_remote_branches!
81
- remote_branches.each do |branch|
82
- checkout!(branch.slice(%r{[^/]+$}), :force => true)
83
- merge! branch
94
+ def hash_from(remote, reference)
95
+ branch_names = remote_branch_names[remote]
96
+ if branch_names.include?(reference)
97
+ reference = "#{remote}/#{reference}"
98
+ end
99
+
100
+ within do
101
+ command = "rev-parse #{reference}"
102
+ run!(command).strip
84
103
  end
85
104
  end
86
105
 
87
- def remote_branches
106
+ def current_commit_hash
88
107
  within do
89
- command ="branch -r --no-color"
90
- run!(command, false).split("\n ").reject do |r|
91
- r.include? '->' #delete pointers like origin/HEAD -> origin/master
92
- end.collect {|r|r.strip}
108
+ command = "rev-parse HEAD"
109
+ run!(command).strip!
93
110
  end
94
111
  end
95
112
  private
@@ -1,3 +1,3 @@
1
1
  module Librarian
2
- VERSION = "0.0.14"
2
+ VERSION = "0.0.15"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: librarian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-13 00:00:00.000000000 Z
12
+ date: 2012-04-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
16
- requirement: &15281700 !ruby/object:Gem::Requirement
16
+ requirement: &12899900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *15281700
24
+ version_requirements: *12899900
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &15281180 !ruby/object:Gem::Requirement
27
+ requirement: &12899480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *15281180
35
+ version_requirements: *12899480
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &15280600 !ruby/object:Gem::Requirement
38
+ requirement: &12899060 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *15280600
46
+ version_requirements: *12899060
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: cucumber
49
- requirement: &15279900 !ruby/object:Gem::Requirement
49
+ requirement: &12898640 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *15279900
57
+ version_requirements: *12898640
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: aruba
60
- requirement: &15278980 !ruby/object:Gem::Requirement
60
+ requirement: &12898220 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *15278980
68
+ version_requirements: *12898220
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
- requirement: &15278400 !ruby/object:Gem::Requirement
71
+ requirement: &12897800 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *15278400
79
+ version_requirements: *12897800
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: chef
82
- requirement: &15277240 !ruby/object:Gem::Requirement
82
+ requirement: &12897300 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0.10'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *15277240
90
+ version_requirements: *12897300
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: highline
93
- requirement: &15276740 !ruby/object:Gem::Requirement
93
+ requirement: &12896880 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *15276740
101
+ version_requirements: *12896880
102
102
  description: Librarian
103
103
  email:
104
104
  - y_feldblum@yahoo.com
@@ -216,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
216
  version: '0'
217
217
  requirements: []
218
218
  rubyforge_project: librarian
219
- rubygems_version: 1.8.10
219
+ rubygems_version: 1.8.17
220
220
  signing_key:
221
221
  specification_version: 3
222
222
  summary: Librarian