rubycut-babushka 0.10.8 → 0.15.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +17 -15
  3. data/README.markdown +163 -41
  4. data/Rakefile +1 -1
  5. data/bin/babushka +1 -1
  6. data/deps/apt.rb +44 -0
  7. data/deps/babushka.rb +54 -42
  8. data/deps/deprecated.rb +16 -0
  9. data/deps/dev.rb +28 -3
  10. data/deps/git.rb +27 -12
  11. data/deps/homebrew.rb +2 -2
  12. data/deps/packages.rb +14 -15
  13. data/deps/pkg_managers.rb +21 -75
  14. data/deps/ruby.rb +5 -19
  15. data/deps/rubygems.rb +3 -3
  16. data/deps/system.rb +2 -2
  17. data/deps/templates/app.rb +60 -41
  18. data/deps/templates/bin.rb +16 -0
  19. data/deps/templates/installer.rb +9 -9
  20. data/deps/templates/lib.rb +17 -0
  21. data/deps/templates/managed.rb +1 -38
  22. data/deps/templates/src.rb +16 -8
  23. data/deps/templates/task.rb +11 -0
  24. data/deps/templates/tmbundle.rb +16 -2
  25. data/lib/babushka.rb +2 -3
  26. data/lib/babushka/accepts_block_for.rb +5 -3
  27. data/lib/babushka/asset.rb +172 -0
  28. data/lib/babushka/base.rb +37 -8
  29. data/lib/babushka/bug_reporter.rb +6 -6
  30. data/lib/babushka/cmdline.rb +11 -10
  31. data/lib/babushka/cmdline/handler.rb +7 -3
  32. data/lib/babushka/cmdline/helpers.rb +15 -23
  33. data/lib/babushka/cmdline/parser.rb +1 -1
  34. data/lib/babushka/core_patches/object.rb +1 -1
  35. data/lib/babushka/core_patches/string.rb +8 -3
  36. data/lib/babushka/current_ruby.rb +44 -0
  37. data/lib/babushka/dep.rb +111 -185
  38. data/lib/babushka/dep_context.rb +8 -3
  39. data/lib/babushka/dep_definer.rb +45 -15
  40. data/lib/babushka/dep_pool.rb +5 -8
  41. data/lib/babushka/{meta_dep.rb → dep_template.rb} +21 -2
  42. data/lib/babushka/dsl.rb +3 -0
  43. data/lib/babushka/git_repo.rb +143 -49
  44. data/lib/babushka/helpers/git_helpers.rb +7 -6
  45. data/lib/babushka/helpers/log_helpers.rb +51 -13
  46. data/lib/babushka/helpers/path_helpers.rb +5 -7
  47. data/lib/babushka/helpers/run_helpers.rb +15 -55
  48. data/lib/babushka/helpers/shell_helpers.rb +18 -26
  49. data/lib/babushka/helpers/uri_helpers.rb +9 -18
  50. data/lib/babushka/lambda_chooser.rb +20 -13
  51. data/lib/babushka/parameter.rb +20 -4
  52. data/lib/babushka/path_checker.rb +72 -0
  53. data/lib/babushka/pkg_helper.rb +38 -13
  54. data/lib/babushka/pkg_helpers/apt_helper.rb +15 -8
  55. data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +15 -14
  56. data/lib/babushka/pkg_helpers/binports_helper.rb +7 -7
  57. data/lib/babushka/pkg_helpers/brew_helper.rb +17 -25
  58. data/lib/babushka/pkg_helpers/gem_helper.rb +36 -27
  59. data/lib/babushka/pkg_helpers/npm_helper.rb +9 -9
  60. data/lib/babushka/pkg_helpers/pacman_helper.rb +5 -4
  61. data/lib/babushka/pkg_helpers/pip_helper.rb +14 -10
  62. data/lib/babushka/pkg_helpers/unknown_pkg_helper.rb +19 -0
  63. data/lib/babushka/pkg_helpers/yum_helper.rb +1 -1
  64. data/lib/babushka/popen.rb +13 -10
  65. data/lib/babushka/prompt.rb +14 -1
  66. data/lib/babushka/renderable.rb +11 -9
  67. data/lib/babushka/resource.rb +5 -166
  68. data/lib/babushka/run_reporter.rb +12 -3
  69. data/lib/babushka/shell.rb +54 -44
  70. data/lib/babushka/source.rb +41 -20
  71. data/lib/babushka/source_pool.rb +20 -13
  72. data/lib/babushka/system_definitions.rb +11 -3
  73. data/lib/babushka/system_detector.rb +31 -0
  74. data/lib/babushka/system_matcher.rb +53 -0
  75. data/lib/babushka/system_profile.rb +67 -89
  76. data/lib/babushka/task.rb +36 -8
  77. data/lib/babushka/{meta_dep_context.rb → templated_dep_context.rb} +1 -1
  78. data/lib/babushka/vars.rb +46 -4
  79. data/lib/babushka/version_of.rb +35 -17
  80. data/lib/babushka/version_str.rb +12 -8
  81. data/lib/components.rb +9 -8
  82. data/lib/fancypath/fancypath.rb +109 -83
  83. data/lib/inkan/inkan.rb +14 -14
  84. data/lib/{babushka → levenshtein}/levenshtein.rb +0 -0
  85. data/spec/acceptance/acceptance.rb +4 -4
  86. data/spec/acceptance_helper.rb +10 -6
  87. data/spec/babushka/accepts_for_spec.rb +137 -142
  88. data/spec/babushka/accepts_for_support.rb +13 -6
  89. data/spec/babushka/asset_spec.rb +165 -0
  90. data/spec/babushka/cmdline/help_spec.rb +11 -9
  91. data/spec/babushka/cmdline/meet_spec.rb +15 -0
  92. data/spec/babushka/cmdline/version_spec.rb +1 -1
  93. data/spec/babushka/core_patches_spec.rb +9 -0
  94. data/spec/babushka/current_ruby_spec.rb +73 -0
  95. data/spec/babushka/dep_context_spec.rb +27 -13
  96. data/spec/babushka/dep_definer_spec.rb +108 -16
  97. data/spec/babushka/dep_spec.rb +87 -104
  98. data/spec/babushka/dep_template_spec.rb +176 -0
  99. data/spec/babushka/deps_spec.rb +48 -19
  100. data/spec/babushka/gem_helper_spec.rb +46 -59
  101. data/spec/babushka/git_repo_spec.rb +242 -51
  102. data/spec/babushka/ip_spec.rb +11 -11
  103. data/spec/babushka/lambda_chooser_spec.rb +47 -9
  104. data/spec/babushka/parameter_spec.rb +21 -0
  105. data/spec/babushka/path_checker_spec.rb +35 -0
  106. data/spec/babushka/path_helpers_spec.rb +51 -50
  107. data/spec/babushka/prompt_spec.rb +4 -4
  108. data/spec/babushka/renderable_spec.rb +61 -28
  109. data/spec/babushka/shell_helpers_spec.rb +110 -85
  110. data/spec/babushka/shell_spec.rb +15 -0
  111. data/spec/babushka/source_pool_spec.rb +204 -210
  112. data/spec/babushka/source_spec.rb +125 -42
  113. data/spec/babushka/source_support.rb +1 -1
  114. data/spec/babushka/system_profile_spec.rb +86 -49
  115. data/spec/babushka/task_spec.rb +80 -13
  116. data/spec/babushka/vars_spec.rb +2 -1
  117. data/spec/babushka/version_of_spec.rb +29 -2
  118. data/spec/babushka/version_str_spec.rb +91 -65
  119. data/spec/babushka/xml_string_spec.rb +1 -1
  120. data/spec/deps/bad/broken.rb +2 -2
  121. data/spec/deps/bad/working.rb +0 -1
  122. data/spec/deps/good/{meta.rb → template.rb} +0 -0
  123. data/spec/deps/good/test.rb +0 -3
  124. data/spec/deps/outer/deps.rb +0 -2
  125. data/spec/fancypath/fancypath_spec.rb +30 -0
  126. data/spec/inkan/inkan_spec.rb +34 -32
  127. data/spec/spec_helper.rb +7 -50
  128. data/spec/system_detector_spec.rb +70 -0
  129. metadata +163 -177
  130. data/deps/os_x.rb +0 -33
  131. data/deps/templates/ppa.rb +0 -24
  132. data/lib/babushka/core_patches/io.rb +0 -8
  133. data/lib/babushka/dep_runner.rb +0 -85
  134. data/lib/babushka/helpers/suggest_helpers.rb +0 -16
  135. data/lib/babushka/pkg_helpers/base_helper.rb +0 -19
  136. data/lib/babushka/pkg_helpers/macports_helper.rb +0 -22
  137. data/spec/babushka/dep_definer_support.rb +0 -36
  138. data/spec/babushka/meta_dep_definer_spec.rb +0 -127
  139. data/spec/babushka/meta_dep_wrapper_spec.rb +0 -32
  140. data/spec/babushka/resource_spec.rb +0 -141
  141. data/spec/babushka/run_helpers_spec.rb +0 -26
  142. data/spec/babushka/source_pool_support.rb +0 -31
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ group :test do
5
5
  gem 'rspec'
6
6
  gem 'fuubar'
7
7
  gem 'cloudservers'
8
+ gem 'ir_b'
8
9
  end
data/Gemfile.lock CHANGED
@@ -1,25 +1,26 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- cloudservers (0.4.1)
4
+ cloudservers (0.4.2)
5
5
  json
6
6
  diff-lcs (1.1.3)
7
- fuubar (0.0.6)
7
+ fuubar (1.1.0)
8
8
  rspec (~> 2.0)
9
- rspec-instafail (~> 0.1.8)
10
- ruby-progressbar (~> 0.0.10)
11
- json (1.6.1)
9
+ rspec-instafail (~> 0.2.0)
10
+ ruby-progressbar (~> 1.0.0)
11
+ ir_b (1.5.0)
12
+ json (1.7.5)
12
13
  rake (0.9.2.2)
13
- rspec (2.7.0)
14
- rspec-core (~> 2.7.0)
15
- rspec-expectations (~> 2.7.0)
16
- rspec-mocks (~> 2.7.0)
17
- rspec-core (2.7.1)
18
- rspec-expectations (2.7.0)
19
- diff-lcs (~> 1.1.2)
20
- rspec-instafail (0.1.9)
21
- rspec-mocks (2.7.0)
22
- ruby-progressbar (0.0.10)
14
+ rspec (2.11.0)
15
+ rspec-core (~> 2.11.0)
16
+ rspec-expectations (~> 2.11.0)
17
+ rspec-mocks (~> 2.11.0)
18
+ rspec-core (2.11.1)
19
+ rspec-expectations (2.11.3)
20
+ diff-lcs (~> 1.1.3)
21
+ rspec-instafail (0.2.4)
22
+ rspec-mocks (2.11.3)
23
+ ruby-progressbar (1.0.2)
23
24
 
24
25
  PLATFORMS
25
26
  ruby
@@ -27,5 +28,6 @@ PLATFORMS
27
28
  DEPENDENCIES
28
29
  cloudservers
29
30
  fuubar
31
+ ir_b
30
32
  rake
31
33
  rspec
data/README.markdown CHANGED
@@ -1,40 +1,132 @@
1
- # About this repo
1
+ # babushka: test-driven sysadmin.
2
2
 
3
- While using this gem, keep in mind:
3
+ - _docs: http://babushka.me_
4
+ - _rdocs: http://babushka.me/rdoc_
4
5
 
5
- * This software is packaged as rubycut-babushka, since author asked us not to use babushka as gem name since he wants to keep only one way of installing babushka (see https://github.com/benhoskings/babushka/issues/173 for details)
6
- * by using this babushka as gem, it is not possible for babushka to configure ruby and rubygems
7
- * switching the active rvm/rbenv ruby, or installing a new ruby that shadows the existing one, changes the set of gems that are in the path, which would make it look like babushka had disappeared.
8
- * lot of tools are confined to a single set of gems, or a single bundle. But babushka should exist outside of those things so it can configure them.
9
- * This is unstandard way to install babushka, standard way is explained at: http://babushka.me/installing
10
- * This gem is built using https://github.com/rubycut/babushka, we try to follow main repo but can not guearantee that we will produce gem same day official babushka version comes out
11
- * we will not be adding any new code to babhushka source code for now, but we will add more source documentation
6
+ A lot of the tech jobs we do manually aren't challenging or fun, but they're quite particular and have to be done just right -- they're chores. Things that are important to do, but that are better automated than done manually.
12
7
 
8
+ That's what babushka is for. Once you describe a job using its DSL, babushka can not only accomplish each part of the job, but also check if each part is already satisfied. For each component of the job, a test, along with the code to make that test pass -- test-driven sysadmin.
13
9
 
14
- ## Development status
15
10
 
16
- This gem is not fully tested in realistic environment, although all the spec work.
11
+ # installing
17
12
 
18
- # babushka: test-driven sysadmin.
13
+ Installing is really easy. All it takes is one command, and it can be the first command you run on the machine. (Babushka will happily install on any machine though, not just new ones.)
14
+
15
+ If you have curl (OS X):
16
+
17
+ bash -c "`curl babushka.me/up`"
18
+
19
+ If you have wget (Ubuntu):
20
+
21
+ bash -c "`wget -O - babushka.me/up`"
22
+
23
+ Babushka should run on any Unix. OS X and Ubuntu are fully supported, including their respective package managers, homebrew and apt. There is some yum (RedHat/Fedora/CentOS) and pacman (Arch) support, but I'm not familiar with those systems so it might be incomplete. Patches are most welcome.
24
+
25
+
26
+ # kicking the tyres
27
+
28
+ Once the install process has finished, you're ready to rock. If you have a Mac, maybe a good example is to install homebrew. To do that, we run the dependency (in babushka parlance, 'dep') called `homebrew`:
29
+
30
+ babushka homebrew
31
+
32
+ Another example. Here's how you could check that your rubygems install is up to date and in the right place. This demonstrates how babushka works: it's the goal (rubygems set up well) that's important. You can safely run this whether rubygems is outdated, up to date, or missing, and babushka will work out what tasks need to be done in order to achieve the end goal. The `rubygems` dep handles that.
33
+
34
+ babushka rubygems
35
+
36
+ Things like rubygems and homebrew aren't hard to install on their own, but with babushka it's _really_ easy, and _fast_. But more importantly, you know the job is being done just right, every time.
37
+
38
+ (These deps aren't special, they're just bundled along with babushka because I like to ship package manager support.)
39
+
40
+ OK, something more complex now---a vhosting nginx. Since there's not much point configuring nginx until it's installed, this dep `requires` another called `nginx.src` that does the actual install (i.e. downloading and building the source). That means calling this one will include the installation if it's not already present (i.e. if `nginx.src` is unmet).
41
+
42
+ babushka benhoskings:'configured.nginx'
43
+
44
+ Then you can set up each virtualhost with another dep (which itself requires `configured.nginx`). In fact, you could call just this one, and leave the one above: configuring a vhost requires the global config, which in turn requires the install.
45
+
46
+ The idea is that you can talk solely about your actual goal, without regard for the dependencies -- they'll all be pulled in as required.
47
+
48
+ babushka benhoskings:'vhost configured.nginx'
49
+
50
+ That's how I set up my production machines. If something isn't working, you have a list of things that _aren't_ the culprit: everything in the output with a green ✓ beside it. Conversely, if babushka can detect the problem, the failing dep will have a red ✗ beside it instead, which leads you straight to the cause of the problem. Test-driven sysadmin!
51
+
52
+
53
+ # nothing up my sleeve…
54
+
55
+ Creating and sharing this knowledge is central to babushka. It's all very well to run `babushka rubygems` and have it do a job for you, but the real power is in babushka's ability to automate whatever chore you want, not just ones that others have thought of already.
56
+
57
+ To that end, I've tried really hard to make the process quick and satisfying. If you spend a little bit of time getting the feel for babushka's DSL, you'll be cranking out deps just like the rubygems, homebrew, and nginx ones above.
58
+
59
+
60
+ ## yeah, but how?
19
61
 
20
- When you spend time researching something new, it's pretty easy to forget what you found, and have to re-research it again next time.
62
+ A dep is one single piece of a larger task. A little nugget of code that does just one thing, and does it right. Here's a babushka dep, at its most generic.
21
63
 
22
- A lot of the tech jobs we do manually aren't challenging or fun, but they're finicky and have to be done just right. They're chores. Things that are important to do, but that are better automated than done manually by us people, right? After all, that's what is supposed to happen in the future. And the future is good, because in the future, we'll all have jetpants. So, onward.
64
+ dep 'name', :argument do
65
+ requires 'other deps'.with('args'), 'whatever they might be'
66
+ met? {
67
+ # is this dependency already met?
68
+ }
69
+ meet {
70
+ # this code gets run if it isn't.
71
+ }
72
+ end
23
73
 
24
- The idea is this: you take a job that you'd rather not do manually, and describe it to babushka using its DSL. The way it works, babushka not only knows how to accomplish each part of the job, it also knows how to check if each part is already done. You're teaching babushka to achieve an end goal with whatever runtime conditions you throw at it, not just to perform the task that would get you there from the very start.
74
+ The important bit here is that when you're writing a dep, you don't have to think about context at all, just the one little task it's doing in isolation. As long as your `requires` are correct, you can leave the overall structure to babushka and just write each little dep separately. When you run `babushka name`, babushka uses the `requires` in each dep to assemble a tree of deps and achieve the end goal you're after.
25
75
 
26
- ## Beginner
76
+ The idea is to keep a clean separation between `met?` and `meet`: the code in `met?` should do nothing except just check whether the dep is met and return a boolean, and `meet` should unconditionally satisfy the dep without doing any checks.
27
77
 
78
+ Right, here's one I prepared earlier. Given you're on a Mac with Xcode installed, this dep knows how to achieve the goal of having llvm available in the PATH.
28
79
 
80
+ dep 'llvm in path', :for => :snow_leopard do
81
+ requires 'xcode tools'
82
+ met? { which 'llvm-gcc-4.2' }
83
+ meet {
84
+ cd('/usr/local/bin') {|path|
85
+ shell "ln -s /Developer/usr/llvm-gcc-4.2/bin/llvm* .", :sudo => !path.writable?
86
+ }
87
+ }
88
+ end
29
89
 
30
- * {file:docs/deps.md Deps Guide} - Best place to start is it will teach you what deps is, and how to write one.
31
- * {file:docs/templates.md Templating Guide} - generating (config) files files based on templates
32
- * {file:docs/packages.md Packages guide} - Babushka can help you install gem, deb, rpm and other packages
33
- * {file:docs/sources.md Sources Guide} - Where to save your deps and how to ditribute them
90
+ All the common logic is handled by babushka, which means that all the code in the dep is specific to the job at hand. The idea is maximising that signal-to-noise ratio: as much of the code in the dep above should be talking about llvm, not about other things that can be inferred elsewhere.
34
91
 
35
- ## Advanced
92
+ Notice that there's no conditional or nested logic within the dep. That's by design: the more declarative things are, the more composable and re-interpretable they are later.
93
+
94
+ If you find you're checking for the presence of some condition in your `meet` block, it probably means you're trying to do too much in a single dep, and you should be splitting it up into smaller ones. Remember, deps are small, self-contained and context-free - the more focused, the better.
95
+
96
+
97
+ ## let's get declarative
98
+
99
+ The basic dep, with just `requires`, `met?` and `meet`, is all you need to describe an end goal. But this generic nature of `met?` and `meet` means just as they're general purpose, they can lack focus. For example, installing an app using the system's package manager has a predictable `met?` block---check whether the package is present and its binaries are in the path.
100
+
101
+ A lot of chores are variations on a theme like this, or just too cumbersome to do repeatedly at a low level. So babushka provides a way to write dep templates, or _meta deps_, that can be reused later. These meta deps allow you to focus the DSL, and make it even more concise.
102
+
103
+ For example, Babushka ships with a meta dep that knows how to install TextMate bundles, given just the URL. All the actual logic, including the code for `met?` and `meet`, is wrapped up in the meta dep.
104
+
105
+ meta :tmbundle, :for => :osx do
106
+ accepts_value_for :source
107
+
108
+ template {
109
+ requires 'TextMate.app'
110
+ def path
111
+ '~/Library/Application Support/TextMate/Bundles' / name
112
+ end
113
+ met? { path.dir? }
114
+ before { path.parent.mkdir }
115
+ meet { git source, :to => path }
116
+ after { shell %Q{osascript -e 'tell app "TextMate" to reload bundles'} }
117
+ }
118
+ end
119
+
120
+ Notice how the contents of the `template` block looks like a normal dep. That's cause it is---the meta dep is a factory, that accepts a value defined by `accepts_value_for` (in this case, `source`) and produces regular deps at runtime under the covers.
121
+
122
+ Given the `tmbundle` meta dep, this dep handles the cucumber bundle:
123
+
124
+ dep 'Cucumber.tmbundle' do
125
+ source 'https://github.com/bmabey/cucumber-tmbundle.git'
126
+ end
127
+
128
+ Notice there's no imperative code there at all---just declarations. That's what the DSL aims for. Instead of saying "do this, then do this, then do this", the code should say "here's a description of the problem, now you work it out." Also notice that there's no TextMate-specific logic. Adding this extra level of abstraction means all that's left are the specifics for _this_ TextMate bundle.
36
129
 
37
- * {file:docs/meta_deps.md Meta Deps Guide}
38
130
 
39
131
  # a runtime example
40
132
 
@@ -45,32 +137,62 @@ If you already have TextMate installed, babushka notices and just installs the b
45
137
  Cucumber.tmbundle {
46
138
  TextMate.app {
47
139
  Found at /Applications/TextMate.app.
48
- } TextMate.app
49
- not already met.
50
- Cloning from https://github.com/bmabey/cucumber-tmbundle.git... done.
51
- Cucumber.tmbundle met.
52
- } Cucumber.tmbundle
140
+ } TextMate.app
141
+ meet {
142
+ Cloning from https://github.com/bmabey/cucumber-tmbundle.git... done.
143
+ }
144
+ } Cucumber.tmbundle
53
145
 
54
146
  But if you don't have TextMate, that's an unmet dependency, so it gets pulled in too.
55
147
 
56
148
  Cucumber.tmbundle {
57
149
  TextMate.app {
58
- not already met.
59
- Downloading http://download-b.macromates.com/TextMate_1.5.9.dmg... done.
60
- Attaching TextMate_1.5.9.dmg... done.
61
- Found TextMate.app in the DMG, copying to /Applications... done.
62
- Detaching TextMate_1.5.9.dmg... done.
150
+ meet {
151
+ Downloading http://download-b.macromates.com/TextMate_1.5.9.dmg... done.
152
+ Attaching TextMate_1.5.9.dmg... done.
153
+ Found TextMate.app in the DMG, copying to /Applications... done.
154
+ Detaching TextMate_1.5.9.dmg... done.
155
+ }
63
156
  Found at /Applications/TextMate.app.
64
- TextMate.app met.
65
- } √ TextMate.app
66
- not already met.
67
- Cloning from https://github.com/bmabey/cucumber-tmbundle.git... done.
68
- Cucumber.tmbundle met.
69
- } √ Cucumber.tmbundle
157
+ } ✓ TextMate.app
158
+ meet {
159
+ Cloning from https://github.com/bmabey/cucumber-tmbundle.git... done.
160
+ }
161
+ } ✓ Cucumber.tmbundle
162
+
163
+
164
+ ## dep sources
165
+
166
+ Babushka only contains the deps that it needs to know how to install itself, and set up a bare minimum of software like package managers, `ruby` and `git`. Everything else is stored separately, in _dep sources_. A dep source is a babushka-managed git repo that contains a bunch of ruby files.
167
+
168
+ The organisation and naming of the files within the source is completely up to you - babushka will recursively load all the .rb files it can find in the source, in alphabetical order.
169
+
170
+ You can define deps and templates in the same source, arranged however you like. You don't have to worry about having templates loaded before deps that are defined against them, because the load is a two-stage process that first reads every file and sets up the templates, and then defines all the deps that were found.
171
+
172
+ The best way manage your own source is to make <tt>~/.babushka/deps</tt> a git repo, and push it to <tt>https://github.com/username/babushka-deps.git</tt>.
173
+
174
+ To run deps from others' sources, you don't need to add the source explicitly. Just prefix the dep name with the correct username:
175
+
176
+ babushka conversation:coffeescript.src
177
+
178
+ The dep source will be cloned into <tt>~/.babushka/sources/conversation</tt>, or updated if it's already there, and then babushka will search for a dep called "coffeescript" within that source. Because of this partitioning, you don't have to worry about naming conflicts with other people; everything is per-source.
179
+
180
+ If you want to rename a source, or add one with a custom URL, you can add sources manually like this:
181
+
182
+ babushka sources -a custom-name git://example.com/custom/url.git
183
+
184
+ That will make the source available in <tt>~/.babushka/sources/custom-name</tt>.
185
+
186
+ There's no configuration file for dep sources; the only state is stored in the contents of <tt>~/.babushka/sources</tt>. Specifically, the source names are the directory names, and the URLs are the locations of the corresponding 'origin' git remotes.
187
+
188
+ Because of this, you can safely add, remove, rename and edit the directories and repositories in there as much as you like---but importantly, *babushka assumes it has free run of <tt>~/.babushka/sources</tt>, and won't hesitate to `git reset --hard`. If you leave uncommitted or unpushed changes in a source, they'll be lost when that source is updated.*
189
+
190
+ If you want to write deps just for yourself that you don't plan to push online, just drop them in <tt>~/.babushka/deps</tt>. If you'd rather keep them elsewhere, like in <tt>~/src</tt> or similar, you can symlink the directory into <tt>~/.babushka/deps</tt>.
70
191
 
192
+ Finally, babushka also loads deps from `./babushka-deps` in the directory from which it was run. This is a good place for project-specific deps, because you can keep them within the project's source control.
71
193
 
72
194
 
73
- ## WARNING
195
+ ## n.b.
74
196
 
75
197
  A dep can run any code. Run deps of unknown origin at your own risk, and when choosing deps and dep sources, use the only real security there is: a network of trust.
76
198
 
@@ -105,6 +227,6 @@ Thanks to my rubyist friends who've helped with brainstorming and testing---the
105
227
 
106
228
  Babushka is licensed under the BSD license, except for the following exception:
107
229
 
108
- lib/support/levenshtein.rb, which is licensed under the MIT license.
230
+ lib/levenshtein/levenshtein.rb, which is licensed under the MIT license.
109
231
 
110
- The BSD license can be found in full in the LICENSE file, and the MIT license at the top of lib/support/levenshtein.rb.
232
+ The BSD license can be found in full in the LICENSE file, and the MIT license at the top of lib/levenshtein/levenshtein.rb.
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ RSpec::Core::RakeTask.new('acceptance') {|t|
14
14
 
15
15
  desc 'Profile the spec suite'
16
16
  RSpec::Core::RakeTask.new('profile') {|t|
17
- t.rspec_opts = %w[--colour --profile]
17
+ t.rspec_opts = ['--colour', '--format Fuubar', '--profile']
18
18
  }
19
19
 
20
20
  desc 'Run code coverage'
data/bin/babushka CHANGED
@@ -8,4 +8,4 @@ Object.send :include, Babushka::DSL
8
8
  Babushka::Base.exit_on_interrupt!
9
9
 
10
10
  # Invoke babushka, returning the correct exit status to the shell.
11
- exit !!Babushka::Base.run
11
+ exit !!Babushka::Base.run
data/deps/apt.rb ADDED
@@ -0,0 +1,44 @@
1
+ dep 'apt source', :uri, :release, :repo do
2
+ uri.default!(Babushka::AptHelper.source_for_system)
3
+ release.default!(Babushka.host.name)
4
+
5
+ def present_in_file? filename
6
+ filename.p.exists? &&
7
+ # e.g. deb http://au.archive.ubuntu.com/ubuntu/ natty main restricted
8
+ filename.p.read[/^deb\s+#{Regexp.escape(uri)}\s+#{release}\b.*\b#{repo}\b/]
9
+ end
10
+
11
+ met? {
12
+ present_in_file?('/etc/apt/sources.list') or
13
+ Dir.glob("/etc/apt/sources.list.d/*").any? {|f| present_in_file?(f) }
14
+ }
15
+ meet {
16
+ '/etc/apt/sources.list.d/babushka.list'.p.append("deb #{uri} #{release} #{repo}\n")
17
+ }
18
+ after {
19
+ Babushka::AptHelper.update_pkg_lists "Updating apt lists to load #{uri}."
20
+ }
21
+ end
22
+
23
+ dep 'ppa', :spec do
24
+ requires 'python-software-properties.bin'
25
+ def spec_name
26
+ log_error("'#{spec}' doesn't look like 'ppa:something'.") unless spec[/^ppa\:\w+/]
27
+ spec.to_s.sub(/^ppa\:/, '')
28
+ end
29
+ def ppa_release_file
30
+ # This may be hardcoded to some extent, but I'm calling YAGNI on it for now.
31
+ "ppa.launchpad.net_#{spec_name.gsub('/', '_')}_ubuntu_dists_#{Babushka.host.name}_Release"
32
+ end
33
+ met? {
34
+ ('/var/lib/apt/lists/' / ppa_release_file).exists?
35
+ }
36
+ meet {
37
+ log_shell "Adding #{spec}", "add-apt-repository '#{spec}'", :spinner => true
38
+ log_shell "Updating apt lists to load #{spec}.", "apt-get update"
39
+ }
40
+ end
41
+
42
+ dep 'python-software-properties.bin' do
43
+ provides 'add-apt-repository'
44
+ end
data/deps/babushka.rb CHANGED
@@ -2,68 +2,80 @@ meta :babushka do
2
2
  def repo
3
3
  Babushka::GitRepo.new(path)
4
4
  end
5
+
6
+ def qualified_ref
7
+ # Prepend "origin/" we're installing from scratch, or if the result is a
8
+ # valid remote branch.
9
+ if repo.exists? && repo.all_branches.include?("origin/#{ref}")
10
+ "origin/#{ref}"
11
+ else
12
+ ref
13
+ end
14
+ end
15
+
16
+ def resolved_ref
17
+ repo.resolve(qualified_ref)
18
+ end
5
19
  end
6
20
 
7
- dep 'babushka', :from, :path, :branch do
8
- requires 'up to date.babushka'.with(from, path, branch)
21
+ dep 'babushka', :from, :path, :version, :branch do
22
+ ref = if branch.set?
23
+ deprecated! '2012-12-20', :method_name => "the :branch parameter to 'babushka'", :instead => ':version'
24
+ branch
25
+ else
26
+ version.default!('master')
27
+ end
28
+ requires 'up to date.babushka'.with(from, path, ref)
9
29
  requires 'in path.babushka'.with(from, path)
10
30
  path.ask("Where would you like babushka installed").default('/usr/local/babushka')
11
31
  path.default!(Babushka::Path.path) if Babushka::Path.run_from_path?
12
- branch.default!('master')
13
32
  end
14
33
 
15
- dep 'up to date.babushka', :from, :path, :branch do
34
+ dep 'up to date.babushka', :from, :path, :ref do
16
35
  requires 'repo clean.babushka'.with(from, path)
17
- requires 'update would fast forward.babushka'.with(from, path, branch)
36
+ requires 'resolvable ref.babushka'.with(from, path, ref)
37
+
18
38
  met? {
19
- (!repo.behind?).tap {|result|
39
+ (repo.current_head == resolved_ref).tap {|result|
20
40
  if result
21
- log_ok "babushka is up to date at revision #{repo.current_head}."
41
+ log_ok "babushka is up to date at #{repo.current_head}."
22
42
  else
23
- log "babushka can be updated: #{repo.current_head}..#{repo.repo_shell("git rev-parse --short origin/#{branch}")}"
43
+ log "babushka can be updated: #{repo.current_head}..#{resolved_ref}"
24
44
  end
25
45
  }
26
46
  }
27
47
  meet {
28
- log "#{repo.repo_shell("git diff --stat #{repo.current_head}..origin/#{branch}")}"
29
- repo.reset_hard! "origin/#{branch}"
48
+ log "#{repo.repo_shell("git diff --stat #{repo.current_head}..#{resolved_ref}")}"
49
+ repo.detach!(resolved_ref)
30
50
  }
31
51
  end
32
52
 
33
- dep 'update would fast forward.babushka', :from, :path, :branch do
34
- requires 'on correct branch.babushka'.with(from, path, branch)
53
+ dep 'repo clean.babushka', :from, :path do
54
+ requires 'installed.babushka'.with(from, path)
35
55
  met? {
36
- if !repo.repo_shell('git fetch origin')
37
- unmeetable "Couldn't pull the latest code - check your internet connection."
38
- else
39
- if !repo.remote_branch_exists?
40
- unmeetable "The current branch, #{repo.current_branch}, isn't pushed to origin/#{repo.current_branch}."
41
- elsif repo.ahead?
42
- unmeetable "There are unpushed commits in #{repo.current_branch}."
43
- else
44
- true
45
- end
46
- end
56
+ repo.clean? or unmeetable!("There are local changes in #{repo.path}.")
47
57
  }
48
58
  end
49
59
 
50
- dep 'on correct branch.babushka', :from, :path, :branch do
51
- requires 'branch exists.babushka'.with(from, path, branch)
52
- requires_when_unmet 'repo clean.babushka'.with(from, path)
53
- met? { repo.current_branch == branch.to_s }
54
- meet { repo.checkout! branch }
55
- end
56
-
57
- dep 'branch exists.babushka', :from, :path, :branch do
58
- requires 'installed.babushka'.with(from, path)
59
- met? { repo.branches.include? branch.to_s }
60
- meet { repo.track! "origin/#{branch}" }
61
- end
62
-
63
- dep 'repo clean.babushka', :from, :path do
64
- requires 'installed.babushka'.with(from, path)
60
+ dep 'resolvable ref.babushka', :from, :path, :ref do
65
61
  met? {
66
- repo.clean? or unmeetable("There are local changes in #{repo.path}.")
62
+ if !@fetched && qualified_ref['origin/']
63
+ false # Always fetch before resolving a remote ref.
64
+ else
65
+ resolved_ref.tap {|result|
66
+ if result
67
+ log_ok "#{ref} resolves to #{result}."
68
+ else
69
+ log "#{ref} doesn't resolve to a ref."
70
+ end
71
+ }
72
+ end
73
+ }
74
+ meet {
75
+ log_block "Fetching #{from}", :failure => "failed, check your internet connection." do
76
+ @fetched = true
77
+ repo.repo_shell?('git fetch origin')
78
+ end
67
79
  }
68
80
  end
69
81
 
@@ -74,12 +86,12 @@ dep 'in path.babushka', :from, :path do
74
86
  end
75
87
  setup {
76
88
  unless ENV['PATH'].split(':').map {|p| p.chomp('/') }.include?(bin_path)
77
- unmeetable "The binary path alongside babushka, #{bin_path}, isn't in your $PATH."
89
+ unmeetable! "The binary path alongside babushka, #{bin_path}, isn't in your $PATH."
78
90
  end
79
91
  }
80
92
  met? { which 'babushka' }
81
93
  prepare {
82
- unmeetable "The current user, #{shell('whoami')}, can't write to #{bin_path} (to symlink babushka into the path)." unless bin_path.hypothetically_writable?
94
+ unmeetable! "The current user, #{shell('whoami')}, can't write to #{bin_path} (to symlink babushka into the path)." unless bin_path.hypothetically_writable?
83
95
  }
84
96
  meet {
85
97
  bin_path.mkdir
@@ -92,7 +104,7 @@ dep 'installed.babushka', :from, :path do
92
104
 
93
105
  requires 'ruby', 'git'
94
106
  setup {
95
- unmeetable "The current user, #{shell('whoami')}, can't write to #{repo.path}." unless repo.path.hypothetically_writable?
107
+ unmeetable! "The current user, #{shell('whoami')}, can't write to #{repo.path}." unless repo.path.hypothetically_writable?
96
108
  }
97
109
  met? { repo.exists? }
98
110
  meet {