caligari 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7d28cdbceef43dd381e3754c8edf16801550b4c8
4
+ data.tar.gz: 1345087a5222d642cdade41b78c21be222891030
5
+ SHA512:
6
+ metadata.gz: d3f798fd7ead95117d0f6f1dfd5cbf9aec789bfa6c7ba83aaefffd912884f8550902dba6371815bfc0fa5f299ca1c584ce948ed3417f92cbfacdfba5fe0f17e2
7
+ data.tar.gz: 8afe108d18661153e28598f96edd97dcc478b6c5fceff2eacf4a28ccc9541a3cac92a851b7557759e291b3cb3c751d3c9d586fbcdde86c76aeddcaff8a6537c9
@@ -0,0 +1,8 @@
1
+ .yardoc/
2
+ doc/
3
+ Gemfile.lock
4
+ pkg/
5
+
6
+ man/**/*.html
7
+ man/**/*.css
8
+ man/**/*.?
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Copyright (c) 2016 Robin Owen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
+ software and associated documentation files (the "Software"), to deal in the Software
5
+ without restriction, including without limitation the rights to use, copy, modify, merge,
6
+ publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
+ to whom the Software is furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or
10
+ substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
+ DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,99 @@
1
+ # Caligari
2
+ _"...I must become Caligari!"_
3
+
4
+ ## Description
5
+ `caligari` installs configuration files by symbolically linking all of the
6
+ files from the given paths directly to the current user's home directory with
7
+ the same relative file structure, creating any requisite directories as-needed.
8
+
9
+ ## Usage
10
+ `caligari` allows you to exclude files matching a given `fnmatch` pattern with
11
+ the **--exclude/-x** flag. For example, the following may be used to exclude
12
+ all backup files and `vim` swap files:
13
+
14
+ ```sh
15
+ caligari --exclude '**/*~' '**/*.swp'
16
+ ```
17
+
18
+ By default, `caligari` will simply skip over any files which already exist in
19
+ the current user's home directory; however, you can force `caligari` to
20
+ overwrite existing files with the **--force/-f** flag:
21
+
22
+ ```sh
23
+ caligari --force
24
+ ```
25
+
26
+ `caligari` is normally silent except for warnings and errors; if you want more
27
+ explicit output about the operations `caligari` performs, simply use the
28
+ **--verbose/-V** flag. This flag will report all of the file system operations
29
+ `caligari` performs, each with an appropriate label:
30
+
31
+ * **ln** for created symbolic links
32
+ * **path** for created directory paths
33
+ * **rm** for unlinked files
34
+ * **err** for any errors encountered
35
+
36
+ `caligari` reports operations in this way so that they may be filtered in
37
+ whichever way the user desires. For example, you could print a list of the
38
+ files removed by a forceful `caligari` run like so:
39
+
40
+ ```sh
41
+ caligari --force --verbose | awk '/^rm:/ { print $2 }'
42
+ ```
43
+
44
+ You may also simulate the actions `caligari` would normally take upon the file
45
+ system by passing the **--simulate/-s** flag. This implies the **--verbose**
46
+ flag, allowing you to inspect which actions `caligari` would take if run:
47
+
48
+ ```
49
+ $ caligari --simulate --force
50
+ rm: /home/user/do-not-remove
51
+ ln: /home/user/do-not-remove
52
+ ```
53
+
54
+ ## Configuration
55
+ `caligari` may be configured by editing the system-wide configuration file
56
+ (defined by default as */etc/xdg/caligari.yml*) or the per-user configuration
57
+ file (defined by default as *~/.config/caligari.yml*). These configuration
58
+ files are simple YAML files which define the default exclusion patterns used
59
+ by `caligari`.
60
+
61
+ Example *~/.config/caligari.yml* to automatically exclude the *.git* directory
62
+ and all *README.md* files:
63
+
64
+ ```yaml
65
+ ---
66
+ :exclude:
67
+ - "**/.git"
68
+ - "**/README.md"
69
+ ```
70
+
71
+ ## Installation
72
+ ```sh
73
+ gem install caligari
74
+ ```
75
+
76
+ ## Development
77
+ Just clone the [git repository][repo] and run `bundle install` to install the
78
+ development and runtime dependencies:
79
+
80
+ ```sh
81
+ git clone https://github.com/vthrenody/caligari.git
82
+ cd caligari
83
+ bundle install
84
+ ```
85
+
86
+ You can run Caligari locally for development purposes by running it directly
87
+ from the repository like so:
88
+
89
+ ```sh
90
+ bin/caligari
91
+ ```
92
+
93
+ To install a local copy of Caligari, simply run `rake install`.
94
+
95
+ ## License
96
+ Caligari is made available under the terms of the MIT Expat license. See the
97
+ included LICENSE file for more information.
98
+
99
+ [repo]: https://www.github.com/vthrenody/caligari
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'md2man/rakefile'
3
+ require 'yard'
4
+
5
+ YARD::Rake::YardocTask.new do |yard|
6
+ yard.options = [
7
+ '--title', 'Caligari Documentation',
8
+ '--readme', 'README.md',
9
+ '--files', 'LICENSE',
10
+ '--markup', 'markdown',
11
+ '--private',
12
+ ]
13
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'trollop'
4
+
5
+ if $0.start_with?('/')
6
+ require 'caligari'
7
+ else
8
+ warn 'warn: running local caligari'
9
+ require_relative '../lib/caligari'
10
+ end
11
+
12
+ def die(message)
13
+ $stderr.puts "err: #{message}"
14
+ exit 1
15
+ end
16
+
17
+ options = Trollop.options do
18
+ version Caligari::COPYRIGHT
19
+ banner <<-EOS
20
+ #{Caligari::COPYRIGHT}
21
+
22
+ caligari is a simple configuration file installer. By default, this utility
23
+ will generate symbolic links in the current user's home directory for all of
24
+ the files present in the target path(s).
25
+
26
+ Usage:
27
+ caligari [OPTION]... [PATH]...
28
+
29
+ Options:
30
+ EOS
31
+
32
+ opt :exclude, 'Exclude the given files or directories', short: 'x',
33
+ type: :strings
34
+ opt :force, 'Force installation over existing files'
35
+ opt :simulate, 'Simulate installation (implies --verbose)'
36
+ opt :traverse, 'Traverse into the given paths while processing'
37
+ opt :verbose, 'Print verbose installation information', short: 'V'
38
+ end
39
+
40
+ # Make sure we have at least an empty array for exclusions.
41
+ options[:exclude] ||= []
42
+
43
+ # Make sure `ARGV` is populated with the current working directory if not
44
+ # otherwise specified. Note that we use "." here instead of, for example,
45
+ # `Dir.pwd` -- Caligari does not like absolute paths.
46
+ ARGV.push('.') if ARGV.empty?
47
+
48
+ begin
49
+ Caligari::Application.new(*ARGV, options).run
50
+ rescue Psych::SyntaxError => ex
51
+ die("configuration is malformed:\n\t#{ex.message}")
52
+ rescue Exception => ex
53
+ die(ex.message)
54
+ end
@@ -0,0 +1,31 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'caligari/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'caligari'
8
+ gem.version = Caligari::VERSION
9
+ gem.authors = ['Robin Owen']
10
+ gem.email = ['vthrenody@gmail.com']
11
+ gem.homepage = 'https://github.com/vthrenody/caligari'
12
+ gem.platform = Gem::Platform::RUBY
13
+ gem.license = 'MIT'
14
+
15
+ gem.summary = 'Caligari symbolically links configuration files.'
16
+ gem.description = %{
17
+ Caligari is designed to allow the quick and easy installation of
18
+ configuration files by symbolically linking files from external sources
19
+ directly to the user's home directory.
20
+ }.gsub!(/\s+/, " ").strip
21
+
22
+ %w(bundler md2man rake yard).each do |dep|
23
+ gem.add_development_dependency(dep)
24
+ end
25
+ gem.add_dependency('trollop')
26
+
27
+ gem.files = `git ls-files -z`.split("\x0")
28
+ gem.files += Dir['man/man?/*.?'] # Explicitly add generated man page.
29
+ gem.executables = 'caligari'
30
+ gem.require_path = 'lib'
31
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'caligari/application'
2
+ require_relative 'caligari/xdg'
3
+ require_relative 'caligari/version'
4
+
5
+ # Caligari is designed to allow the quick and easy installation of
6
+ # configuration files by symbolically linking files from external sources
7
+ # directly to the user's home directory.
8
+ module Caligari
9
+ end
@@ -0,0 +1,127 @@
1
+ require 'pathname'
2
+ require 'yaml/store'
3
+
4
+ require_relative 'xdg'
5
+
6
+ module Caligari
7
+ # This class is instantiated and used to run a single invocation of the
8
+ # `caligari` application.
9
+ class Application
10
+ # The flags to be passed to `Pathname#fnmatch?` to filter exclusions.
11
+ FLAGS = File::FNM_DOTMATCH | File::FNM_PATHNAME
12
+
13
+ # The `Pathname` representation of the current user's home directory.
14
+ HOME = Pathname.new(Dir.home)
15
+
16
+ # Instantiates a new {Application} instance.
17
+ #
18
+ # @param paths [Array<String>]
19
+ # the paths for this {Application} to {#run} on
20
+ # @param options [Hash]
21
+ # the hash of options to apply to this {Application}
22
+ # @return [self]
23
+ # the initialized {Application} instance
24
+ def initialize(*paths, **options)
25
+ @paths = paths.map { |path| Pathname.new(path) }
26
+ options.each do |key, value|
27
+ instance_variable_set(:"@#{key}", value)
28
+ end
29
+ collect_exclusions
30
+ end
31
+
32
+ # Runs Caligari.
33
+ #
34
+ # @return [self]
35
+ def run
36
+ @paths.each do |path|
37
+ fail "#{path} is not a valid path" unless path.directory?
38
+ if @traverse
39
+ Dir.chdir(path) do
40
+ each_file(Pathname.new('.')) { |file| link(file) }
41
+ end
42
+ else
43
+ each_file(path) { |file| link(file) }
44
+ end
45
+ end
46
+ self
47
+ end
48
+
49
+ # Collects the list of exclusion patterns for Caligari from a combination
50
+ # of XDG configuration directories and the given CLI exclusions.
51
+ #
52
+ # @note Exclusion patterns are used to filter the files to act upon via the
53
+ # `Pathname#fnmatch?` instance method. The actual filtering, however,
54
+ # takes place within {#each_file}.
55
+ #
56
+ # @return [Array<String>]
57
+ # the array of patterns to exclude
58
+ #
59
+ # @see #each_file
60
+ private def collect_exclusions
61
+ XDG::CONFIG_FILES.each do |file|
62
+ config = YAML::Store.new(file)
63
+ @exclude |= config.transaction { config.fetch(:exclude, []) }
64
+ end
65
+ @exclude
66
+ end
67
+
68
+ # Recursively iterates over each file in the given `path`, excluding those
69
+ # which match any of the exclusion patterns collected via the
70
+ # {#collect_exclusions} private instance method. The given `block` is
71
+ # executed for each file.
72
+ #
73
+ # @param path [Pathname]
74
+ # the base directory to iterate over
75
+ # @yieldparam entry [Pathname]
76
+ # the representation of a file
77
+ # @return [Array<Pathname>]
78
+ #
79
+ # @see #collect_exclusions
80
+ private def each_file(path, &block)
81
+ path.each_child do |entry|
82
+ next if @exclude.any? { |pattern| entry.fnmatch?(pattern, FLAGS) }
83
+ entry.directory? ? each_file(entry, &block) : yield(entry)
84
+ end
85
+ end
86
+
87
+ # Symbolically links the given `file` to the current user's home directory.
88
+ #
89
+ # @param file [Pathname]
90
+ # the `Pathname` representation of a file to link
91
+ # @return [Boolean]
92
+ # `true` if the given `file` was symbolically linked, `false` otherwise
93
+ private def link(file)
94
+ return false unless file.exist?
95
+ dest = HOME + file.dirname
96
+ unless dest.exist?
97
+ report "path: #{dest}"
98
+ dest.mkpath unless @simulate
99
+ end
100
+ dest += file.basename
101
+ if @force && dest.file?
102
+ report "rm: #{dest}"
103
+ dest.delete unless @simulate
104
+ end
105
+ report "ln: #{dest}" if @simulate || !dest.file?
106
+ if @simulate || dest.file?
107
+ false
108
+ else
109
+ dest.make_symlink(file.expand_path)
110
+ true
111
+ end
112
+ end
113
+
114
+ # Reports the given `message` on the given `stream` if Caligari has been
115
+ # configured to run in verbose or simulation mode.
116
+ #
117
+ # @param message [#to_s]
118
+ # the message to report
119
+ # @param stream [#puts]
120
+ # the stream to write a message to
121
+ # @return [nil]
122
+ private def report(message, stream = $stdout)
123
+ return unless @verbose || @simulate
124
+ stream.puts message.to_s
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,7 @@
1
+ module Caligari
2
+ # Semantic version of Caligari.
3
+ VERSION = '0.1.0'.freeze
4
+
5
+ # Copyright notice for Caligari.
6
+ COPYRIGHT = "caligari #{VERSION} (c) 2016 Robin Owen".freeze
7
+ end
@@ -0,0 +1,41 @@
1
+ require 'pathname'
2
+
3
+ module Caligari
4
+ # This module contains constants representing XDG configuration directories
5
+ # and files for Caligari as specified by the XDG Base Directory
6
+ # Specification.
7
+ #
8
+ # @see http://polr.me/zjp XDG Base Directory Specification
9
+ module XDG
10
+ # Collects configuration directories as defined by the XDG Base Directory
11
+ # Specification as `Pathname` instances.
12
+ #
13
+ # @api private
14
+ # @return [Array<Pathname>] the collected XDG configuration directories
15
+ def self.collect_xdg_config_dirs
16
+ dirs = ENV['XDG_CONFIG_DIRS']
17
+ if dirs
18
+ dirs.split(':').map! do |dir|
19
+ Pathname.new(dir).expand_path.freeze
20
+ end.freeze
21
+ else
22
+ [Pathname.new('/etc/xdg').freeze].freeze
23
+ end
24
+ end
25
+ private_class_method :collect_xdg_config_dirs
26
+
27
+ # The global XDG configuration directories as an array of `Pathname`
28
+ # instances.
29
+ CONFIG_DIRS = collect_xdg_config_dirs
30
+
31
+ # The user XDG configuration directory as a `Pathname` instance.
32
+ CONFIG_HOME =
33
+ Pathname.new(ENV['XDG_CONFIG_HOME'] || '~/.config').expand_path.freeze
34
+
35
+ # The existent XDG configuration files for Caligari as a `Pathname`
36
+ # instance.
37
+ CONFIG_FILES = (CONFIG_DIRS + [CONFIG_HOME]).map! do |dir|
38
+ (dir + 'caligari.yml').freeze
39
+ end.select! { |file| file.exist? }.freeze
40
+ end
41
+ end
@@ -0,0 +1,105 @@
1
+ CALIGARI 1
2
+ ===============================================================================
3
+
4
+ NAME
5
+ -------------------------------------------------------------------------------
6
+
7
+ caligari - symbolically link external configuration files
8
+
9
+ SYNOPSIS
10
+ -------------------------------------------------------------------------------
11
+
12
+ `caligari` [*OPTION*]... [*PATH*]...
13
+
14
+ DESCRIPTION
15
+ -------------------------------------------------------------------------------
16
+
17
+ `caligari` installs configuration files by symbolically linking all of the
18
+ files from the given paths directly to the current user's home directory with
19
+ the same relative file structure, creating any requisite directories as-needed.
20
+
21
+
22
+ OPTIONS
23
+ -------------------------------------------------------------------------------
24
+
25
+ `-x`, `--exclude` *pattern* ...
26
+ Exclude the files and directories matching the given patterns. Patterns may
27
+ be supplied as *fnmatch* patterns. Note that exclusions are automatically
28
+ given the **FNM_DOTMATCH** and **FNM_PATHNAME** flags.
29
+
30
+ `-f`, `--force`
31
+ Force installation over existing files.
32
+
33
+ `-s`, `--simulate`
34
+ Simulate installation (implies `--verbose`). Any action which would normally
35
+ affect the file system is simply reported rather than acted upon.
36
+
37
+ `-t`, `--traverse`
38
+ Traverse into the given directories while processing. This ensures that each
39
+ path given acts as its own relative "root" path during processing -- the
40
+ files in each path will be linked directly to the user's home directory
41
+ rather than being treated as children of the current working directory.
42
+
43
+ `-V`, `--verbose`
44
+ Print verbose installation information while processing. Each item printed
45
+ by this flag is announced with an appropriate label for the action being
46
+ taken (or simulated): `ln:` for created symbolic links, `path:` for created
47
+ directory paths, `rm:` for unlinked files, and `err:` for any errors
48
+ encountered.
49
+
50
+ CONFIGURATION
51
+ -------------------------------------------------------------------------------
52
+
53
+ `caligari` may be configured by editing the system-wide configuration file
54
+ (defined by default as */etc/xdg/caligari.yml*) or the per-user configuration
55
+ file (defined by default as *~/.config/caligari.yml*). These configuration
56
+ files are simple YAML files which define the default exclusion patterns used
57
+ by `caligari`.
58
+
59
+ EXAMPLES
60
+ -------------------------------------------------------------------------------
61
+
62
+ Create symbolic links for all of the files in the current directory excluding
63
+ the *.git* directory and all *README.md* files:
64
+
65
+ ```sh
66
+ caligari -x '**/.git' '**/README.md'
67
+ ```
68
+
69
+ Forcefully create symbolic links for all of the files in the directories
70
+ *dotfiles* and *more-dotfiles*, traversing to each so the files are linked
71
+ directly to the home directory:
72
+
73
+ ```sh
74
+ caligari -tf dotfiles more-dotfiles
75
+ ```
76
+
77
+ Print each file which was forcefully removed:
78
+
79
+ ```sh
80
+ caligari -Vf | awk '/^rm:/ { print $2 }'
81
+ ```
82
+
83
+ Example *~/.config/caligari.yml* to automatically exclude the *.git* directory
84
+ and all *README.md* files:
85
+
86
+ ```yaml
87
+ ---
88
+ :exclude:
89
+ - "**/.git"
90
+ - "**/README.md"
91
+ ```
92
+
93
+ FILES
94
+ -------------------------------------------------------------------------------
95
+
96
+ */etc/xdg/caligari.yml*
97
+ The system-wide configuration file.
98
+
99
+ *~/.config/caligari.yml*
100
+ Per-user configuration file.
101
+
102
+ AUTHOR
103
+ -------------------------------------------------------------------------------
104
+
105
+ Robin Owen <vthrenody@gmail.com>
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: caligari
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Robin Owen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: md2man
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: trollop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Caligari is designed to allow the quick and easy installation of configuration
84
+ files by symbolically linking files from external sources directly to the user's
85
+ home directory.
86
+ email:
87
+ - vthrenody@gmail.com
88
+ executables:
89
+ - caligari
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - ".gitignore"
94
+ - Gemfile
95
+ - LICENSE
96
+ - README.md
97
+ - Rakefile
98
+ - bin/caligari
99
+ - caligari.gemspec
100
+ - lib/caligari.rb
101
+ - lib/caligari/application.rb
102
+ - lib/caligari/version.rb
103
+ - lib/caligari/xdg.rb
104
+ - man/man1/caligari.1
105
+ - man/man1/caligari.1.md
106
+ homepage: https://github.com/vthrenody/caligari
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.6.6
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Caligari symbolically links configuration files.
130
+ test_files: []