vim-flavor 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.rspec +1 -0
  2. data/.travis.yml +4 -0
  3. data/README.md +3 -174
  4. data/Rakefile +10 -0
  5. data/features/.nav +12 -0
  6. data/features/README.md +17 -0
  7. data/features/caching.feature +50 -0
  8. data/features/command_line/README.md +9 -0
  9. data/features/command_line/progress_messages.feature +44 -0
  10. data/features/flavorfile/README.md +9 -0
  11. data/features/flavorfile/comments.feature +24 -0
  12. data/features/flavorfile/repository_name.feature +53 -0
  13. data/features/flavorfile/version_constraint.feature +52 -0
  14. data/features/install_vim_flavor.md +42 -0
  15. data/features/philosophy.md +90 -0
  16. data/features/resolve_dependencies.feature +16 -0
  17. data/features/step_definitions/bootstrap_script_steps.rb +7 -0
  18. data/features/step_definitions/cli_steps.rb +34 -0
  19. data/features/step_definitions/directory_steps.rb +23 -0
  20. data/features/step_definitions/flavor_steps.rb +37 -0
  21. data/features/step_definitions/flavorfile_steps.rb +12 -0
  22. data/features/step_definitions/lockfile_steps.rb +13 -0
  23. data/features/support/env.rb +49 -0
  24. data/features/typical_usage/README.md +63 -0
  25. data/features/typical_usage/deploy_to_arbitrary_place.feature +24 -0
  26. data/features/typical_usage/install_vim_plugins.feature +26 -0
  27. data/features/typical_usage/uninstall_vim_plugins.feature +31 -0
  28. data/features/typical_usage/upgrade_vim_plugins.feature +27 -0
  29. data/features/uninstall_vim_flavor.md +16 -0
  30. data/features/version_lock.feature +26 -0
  31. data/lib/vim-flavor.rb +2 -12
  32. data/lib/vim-flavor/cli.rb +16 -12
  33. data/lib/vim-flavor/enumerableextension.rb +48 -0
  34. data/lib/vim-flavor/facade.rb +65 -102
  35. data/lib/vim-flavor/flavor.rb +70 -63
  36. data/lib/vim-flavor/flavorfile.rb +15 -47
  37. data/lib/vim-flavor/lockfile.rb +27 -44
  38. data/lib/vim-flavor/lockfileparser.rb +65 -0
  39. data/lib/vim-flavor/stringextension.rb +25 -1
  40. data/lib/vim-flavor/version.rb +1 -1
  41. data/lib/vim-flavor/versionconstraint.rb +12 -11
  42. data/spec/enumerableextension_spec.rb +100 -0
  43. data/spec/facade_spec.rb +49 -540
  44. data/spec/flavor_spec.rb +50 -250
  45. data/spec/flavorfile_spec.rb +34 -110
  46. data/spec/lockfile_spec.rb +79 -89
  47. data/spec/spec_helper.rb +0 -65
  48. data/spec/stringextension_spec.rb +10 -6
  49. data/spec/versionconstraint_spec.rb +37 -119
  50. data/vim-flavor.gemspec +3 -1
  51. metadata +135 -46
  52. data/spec/cli_spec.rb +0 -15
@@ -0,0 +1,42 @@
1
+ ## Required softwares
2
+
3
+ * [Git](http://git-scm.com/) 1.7.9 or later
4
+ * [Ruby](http://www.ruby-lang.org/) 1.9.2 or later
5
+ * Recommendation: Use [RVM](http://beginrescueend.com/) or other tools
6
+ for ease of installation across different envinronments.
7
+ * [Vim](http://www.vim.org/) 7.3 or later
8
+ * Note that Vim should be compiled as normal, big or huge version
9
+ to use most of plugins.
10
+
11
+
12
+
13
+
14
+ ## Supported platforms
15
+
16
+ * Unix-like environments such as Linux, Mac OS X, etc.
17
+ * Though Microsoft Windows is not directly supported,
18
+ it is possible to manage Vim plugins via Cygwin or other environments.
19
+
20
+
21
+
22
+
23
+ ## Installation steps
24
+
25
+ gem install vim-flavor
26
+
27
+ cd $YOUR_REPOSITORY_FOR_DOTFILES
28
+
29
+ # Add the following line into the first line of your vimrc:
30
+ #
31
+ # runtime flavors/bootstrap.vim
32
+ vim vimrc
33
+
34
+ touch VimFlavor VimFlavor.lock
35
+
36
+ git add VimFlavor VimFlavor.lock vimrc
37
+ git commit -m 'Use vim-flavor to manage my favorite Vim plugins'
38
+
39
+
40
+
41
+
42
+ <!-- vim: set expandtab shiftwidth=4 softtabstop=4 textwidth=78 : -->
@@ -0,0 +1,90 @@
1
+ ## Installable plugins
2
+
3
+ Not all Vim plugins can be installed with vim-flavor.
4
+ vim-flavor can install plugins which meet the following conditions:
5
+
6
+ * Plugins must have dedicated Git repositories.
7
+ vim-flavor does not support other version control systems.
8
+ This is an intentional design. Because:
9
+ * [vim-scripts.org](http://vim-scripts.org/) provides
10
+ [comprehensive Git mirrors](https://github.com/vim-scripts) for
11
+ [plugins uploaded to www.vim.org](http://www.vim.org/scripts/index.php).
12
+ * Experimental plugins which are not uploaded to www.vim.org
13
+ are usually found in [GitHub](https://github.com/).
14
+ * Plugins must follow [the versioning pocilies of
15
+ RubyGems](http://docs.rubygems.org/read/chapter/7#page26) and have "version"
16
+ tags in their repositories. For example, if there is the version 1.2.3 of
17
+ a plugin, its repository must have the tag `1.2.3`, and the files of the
18
+ version 1.2.3 can be checked out via the tag `1.2.3`. In other words,
19
+ plugins which do not have proper tags are not installable.
20
+ This is an intentional design. Because:
21
+ * It's not possible to determine whether two versions are compatible or not
22
+ without "version" tags. Compatibility is a big problem to resolve
23
+ dependencies of plugins. For example, if plugin A requires plugin X 1.2.3
24
+ or later while plugin B requires plugin X 2.0 or later, it's not possible
25
+ to use A and B at the same time. Such problems should be detected before
26
+ installing plugins.
27
+ * Git mirrors by vim-scripts.org are tagged with version numbers.
28
+ * Some Git repositories might not have "version" tags.
29
+ Such plugins are not ready to use for everyone.
30
+ So that it should not be installable.
31
+ * Plugins must have proper directory structures.
32
+ For example, directories such as `autoload`, `syntax` etc should exist in
33
+ the roots of plugins.
34
+ This is an intentional design. Because:
35
+ * Git mirrors by vim-scripts.org have proper directory structures even if
36
+ the original plugins are uploaded to www.vim.org without proper directory
37
+ structures. (A good example is
38
+ [a.vim](http://www.vim.org/scripts/script.php?script_id=31) and
39
+ [its mirror](https://github.com/vim-scripts/a.vim).)
40
+ * Other Git repositories might not have proper directory structures.
41
+ Such plugins are not ready to use for everyone.
42
+ So that it should not be installable.
43
+
44
+
45
+
46
+
47
+ ## Why make another management tool?
48
+
49
+ I know that there are several implementations for the same purpose and many
50
+ users love them, but all of them do not meet my taste. That's why I wrote
51
+ vim-flavor. The philosophy on vim-flavor is as follows:
52
+
53
+ Whole configuration including *versions of plugins* should be under a version
54
+ control system. All of existing implementations do not manage versions of
55
+ plugins. This means that *it's not possible to use the same configuration
56
+ across multiple environments* (the only one exception is using
57
+ [pathogen](https://github.com/tpope/vim-pathogen) with Git submodules,
58
+ but you'll find it's painful to manually manage many plugins).
59
+
60
+ There should be a standard way to describe proper dependencies of plugins to
61
+ install dependencies without explicit declarations. Most of existing
62
+ implementations do not resolve dependencies automatically (the only one
63
+ exception is
64
+ [vim-addon-manager](https://github.com/MarcWeber/vim-addon-manager), but it
65
+ doesn't take care about required versions). The configuration file formats of
66
+ vim-flavor are also used to describe dependencies of plugins with required
67
+ versions. This means that vim-flavor installs plugins and their dependencies
68
+ automatically (unfortunately this feature is not implemented yet, but it'll be
69
+ available soon).
70
+
71
+ Any software should have enough and reproducible test cases.
72
+ But existing implementations such as
73
+ [vundle](https://github.com/gmarik/vundle) and
74
+ [neobundle](https://github.com/Shougo/neobundle.vim) are not developed so.
75
+ It's horrible for me.
76
+
77
+ Installation steps should be small, be reproducible, and not affect existing
78
+ environment as less as possible. Most of existing implementations require to
79
+ manually tweak `~/.vim` etc. It's painful to set up such stuffs manually
80
+ because a vimfiles path is varied on each platform.
81
+
82
+ Finally, a tool and files deployed by the tool should be uninstalled easily.
83
+ [Vimana](https://github.com/c9s/Vimana) does not meet this because it directly
84
+ puts files into `~/.vim/colors` etc and it doesn't provide `uninstall`
85
+ command.
86
+
87
+
88
+
89
+
90
+ <!-- vim: set expandtab shiftwidth=4 softtabstop=4 textwidth=78 : -->
@@ -0,0 +1,16 @@
1
+ Feature: Resolve dependencies of Vim plugins
2
+ In order to hide details of dependencies,
3
+ as a lazy Vim user,
4
+ I want to resolve and install dependencies of Vim plugins automatically.
5
+
6
+ # TODO
7
+ Scenario: Resolve 2-level dependencies
8
+
9
+ # TODO
10
+ Scenario: Resolve 3-level dependencies
11
+
12
+ # TODO
13
+ Scenario: Resolve dependencies of a plugin required by two or more plugins
14
+
15
+ # TODO
16
+ Scenario: Resolve dependencies of a plugin required by plugins and user
@@ -0,0 +1,7 @@
1
+ Then /^I get a bootstrap script in '(.+)'$/ do |virtual_path|
2
+ File.should exist(
3
+ expand(virtual_path).
4
+ to_flavors_path.
5
+ to_bootstrap_path
6
+ )
7
+ end
@@ -0,0 +1,34 @@
1
+ When /^I run `vim-flavor(.*)`(?: again)?(?:,? (but))?$/ do |args, mode|
2
+ begin
3
+ original_home = ENV['HOME']
4
+ ENV['HOME'] = expand('$home')
5
+ Dir.chdir(expand('$tmp')) do
6
+ original_stdout = $stdout
7
+ begin
8
+ $stdout = @output = StringIO.new()
9
+ Vim::Flavor::CLI.start(args.strip().split(/\s+/).map {|a| expand(a)})
10
+ rescue RuntimeError => e
11
+ @last_error = e
12
+ ensure
13
+ $stdout = original_stdout
14
+ end
15
+ if mode == 'but'
16
+ raise RuntimeError, 'Command succeeded unexpectedly' if not @last_error
17
+ else
18
+ raise @last_error if @last_error
19
+ end
20
+ end
21
+ ensure
22
+ ENV['HOME'] = original_home
23
+ end
24
+ end
25
+
26
+ Then /^it fails with messages like$/ do |pattern|
27
+ @last_error.should_not be_nil
28
+ @last_error.message.should match Regexp.new(pattern.strip().gsub(/\s+/, '\s+'))
29
+ end
30
+
31
+ Then 'it outputs progress like' do |text|
32
+ # For some reason, Cucumber drops the last newline from every docstring...
33
+ @output.string.should include expand(text + "\n")
34
+ end
@@ -0,0 +1,23 @@
1
+ require 'tmpdir'
2
+
3
+ Given /^a temporary directory called '(.+)'$/ do |name|
4
+ path = Dir.mktmpdir
5
+ at_exit do
6
+ delete_path path
7
+ end
8
+ variable_table[name] = path
9
+ end
10
+
11
+ Given /^a home directory called '(.+)' in '(.+)'$/ do |name, virtual_path|
12
+ actual_path = expand(virtual_path)
13
+ Dir.mkdir actual_path, 0700
14
+ variable_table[name] = actual_path
15
+ end
16
+
17
+ Given /^I don't have a directory called '(.+)'$/ do |virtual_path|
18
+ Dir.should_not exist(expand(virtual_path))
19
+ end
20
+
21
+ Given /^I delete '(.+)'$/ do |virtual_path|
22
+ delete_path expand(virtual_path)
23
+ end
@@ -0,0 +1,37 @@
1
+ Given /^a repository '(.+)' with versions '(.+)'$/ do |basename, versions|
2
+ repository_path = make_repo_path(basename)
3
+ doc_name = basename.split('/').last.sub(/^vim-/, '')
4
+ variable_table["#{basename}_uri"] = make_repo_uri(basename)
5
+ system <<-"END"
6
+ {
7
+ mkdir -p '#{repository_path}' &&
8
+ cd '#{repository_path}' &&
9
+ git init &&
10
+ mkdir doc &&
11
+ for v in #{versions}
12
+ do
13
+ echo "*#{doc_name}* $v" >'doc/#{doc_name}.txt'
14
+ git add doc
15
+ git commit -m "Version $v"
16
+ git tag -m "Version $v" "$v"
17
+ done
18
+ } >/dev/null
19
+ END
20
+ end
21
+
22
+ Given /^I disable network to the original repository of '(.+)'$/ do |basename|
23
+ delete_path make_repo_path(basename)
24
+ end
25
+
26
+ Then /^I get flavor '(.+)' with '(.+)' in '(.+)'$/ do |v_repo_name, version, virtual_path|
27
+ flavor_path = make_flavor_path(expand(virtual_path), expand(v_repo_name))
28
+ basename = expand(v_repo_name).split('/').last.sub(/^vim-/, '')
29
+ File.open("#{flavor_path}/doc/#{basename}.txt", 'r').read().should ==
30
+ "*#{basename}* #{version}\n"
31
+ File.should exist("#{flavor_path}/doc/tags")
32
+ end
33
+
34
+ Then /^I don't have flavor '(.+)' in '(.+)'$/ do |v_repo_name, virtual_path|
35
+ flavor_path = make_flavor_path(expand(virtual_path), expand(v_repo_name))
36
+ Dir.should_not exist(flavor_path)
37
+ end
@@ -0,0 +1,12 @@
1
+ Given 'flavorfile' do |content|
2
+ create_file expand('$tmp').to_flavorfile_path, expand(content)
3
+ end
4
+
5
+ When 'I edit flavorfile as' do |content|
6
+ steps %Q{
7
+ Given flavorfile
8
+ """
9
+ #{content}
10
+ """
11
+ }
12
+ end
@@ -0,0 +1,13 @@
1
+ Given 'lockfile' do |content|
2
+ create_file expand('$tmp').to_lockfile_path, expand(content)
3
+ end
4
+
5
+ Given /^I delete lockfile$/ do
6
+ delete_path expand('$tmp').to_lockfile_path
7
+ end
8
+
9
+ Then 'I get lockfile' do |content|
10
+ # For some reason, Cucumber drops the last newline from every docstring...
11
+ File.open(expand('$tmp').to_lockfile_path, 'r').read().should ==
12
+ (content == '' ? '' : expand(content) + "\n")
13
+ end
@@ -0,0 +1,49 @@
1
+ require 'fileutils'
2
+ require 'vim-flavor'
3
+
4
+ class FakeUserEnvironment
5
+ def initialize()
6
+ env = self
7
+ Vim::Flavor::Flavor.instance_eval do
8
+ @github_repo_uri = lambda {|user, repo|
9
+ "file://#{env.expand('$tmp')}/repos/#{user}/#{repo}"
10
+ }
11
+ end
12
+ end
13
+
14
+ def create_file path, content
15
+ File.open(path, 'w') do |f|
16
+ f.write(content)
17
+ end
18
+ end
19
+
20
+ def delete_path path
21
+ FileUtils.remove_entry_secure(path)
22
+ end
23
+
24
+ def expand(virtual_path)
25
+ virtual_path.gsub(/\$([a-z_]+)/) {
26
+ variable_table[$1]
27
+ }
28
+ end
29
+
30
+ def make_flavor_path(vimfiles_path, repo_name)
31
+ "#{vimfiles_path.to_flavors_path}/#{repo_name.zap}"
32
+ end
33
+
34
+ def make_repo_path(basename)
35
+ "#{expand("$tmp")}/repos/#{basename}"
36
+ end
37
+
38
+ def make_repo_uri(basename)
39
+ "file://#{make_repo_path(basename)}"
40
+ end
41
+
42
+ def variable_table
43
+ @variable_table ||= Hash.new
44
+ end
45
+ end
46
+
47
+ World do
48
+ FakeUserEnvironment.new
49
+ end
@@ -0,0 +1,63 @@
1
+ ## Abstract
2
+
3
+ As a skilled Vim user, it is an exciting time to start using a new plugin,
4
+ but installation is not so, because there are several steps to do like the
5
+ following:
6
+
7
+ 1. Get a package of the plugin.
8
+ 2. Copy source tree in the package into `~/.vim` etc.
9
+ 3. Generate the help tags file for the plugin.
10
+
11
+ It is also exciting to upgrade favorite Vim plugins to the latest version,
12
+ but I don't want to repeat the steps for each plugin. It's boring.
13
+
14
+ Some plugins depend on other plugins, so that I have to install also
15
+ dependencies, but it is easy to forget about dependencies.
16
+ It's sad to see error messages like "E117: Unknown function: foo#bar".
17
+
18
+ It would be better to automate these routine works with a declarative way,
19
+ and `vim-flavor` does it.
20
+
21
+
22
+
23
+
24
+ ## Typical workflow
25
+
26
+ cd $YOUR_REPOSITORY_FOR_DOTFILES
27
+
28
+ # Add, delete or change declarations which versions of Vim plugins to use.
29
+ vim VimFlavor
30
+
31
+ # Install Vim plugins according to VimFlavor.
32
+ vim-flavor install
33
+
34
+ # Record changes to the declarations and locked status.
35
+ git add VimFlavor VimFlavor.lock
36
+ git commit -m '...'
37
+
38
+
39
+
40
+
41
+ ## Flavorfile (`VimFlavor`)
42
+
43
+ `vim-flavor` reads a file `VimFlavor` in the current working directory.
44
+ The file is called a flavorfile. A flavorfile contains zero or more
45
+ declarations about Vim plugins and which versions of Vim plugins to use.
46
+
47
+ See also [Flavorfile details](../flavorfile).
48
+
49
+
50
+
51
+
52
+ ## Lockfile (`VimFlavor.lock`)
53
+
54
+ `vim-flavor` creates a file `VimFlavor.lock` in the current working directory.
55
+ The file is called a lockfile. A lockfile contains details about installed
56
+ Vim plugins to use the same configuration on every machine.
57
+
58
+ You don't have to care about the content of a lockfile.
59
+
60
+
61
+
62
+
63
+ <!-- vim: set expandtab shiftwidth=4 softtabstop=4 textwidth=78 : -->
@@ -0,0 +1,24 @@
1
+ @typical_usage
2
+ Feature: Deploy Vim plugins to a non-standard directory
3
+ In order to provide flexibility,
4
+ as a lazy Vim user,
5
+ I want to deploy Vim plugins to arbitrary place.
6
+
7
+ Background:
8
+ Given a temporary directory called 'tmp'
9
+ And a home directory called 'home' in '$tmp/home'
10
+ And a repository 'foo' with versions '1.0.0 1.0.1 1.0.2'
11
+
12
+ Scenario: Install to specified vimfiles path which does not exist
13
+ Given flavorfile
14
+ """ruby
15
+ flavor '$foo_uri'
16
+ """
17
+ And I don't have a directory called '$tmp/my-vimfiles'
18
+ When I run `vim-flavor install --vimfiles-path=$tmp/my-vimfiles`
19
+ Then I get lockfile
20
+ """
21
+ $foo_uri (1.0.2)
22
+ """
23
+ And I get a bootstrap script in '$tmp/my-vimfiles'
24
+ And I get flavor '$foo_uri' with '1.0.2' in '$tmp/my-vimfiles'
@@ -0,0 +1,26 @@
1
+ @typical_usage
2
+ Feature: Install Vim plugins
3
+ In order to automate boring steps,
4
+ as a lazy Vim user,
5
+ I want to use a declarative way to start using new Vim plugins.
6
+
7
+ Background:
8
+ Given a temporary directory called 'tmp'
9
+ And a home directory called 'home' in '$tmp/home'
10
+ And a repository 'foo' with versions '1.0.0 1.0.1 1.0.2'
11
+
12
+ Scenario: Install from scratch
13
+ Given flavorfile
14
+ """ruby
15
+ """
16
+ When I edit flavorfile as
17
+ """ruby
18
+ flavor '$foo_uri'
19
+ """
20
+ And I run `vim-flavor install`
21
+ Then I get lockfile
22
+ """
23
+ $foo_uri (1.0.2)
24
+ """
25
+ And I get a bootstrap script in '$home/.vim'
26
+ And I get flavor '$foo_uri' with '1.0.2' in '$home/.vim'