homedir 3.0.alpha2 → 3.0.alpha4
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -1
- data/Guardfile +8 -4
- data/README.mkd +11 -1
- data/homedir.gemspec +1 -0
- data/lib/homedir.rb +3 -2
- data/lib/homedir/catalog.rb +4 -1
- data/lib/homedir/cli.rb +34 -3
- data/lib/homedir/errors.rb +4 -0
- data/lib/homedir/hacks.rb +9 -0
- data/lib/homedir/package.rb +47 -18
- data/lib/homedir/package_discovery_loader.rb +29 -0
- data/lib/homedir/package_loader.rb +48 -0
- data/lib/homedir/package_version1_loader.rb +70 -0
- data/lib/homedir/package_version2_loader.rb +48 -0
- data/lib/homedir/package_version3_loader.rb +45 -0
- data/lib/homedir/version.rb +1 -1
- data/spec/acceptance/load_packages_spec.rb +17 -0
- data/spec/examples/version1-example/.homedir.control +11 -0
- data/spec/examples/version1-example/combined/version1-file +3 -0
- data/spec/examples/version1-example/version1/separate-file +2 -0
- data/spec/examples/version2-example/.homedir/control +13 -0
- data/spec/examples/version2-example/.homedir/post-install +2 -0
- data/spec/examples/version2-example/.homedir/post-remove +2 -0
- data/spec/examples/version2-example/.homedir/pre-install +2 -0
- data/spec/examples/version2-example/.homedir/pre-remove +2 -0
- data/spec/examples/version2-example/combined/version2-file +3 -0
- data/spec/examples/version2-example/version2/separate-file +2 -0
- data/spec/examples/version3-example/.gitignore +1 -0
- data/spec/examples/version3-example/description.txt +3 -0
- data/spec/examples/version3-example/homedir.yml +4 -0
- data/spec/examples/version3-example/homedir/combined/version3-file +3 -0
- data/spec/examples/version3-example/homedir/version3/separate-file +2 -0
- data/spec/examples/version3-example/post-install.sh +2 -0
- data/spec/examples/version3-example/post-remove.sh +2 -0
- data/spec/examples/version3-example/post-update.sh +2 -0
- data/spec/examples/version3-example/pre-install.sh +2 -0
- data/spec/examples/version3-example/pre-remove.sh +2 -0
- data/spec/examples/version3-example/pre-update.sh +2 -0
- data/spec/integration/catalog_packages_spec.rb +27 -0
- data/spec/lib/homedir/package_loader_spec.rb +30 -0
- data/spec/lib/homedir/package_spec.rb +49 -4
- data/spec/lib/homedir/package_version1_loader_spec.rb +66 -0
- data/spec/lib/homedir/package_version2_loader_spec.rb +41 -0
- data/spec/lib/homedir/package_version3_loader_spec.rb +41 -0
- data/spec/spec_helper.rb +15 -8
- data/spec/support/package_shared_examples.rb +59 -0
- metadata +93 -20
data/Guardfile
CHANGED
@@ -7,11 +7,15 @@ guard 'bundler' do
|
|
7
7
|
# watch(/^.+\.gemspec/)
|
8
8
|
end
|
9
9
|
|
10
|
-
guard 'rspec', :version => 2, :cli => "--color --format doc
|
10
|
+
guard 'rspec', :version => 2, :cli => "--color --format doc" do
|
11
11
|
watch(%r{^spec/.+_spec\.rb$})
|
12
|
-
watch(%r{^lib/
|
13
|
-
watch(
|
14
|
-
watch(
|
12
|
+
watch(%r{^lib/}) { "spec/integration" }
|
13
|
+
#watch(%r{^(lib|bin)/}) { "spec/acceptance" }
|
14
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
15
|
+
watch('spec/spec_helper.rb') { "spec" }
|
16
|
+
watch('spec/factories.rb') { "spec" }
|
17
|
+
watch(%r{^spec/support/.+\.rb}) { "spec" }
|
18
|
+
watch(%r{^spec/examples/}) { "spec" }
|
15
19
|
end
|
16
20
|
|
17
21
|
|
data/README.mkd
CHANGED
@@ -22,7 +22,17 @@ That's it!
|
|
22
22
|
|
23
23
|
## Support
|
24
24
|
|
25
|
-
|
25
|
+
* File an [issue](https://github.com/docwhat/homedir/issues).
|
26
|
+
* Freenode IRC in [`#homedir`](http://webchat.freenode.net/?channels=rvm).
|
27
|
+
* Contact me [directly](http://docwhat.org/email).
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
I love having people help me. All changes are welcome!
|
32
|
+
|
33
|
+
* Submit a [pull request](https://github.com/docwhat/homedir/pulls)
|
34
|
+
* Add to the [wiki](https://github.com/docwhat/homedir/wiki).
|
35
|
+
* Use the github instant editing feature.
|
26
36
|
|
27
37
|
## The Story So Far…
|
28
38
|
|
data/homedir.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.add_development_dependency('factory_girl', ["~> 2.5.2"])
|
25
25
|
|
26
26
|
gem.add_development_dependency('yard')
|
27
|
+
gem.add_development_dependency('redcarpet')
|
27
28
|
|
28
29
|
gem.add_development_dependency('guard')
|
29
30
|
gem.add_development_dependency('guard-rspec')
|
data/lib/homedir.rb
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
# COPYRIGHT:: Copyright (c) 2012 Christian Höltje
|
3
3
|
# LICENSE:: The MIT License. See the file LICENSE distributed with this source.
|
4
4
|
require 'homedir/package'
|
5
|
+
require 'homedir/catalog'
|
6
|
+
require 'homedir/package_discovery_loader'
|
7
|
+
require 'homedir/errors'
|
5
8
|
|
6
9
|
module Homedir
|
7
|
-
class Error < StandardError
|
8
|
-
end
|
9
10
|
end
|
data/lib/homedir/catalog.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'homedir/errors'
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
module Homedir
|
4
|
-
class Catalog < Set
|
5
|
+
class Catalog < ::Set
|
5
6
|
|
7
|
+
# Find the package with the name `name`
|
8
|
+
#
|
6
9
|
# @param {String} name The name of the {Homedir::Package package} to find.
|
7
10
|
# @return {Homedir::Package} The package that matches the `name`
|
8
11
|
def find_by_name name
|
data/lib/homedir/cli.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
|
+
require 'homedir'
|
3
|
+
require 'pathname'
|
2
4
|
|
3
5
|
module Homedir
|
4
6
|
# The command line interface for {Homedir}.
|
@@ -7,7 +9,28 @@ module Homedir
|
|
7
9
|
# information
|
8
10
|
class CLI < Thor
|
9
11
|
|
10
|
-
|
12
|
+
no_tasks do
|
13
|
+
# The directories to scan for repositories
|
14
|
+
#
|
15
|
+
# @return {Enumerable} A list of Pathname objects
|
16
|
+
def repositories
|
17
|
+
[ Pathname.new(ENV['HOME']) + '.homedir' + 'packages']
|
18
|
+
end
|
19
|
+
|
20
|
+
# Helper method to initialize the catalog, if needed.
|
21
|
+
#
|
22
|
+
# @return {Homedir::Catalog} A populated catalog
|
23
|
+
def catalog
|
24
|
+
@catalog ||= Catalog.new.tap do |cat|
|
25
|
+
pdl = PackageDiscoveryLoader.new(cat)
|
26
|
+
repositories.each do |repo|
|
27
|
+
pdl.load_from_directory(repo)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "list", "Lists available packages."
|
11
34
|
method_option(
|
12
35
|
:remote,
|
13
36
|
:type => :boolean,
|
@@ -15,8 +38,11 @@ module Homedir
|
|
15
38
|
:aliases => '-r',
|
16
39
|
:description => "Queries the remote server")
|
17
40
|
def list
|
18
|
-
|
19
|
-
puts "
|
41
|
+
packages = catalog.to_a # TODO sort
|
42
|
+
puts "#{packages.length} local packages found:"
|
43
|
+
packages.each do |package|
|
44
|
+
puts " * #{package}"
|
45
|
+
end
|
20
46
|
end
|
21
47
|
|
22
48
|
desc "info PACKAGE", "Describe a specific PACKAGE in detail."
|
@@ -50,6 +76,11 @@ module Homedir
|
|
50
76
|
puts "Not implemented yet #{package_name.inspect}"
|
51
77
|
end
|
52
78
|
|
79
|
+
desc "repair", "Scans through your home directory and repairs all links. Warning: This can take a long time."
|
80
|
+
def repair
|
81
|
+
# FIXME: needs to do something
|
82
|
+
puts "Not implemented yet"
|
83
|
+
end
|
53
84
|
end
|
54
85
|
end
|
55
86
|
|
data/lib/homedir/errors.rb
CHANGED
data/lib/homedir/package.rb
CHANGED
@@ -20,12 +20,16 @@ module Homedir
|
|
20
20
|
:directory,
|
21
21
|
].freeze
|
22
22
|
DEFAULT_VALUES = {
|
23
|
-
:name
|
24
|
-
:description
|
25
|
-
:dependencies
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
23
|
+
:name => nil,
|
24
|
+
:description => nil,
|
25
|
+
:dependencies => [],
|
26
|
+
:pre_install => nil,
|
27
|
+
:post_install => nil,
|
28
|
+
:pre_remove => nil,
|
29
|
+
:post_remove => nil,
|
30
|
+
:pre_update => nil,
|
31
|
+
:post_update => nil,
|
32
|
+
:directory => nil,
|
29
33
|
}.freeze
|
30
34
|
|
31
35
|
# The name of the package.
|
@@ -44,16 +48,40 @@ module Homedir
|
|
44
48
|
# A list of package names this package depends on.
|
45
49
|
#
|
46
50
|
# When assigning a list, they can either be {Homedir::Package Package} objects or strings.
|
47
|
-
# @return [
|
51
|
+
# @return [Set] The set of package {#name names}.
|
48
52
|
attr_reader :dependencies
|
49
53
|
|
50
|
-
# A script
|
54
|
+
# A script to run before a package is enabled.
|
55
|
+
#
|
56
|
+
# @return {String}
|
57
|
+
attr_accessor :pre_install
|
58
|
+
|
59
|
+
# A script to run after a package is enabled.
|
51
60
|
#
|
52
61
|
# @return {String}
|
53
62
|
attr_accessor :post_install
|
54
63
|
|
55
|
-
# A script to run before
|
56
|
-
|
64
|
+
# A script to run before the package is disabled.
|
65
|
+
# @return {String}
|
66
|
+
attr_accessor :pre_remove
|
67
|
+
|
68
|
+
# A script to run after the package is disabled
|
69
|
+
# @return {String}
|
70
|
+
attr_accessor :post_remove
|
71
|
+
|
72
|
+
# A script to run before upgrading the package's source
|
73
|
+
#
|
74
|
+
# This is run before any upgrade steps run for the package source.
|
75
|
+
# @return {String}
|
76
|
+
attr_accessor :pre_update
|
77
|
+
|
78
|
+
# A script that runs after upgrading the package's source
|
79
|
+
#
|
80
|
+
# This is run after a package is upgraded and after the
|
81
|
+
# the package has been re-enabled but before the pre_install
|
82
|
+
# script.
|
83
|
+
# @return {String}
|
84
|
+
attr_accessor :post_update
|
57
85
|
|
58
86
|
# The directory where the package is stored.
|
59
87
|
#
|
@@ -62,15 +90,15 @@ module Homedir
|
|
62
90
|
# @return {Pathname}
|
63
91
|
attr_reader :directory
|
64
92
|
|
65
|
-
# Create a new {
|
93
|
+
# Create a new {Package} instance.
|
66
94
|
#
|
67
95
|
# @param {Hash} options
|
68
|
-
# @option options
|
69
|
-
# @option options
|
70
|
-
# @option options
|
71
|
-
# @option options
|
72
|
-
# @option options
|
73
|
-
# @option options
|
96
|
+
# @option options {String} :name The name of the package.
|
97
|
+
# @option options {String} :description The description of the package.
|
98
|
+
# @option options {Enumerable} :dependencies A list of {Homedir::Package packages} or {String strings}.
|
99
|
+
# @option options {Pathname} :directory The directory the packages is located at.
|
100
|
+
# @option options {String} :post_install Commands to run after installing the package.
|
101
|
+
# @option options {String} :pre_uninstall Commands to run before uninstalling the package.
|
74
102
|
def initialize(options = {})
|
75
103
|
options = DEFAULT_VALUES.merge(options)
|
76
104
|
|
@@ -100,7 +128,7 @@ module Homedir
|
|
100
128
|
|
101
129
|
# {include:#dependencies}
|
102
130
|
def dependencies= value
|
103
|
-
@dependencies = value.map { |p| p.to_s }
|
131
|
+
@dependencies = Set.new( value.map { |p| p.to_s } )
|
104
132
|
end
|
105
133
|
|
106
134
|
# {include:#directory}
|
@@ -159,5 +187,6 @@ module Homedir
|
|
159
187
|
def to_s
|
160
188
|
@name
|
161
189
|
end
|
190
|
+
|
162
191
|
end
|
163
192
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'homedir/package_loader'
|
2
|
+
|
3
|
+
module Homedir
|
4
|
+
class PackageDiscoveryLoader
|
5
|
+
attr_reader :catalog
|
6
|
+
def initialize(catalog=nil)
|
7
|
+
@catalog = catalog
|
8
|
+
end
|
9
|
+
|
10
|
+
def loader
|
11
|
+
@loader ||= PackageLoader.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# Recursively loads packages from the directory into {#catalog}
|
15
|
+
#
|
16
|
+
# @params {Pathname} path The directory to start scanning from
|
17
|
+
# @return {Homedir::PackageDiscoveryLoader} self
|
18
|
+
def load_from_directory path
|
19
|
+
if loader.path_is_valid?(path)
|
20
|
+
catalog << loader.load_from_path(path)
|
21
|
+
else
|
22
|
+
path.children.each do |child|
|
23
|
+
load_from_directory(child) if child.directory?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'homedir/errors'
|
2
|
+
require 'homedir/package_version1_loader'
|
3
|
+
require 'homedir/package_version2_loader'
|
4
|
+
require 'homedir/package_version3_loader'
|
5
|
+
|
6
|
+
module Homedir
|
7
|
+
class PackageLoader
|
8
|
+
|
9
|
+
# The list of loaders, in the order they should be tried
|
10
|
+
#
|
11
|
+
# @return {Enumerable} A list of package loaders
|
12
|
+
def loaders
|
13
|
+
# The order is important
|
14
|
+
@loaders ||= [
|
15
|
+
PackageVersion3Loader.new,
|
16
|
+
PackageVersion2Loader.new,
|
17
|
+
PackageVersion1Loader.new,
|
18
|
+
].freeze
|
19
|
+
end
|
20
|
+
|
21
|
+
# Loads a package from a path
|
22
|
+
#
|
23
|
+
# @param {Pathname} path The directory of the package
|
24
|
+
# @return {Homedir::Package} The package object
|
25
|
+
def load_from_path path
|
26
|
+
loaders.each do |loader|
|
27
|
+
begin
|
28
|
+
return loader.load_from_path(path) if loader.path_is_valid?(path)
|
29
|
+
rescue InvalidPackageDirectoryError
|
30
|
+
next
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
raise InvalidPackageDirectoryError.new("The directory '#{path}' doesn't contain a valid package")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Is the path a valid version1 package directory?
|
38
|
+
#
|
39
|
+
# @return {Boolean} Returns true if the path is a valid package directory.
|
40
|
+
def path_is_valid? path
|
41
|
+
loaders.each do |loader|
|
42
|
+
return true if loader.path_is_valid?(path)
|
43
|
+
end
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'homedir/package'
|
2
|
+
require 'homedir/errors'
|
3
|
+
|
4
|
+
module Homedir
|
5
|
+
class PackageVersion1Loader
|
6
|
+
|
7
|
+
# Loads a package from a path
|
8
|
+
#
|
9
|
+
# @param {Pathname} path The directory of the package
|
10
|
+
# @return {Homedir::Package} The package object
|
11
|
+
def load_from_path(path)
|
12
|
+
raise InvalidPackageDirectoryError.new("The directory '#{path}' is not a version 1 package.") unless path_is_valid?(path)
|
13
|
+
control_path = path + '.homedir.control'
|
14
|
+
|
15
|
+
control = parse_control_file control_path
|
16
|
+
|
17
|
+
pkg = Package.new( :directory => path )
|
18
|
+
|
19
|
+
pkg.name = control[:package]
|
20
|
+
pkg.description = control[:description] || ''
|
21
|
+
pkg.dependencies = (control[:depends] || '').split("\n")
|
22
|
+
|
23
|
+
return pkg
|
24
|
+
end
|
25
|
+
|
26
|
+
# Is the path a valid version1 package directory?
|
27
|
+
#
|
28
|
+
# @return {Boolean} Returns true if the path is a valid package directory.
|
29
|
+
def path_is_valid? path
|
30
|
+
return false unless (path).directory?
|
31
|
+
return false unless (path + '.homedir.control').file?
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Parse a control file
|
36
|
+
#
|
37
|
+
# @param {Pathname} path The path to control file
|
38
|
+
# @return {Hash} A hash containing the keys/values.
|
39
|
+
# @see {#parse_control_stream}
|
40
|
+
def parse_control_file path
|
41
|
+
path.open('r') { |f| parse_control_stream f }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Parse a version 1 control from a stream
|
45
|
+
#
|
46
|
+
# This is *not* a robust parser.
|
47
|
+
# @param {IO} stream An IO stream to read from
|
48
|
+
# @return {Hash} A hash containing the keys/values.
|
49
|
+
def parse_control_stream stream
|
50
|
+
contents = stream.read()
|
51
|
+
|
52
|
+
hash = {}
|
53
|
+
last_key = nil
|
54
|
+
last_value = nil
|
55
|
+
contents.split(/[\r\n]+/).each do |line|
|
56
|
+
next if line =~ /^\s*#/
|
57
|
+
if line =~ /^\s/
|
58
|
+
last_value << line.strip unless last_key.nil?
|
59
|
+
elsif line.include? ":"
|
60
|
+
hash[last_key.to_sym] = last_value.join("\n") unless last_key.nil?
|
61
|
+
last_key, value = line.split(/\s*:\s*/, 2)
|
62
|
+
last_value = value.strip.empty? ? [] : [ value.strip ]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
hash[last_key.to_sym] = last_value.join("\n") unless last_key.nil?
|
66
|
+
|
67
|
+
return hash
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'homedir/package'
|
2
|
+
require 'homedir/package_version1_loader'
|
3
|
+
require 'homedir/errors'
|
4
|
+
|
5
|
+
module Homedir
|
6
|
+
class PackageVersion2Loader < PackageVersion1Loader
|
7
|
+
|
8
|
+
# Loads a package from a path
|
9
|
+
#
|
10
|
+
# @param {Pathname} path The directory of the package
|
11
|
+
# @return {Homedir::Package} The package object
|
12
|
+
def load_from_path(path)
|
13
|
+
raise InvalidPackageDirectoryError.new("The directory '#{path}' is not a version 2 package.") unless path_is_valid?(path)
|
14
|
+
control_path = path + '.homedir' + 'control'
|
15
|
+
|
16
|
+
control = parse_control_file control_path
|
17
|
+
|
18
|
+
pkg = Package.new( :directory => path )
|
19
|
+
|
20
|
+
pkg.name = control[:package]
|
21
|
+
pkg.description = control[:description] || ''
|
22
|
+
pkg.dependencies = (control[:depends] || '').split("\n")
|
23
|
+
|
24
|
+
['pre', 'post'].each do |prefix|
|
25
|
+
['install', 'remove'].each do |action|
|
26
|
+
filepath = (path + ".homedir" + "#{prefix}-#{action}")
|
27
|
+
if filepath.file? and filepath.executable?
|
28
|
+
filepath.open('r') do |f|
|
29
|
+
pkg.send("#{prefix}_#{action}=", f.read())
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
return pkg
|
36
|
+
end
|
37
|
+
|
38
|
+
# Is the path a valid version2 package directory?
|
39
|
+
#
|
40
|
+
# @return {Boolean} Returns true if the path is a valid package directory.
|
41
|
+
def path_is_valid? path
|
42
|
+
return false unless (path).directory?
|
43
|
+
return false unless (path + '.homedir').directory?
|
44
|
+
return false unless (path + '.homedir' + 'control').file?
|
45
|
+
return true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|