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.
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/README.md +3 -174
- data/Rakefile +10 -0
- data/features/.nav +12 -0
- data/features/README.md +17 -0
- data/features/caching.feature +50 -0
- data/features/command_line/README.md +9 -0
- data/features/command_line/progress_messages.feature +44 -0
- data/features/flavorfile/README.md +9 -0
- data/features/flavorfile/comments.feature +24 -0
- data/features/flavorfile/repository_name.feature +53 -0
- data/features/flavorfile/version_constraint.feature +52 -0
- data/features/install_vim_flavor.md +42 -0
- data/features/philosophy.md +90 -0
- data/features/resolve_dependencies.feature +16 -0
- data/features/step_definitions/bootstrap_script_steps.rb +7 -0
- data/features/step_definitions/cli_steps.rb +34 -0
- data/features/step_definitions/directory_steps.rb +23 -0
- data/features/step_definitions/flavor_steps.rb +37 -0
- data/features/step_definitions/flavorfile_steps.rb +12 -0
- data/features/step_definitions/lockfile_steps.rb +13 -0
- data/features/support/env.rb +49 -0
- data/features/typical_usage/README.md +63 -0
- data/features/typical_usage/deploy_to_arbitrary_place.feature +24 -0
- data/features/typical_usage/install_vim_plugins.feature +26 -0
- data/features/typical_usage/uninstall_vim_plugins.feature +31 -0
- data/features/typical_usage/upgrade_vim_plugins.feature +27 -0
- data/features/uninstall_vim_flavor.md +16 -0
- data/features/version_lock.feature +26 -0
- data/lib/vim-flavor.rb +2 -12
- data/lib/vim-flavor/cli.rb +16 -12
- data/lib/vim-flavor/enumerableextension.rb +48 -0
- data/lib/vim-flavor/facade.rb +65 -102
- data/lib/vim-flavor/flavor.rb +70 -63
- data/lib/vim-flavor/flavorfile.rb +15 -47
- data/lib/vim-flavor/lockfile.rb +27 -44
- data/lib/vim-flavor/lockfileparser.rb +65 -0
- data/lib/vim-flavor/stringextension.rb +25 -1
- data/lib/vim-flavor/version.rb +1 -1
- data/lib/vim-flavor/versionconstraint.rb +12 -11
- data/spec/enumerableextension_spec.rb +100 -0
- data/spec/facade_spec.rb +49 -540
- data/spec/flavor_spec.rb +50 -250
- data/spec/flavorfile_spec.rb +34 -110
- data/spec/lockfile_spec.rb +79 -89
- data/spec/spec_helper.rb +0 -65
- data/spec/stringextension_spec.rb +10 -6
- data/spec/versionconstraint_spec.rb +37 -119
- data/vim-flavor.gemspec +3 -1
- metadata +135 -46
- 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,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,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'
|