solaris-prototype 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +26 -0
- data/README.rdoc +27 -0
- data/Rakefile +28 -0
- data/lib/solaris.rb +8 -0
- data/lib/solaris/prototype.rb +183 -0
- data/test/test_prototype.rb +108 -0
- data/test/test_solaris.rb +17 -0
- metadata +57 -0
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright 2011 Martin Carpenter. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are
|
4
|
+
permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of
|
7
|
+
conditions and the following disclaimer.
|
8
|
+
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
10
|
+
of conditions and the following disclaimer in the documentation and/or other materials
|
11
|
+
provided with the distribution.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED BY Martin Carpenter ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
14
|
+
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Martin Carpenter OR
|
16
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
17
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
18
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
19
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
20
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
21
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
|
+
|
23
|
+
The views and conclusions contained in the software and documentation are those of the
|
24
|
+
authors and should not be interpreted as representing official policies, either expressed
|
25
|
+
or implied, of Martin Carpenter.
|
26
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
= solaris-prototype
|
3
|
+
|
4
|
+
Author:: Martin Carpenter
|
5
|
+
Email:: mcarpenter@free.fr
|
6
|
+
Copyright:: Copyright (c) Martin Carpenter 2011
|
7
|
+
|
8
|
+
== About
|
9
|
+
|
10
|
+
The solaris-prototype gem helps with the manipulation of SunOS and Solaris
|
11
|
+
prototype entries for SysV packages.
|
12
|
+
|
13
|
+
== Examples
|
14
|
+
|
15
|
+
=== Prepare a prototype for installation as another user
|
16
|
+
|
17
|
+
p = Solaris::Prototype.from_path './usr/local/bin/foo'
|
18
|
+
p.to_s
|
19
|
+
=> "f none ./usr/local/bin/foo 0755 martin staff"
|
20
|
+
p.owner = 'root'
|
21
|
+
p.group = 'sys'
|
22
|
+
p.to_s
|
23
|
+
=> "f none ./usr/local/bin/foo 0755 root sys"
|
24
|
+
p.pathname = "/usr/local/bin/foo=./usr/local/bin/foo"
|
25
|
+
=> "f none /usr/local/bin/foo=./usr/local/bin/foo 0755 root sys"
|
26
|
+
|
27
|
+
This can then be fed into pkgmk(1M).
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'rubygems/package_task'
|
6
|
+
|
7
|
+
desc 'Default task (package)'
|
8
|
+
task :default => [:package]
|
9
|
+
|
10
|
+
Rake::TestTask.new( 'test' )
|
11
|
+
|
12
|
+
SPECFILE = 'solaris-prototype.gemspec'
|
13
|
+
if File.exist?( SPECFILE )
|
14
|
+
spec = eval( File.read( SPECFILE ) )
|
15
|
+
#Rake::GemPackageTask.new( spec ).define
|
16
|
+
Gem::PackageTask.new( spec ).define
|
17
|
+
end
|
18
|
+
|
19
|
+
Rake::RDocTask.new do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = 'solaris-prototype'
|
22
|
+
rdoc.options << '--charset' << 'utf-8'
|
23
|
+
rdoc.options << '--all'
|
24
|
+
rdoc.rdoc_files.include( 'README.rdoc' )
|
25
|
+
rdoc.rdoc_files.include( FileList[ 'lib/**/*' ] )
|
26
|
+
rdoc.rdoc_files.include( FileList[ 'test/**/*' ] )
|
27
|
+
end
|
28
|
+
|
data/lib/solaris.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
|
2
|
+
require 'etc'
|
3
|
+
|
4
|
+
module Solaris
|
5
|
+
|
6
|
+
# Class to represent Solaris package file prototypes.
|
7
|
+
# A prototype line contains information regarding file
|
8
|
+
# type, location, ownership, permisions.
|
9
|
+
#
|
10
|
+
# See Solaris' prototype(4) man-page for information on
|
11
|
+
# attributes.
|
12
|
+
#
|
13
|
+
# This class does not support special lines (those
|
14
|
+
# beginning with !), pathname variable substitution or
|
15
|
+
# prototype parts.
|
16
|
+
class Prototype
|
17
|
+
|
18
|
+
attr_accessor :part
|
19
|
+
attr_accessor :ftype
|
20
|
+
attr_accessor :install_class
|
21
|
+
attr_accessor :pathname
|
22
|
+
attr_accessor :major
|
23
|
+
attr_accessor :minor
|
24
|
+
attr_accessor :mode
|
25
|
+
attr_accessor :owner
|
26
|
+
attr_accessor :group
|
27
|
+
|
28
|
+
# Install class to use if not specified.
|
29
|
+
DEFAULT_INSTALL_CLASS = 'none'
|
30
|
+
|
31
|
+
# Part to use if not specified. Solaris 10 documentation
|
32
|
+
# for prototype(4) states that no part given implies
|
33
|
+
# "part 1".
|
34
|
+
DEFAULT_PART = nil
|
35
|
+
|
36
|
+
# Regular expression for filetype.
|
37
|
+
RE_FTYPE = '([bcdefpvxils])'
|
38
|
+
|
39
|
+
# Regular expression for install class.
|
40
|
+
RE_INSTALL_CLASS = '(\w{1,12})'
|
41
|
+
|
42
|
+
# Regular expression for path.
|
43
|
+
RE_PATH = '(\S+)'
|
44
|
+
|
45
|
+
# Regular expression for major device mode.
|
46
|
+
RE_MAJOR = '(\d+)'
|
47
|
+
|
48
|
+
# Regular expression for minor device mode.
|
49
|
+
RE_MINOR = '(\d+)'
|
50
|
+
|
51
|
+
# Regular expression for octal file mode.
|
52
|
+
RE_MODE = '([0-7]{4})'
|
53
|
+
|
54
|
+
# Regular expression for user name.
|
55
|
+
RE_OWNER = '(\S+)'
|
56
|
+
|
57
|
+
# Regular expression for group name.
|
58
|
+
RE_GROUP = '(\S+)'
|
59
|
+
|
60
|
+
# Create a Prototype object from a line from a prototype(4) file.
|
61
|
+
def self.from_line(line)
|
62
|
+
ftype = $1.to_sym if line =~ /^#{RE_FTYPE} /
|
63
|
+
re = case ftype
|
64
|
+
when :b, :c
|
65
|
+
/^#{ftype} #{RE_INSTALL_CLASS} #{RE_PATH} #{RE_MAJOR} #{RE_MINOR} #{RE_MODE} #{RE_OWNER} #{RE_GROUP}$/
|
66
|
+
when :d, :e, :f, :p, :v, :x
|
67
|
+
/^#{ftype} #{RE_INSTALL_CLASS} #{RE_PATH} #{RE_MODE} #{RE_OWNER} #{RE_GROUP}$/
|
68
|
+
when :i
|
69
|
+
/^#{ftype} #{RE_PATH}/ # perhaps not really path
|
70
|
+
when :l, :s
|
71
|
+
/^#{ftype} #{RE_INSTALL_CLASS} #{RE_PATH}/
|
72
|
+
else
|
73
|
+
raise ArgumentError, 'Unknown filetype'
|
74
|
+
end
|
75
|
+
if line =~ re
|
76
|
+
proto = self.new
|
77
|
+
proto.ftype = ftype
|
78
|
+
case ftype
|
79
|
+
when :b, :c
|
80
|
+
proto.install_class = $1
|
81
|
+
proto.pathname =$2
|
82
|
+
proto.major = $3.to_i
|
83
|
+
proto.minor = $4.to_i
|
84
|
+
proto.mode = $5.to_i(8)
|
85
|
+
proto.owner = $6
|
86
|
+
proto.group = $7
|
87
|
+
when :d, :e, :f, :p, :v, :x
|
88
|
+
proto.install_class = $1
|
89
|
+
proto.pathname = $2
|
90
|
+
proto.mode = $3.to_i(8)
|
91
|
+
proto.owner = $4
|
92
|
+
proto.group = $5
|
93
|
+
when :i
|
94
|
+
proto.pathname = $1
|
95
|
+
when :l, :s
|
96
|
+
proto.install_class = $1
|
97
|
+
proto.pathname = $2
|
98
|
+
end
|
99
|
+
else
|
100
|
+
if line =~ /^!/
|
101
|
+
raise ArgumentError, "Prototype commands not supported #{line.inspect}"
|
102
|
+
else
|
103
|
+
raise ArgumentError, "Could not parse line #{line.inspect}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
proto
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create a Prototype from the file at the +path+ on the local
|
110
|
+
# filesystem.
|
111
|
+
#
|
112
|
+
# If +actual+ is provided then this is the path that is used for the
|
113
|
+
# object's pathname property although all other properties are
|
114
|
+
# created from the +path+ argument. The process must be able to
|
115
|
+
# stat(1) the file at +path+ to determine these properties.
|
116
|
+
#
|
117
|
+
# If this object is to be fed to pkgmk(1M) to be installed at
|
118
|
+
# +real_location+ and the file that will be used to construct the
|
119
|
+
# package currently lives at +current_location+ then the second
|
120
|
+
# argument should take the form +real_location+=+current_location+.
|
121
|
+
# The first argument (+path+) is always the file from which the
|
122
|
+
# Prototype's properties only (eg. owner, mode) are created.
|
123
|
+
#
|
124
|
+
# For example, to take the object attributes from the already
|
125
|
+
# installed file in /opt/MYpkg/foo, but to subsequently package the
|
126
|
+
# file ./foo in that same location using pkgmk(1M) call:
|
127
|
+
# from_path( '/opt/MYpkg/foo', '/opt/MYpkg/foo=./foo' )
|
128
|
+
def self.from_path(path, actual=nil)
|
129
|
+
proto = self.new
|
130
|
+
proto.part = DEFAULT_PART
|
131
|
+
# Use #lstat since we are always interested in the link source,
|
132
|
+
# not the target.
|
133
|
+
stat = File.lstat( path )
|
134
|
+
raise RuntimeError, 'Unknown file type' if stat.ftype == 'unknown'
|
135
|
+
# Stat returns "link" for symlink, not "symlink"
|
136
|
+
proto.ftype = stat.symlink? ? :s : stat.ftype[0].to_sym
|
137
|
+
proto.pathname = actual ? actual : path
|
138
|
+
proto.part = nil
|
139
|
+
proto.install_class = DEFAULT_INSTALL_CLASS
|
140
|
+
if [ :b, :c ].include?( proto.ftype )
|
141
|
+
proto.major = stat.dev_major
|
142
|
+
proto.minor = stat.dev_minor
|
143
|
+
end
|
144
|
+
proto.mode = stat.mode & 07777
|
145
|
+
proto.owner = Etc.getpwuid( stat.uid ).name
|
146
|
+
proto.group = Etc.getgrgid( stat.gid ).name
|
147
|
+
proto
|
148
|
+
end
|
149
|
+
|
150
|
+
# Convert the object to a prototype(4) line (string).
|
151
|
+
def to_s
|
152
|
+
( ( @part ? [ @part ] : [] ) +
|
153
|
+
case @ftype
|
154
|
+
when :b, :c
|
155
|
+
[ @ftype.to_s, @install_class, @pathname, @major, @minor, '%04o' % @mode, @owner, @group ]
|
156
|
+
when :d, :e, :f, :p, :v, :x
|
157
|
+
[ @ftype.to_s, @install_class, @pathname, '%04o' % @mode, @owner, @group ]
|
158
|
+
when :i
|
159
|
+
[ @ftype.to_s, @pathname ]
|
160
|
+
when :l, :s
|
161
|
+
[ @ftype.to_s, @install_class, @pathname ]
|
162
|
+
else
|
163
|
+
raise RuntimeError, "Unknown ftype #{@ftype.inspect}"
|
164
|
+
end ).join(' ')
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns true if the object is a valid prototype specification, false
|
168
|
+
# otherwise.
|
169
|
+
def valid?
|
170
|
+
begin
|
171
|
+
self.class.from_line( to_s )
|
172
|
+
rescue ArgumentError, RuntimeError
|
173
|
+
false
|
174
|
+
else
|
175
|
+
true
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
end # Prototype
|
181
|
+
|
182
|
+
end # Solaris
|
183
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Unit tests for Solaris::Prototype.
|
5
|
+
class TestPrototype < Test::Unit::TestCase #:nodoc:
|
6
|
+
|
7
|
+
# These don't work on Cygwin. They might work on proper unices.
|
8
|
+
#def test_from_path_file
|
9
|
+
# assert( Solaris::Prototype.from_path( __FILE__ ).valid? )
|
10
|
+
#end
|
11
|
+
#
|
12
|
+
#def test_from_path_root
|
13
|
+
# assert( Solaris::Prototype.from_path( '/' ).valid? )
|
14
|
+
#end
|
15
|
+
|
16
|
+
def test_character_device
|
17
|
+
line = 'c none /dev/null 13 2 0666 root sys'
|
18
|
+
proto = Solaris::Prototype.from_line( line )
|
19
|
+
assert_equal( :c, proto.ftype )
|
20
|
+
assert_equal( 'none', proto.install_class )
|
21
|
+
assert_equal( '/dev/null', proto.pathname )
|
22
|
+
assert_equal( 13, proto.major )
|
23
|
+
assert_equal( 2, proto.minor )
|
24
|
+
assert_equal( 438, proto.mode )
|
25
|
+
assert_equal( 'root', proto.owner )
|
26
|
+
assert_equal( 'sys', proto.group )
|
27
|
+
assert( proto.valid? )
|
28
|
+
assert_equal( line, proto.to_s )
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_symbolic_link
|
32
|
+
line = 's none /etc/hosts=./inet/hosts'
|
33
|
+
proto = Solaris::Prototype.from_line( line )
|
34
|
+
assert_equal( :s, proto.ftype )
|
35
|
+
assert_equal( 'none', proto.install_class )
|
36
|
+
assert_equal( '/etc/hosts=./inet/hosts', proto.pathname )
|
37
|
+
assert_equal( nil, proto.major )
|
38
|
+
assert_equal( nil, proto.minor )
|
39
|
+
assert_equal( nil, proto.mode )
|
40
|
+
assert_equal( nil, proto.owner )
|
41
|
+
assert_equal( nil, proto.group )
|
42
|
+
assert( proto.valid? )
|
43
|
+
assert_equal( line, proto.to_s )
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_directory
|
47
|
+
line = 'd none /export/home/martin 0755 mcarpenter staff'
|
48
|
+
proto = Solaris::Prototype.from_line( line )
|
49
|
+
assert_equal( :d, proto.ftype )
|
50
|
+
assert_equal( 'none', proto.install_class )
|
51
|
+
assert_equal( '/export/home/martin', proto.pathname )
|
52
|
+
assert_equal( nil, proto.major )
|
53
|
+
assert_equal( nil, proto.minor )
|
54
|
+
assert_equal( 493, proto.mode )
|
55
|
+
assert_equal( 'mcarpenter', proto.owner )
|
56
|
+
assert_equal( 'staff', proto.group )
|
57
|
+
assert( proto.valid? )
|
58
|
+
assert_equal( line, proto.to_s )
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_file
|
62
|
+
line = 'f none /export/home/martin/.profile 0755 mcarpenter staff'
|
63
|
+
proto = Solaris::Prototype.from_line( line )
|
64
|
+
assert_equal( :f, proto.ftype )
|
65
|
+
assert_equal( 'none', proto.install_class )
|
66
|
+
assert_equal( '/export/home/martin/.profile', proto.pathname )
|
67
|
+
assert_equal( nil, proto.major )
|
68
|
+
assert_equal( nil, proto.minor )
|
69
|
+
assert_equal( 493, proto.mode )
|
70
|
+
assert_equal( 'mcarpenter', proto.owner )
|
71
|
+
assert_equal( 'staff', proto.group )
|
72
|
+
assert( proto.valid? )
|
73
|
+
assert_equal( line, proto.to_s )
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_part
|
77
|
+
line = 'f none /export/home/martin/.profile 0755 mcarpenter staff'
|
78
|
+
proto = Solaris::Prototype.from_line( line )
|
79
|
+
proto.part = 'part'
|
80
|
+
assert_equal( "part #{line}", proto.to_s )
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_unknown_ftype
|
84
|
+
line = 'X none /export/home/martin/.profile 0755 mcarpenter staff'
|
85
|
+
assert_raise ArgumentError do
|
86
|
+
Solaris::Prototype.from_line( line )
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_unparseable_line
|
91
|
+
line = 'f nonsense'
|
92
|
+
assert_raise ArgumentError do
|
93
|
+
Solaris::Prototype.from_line( line )
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_valid
|
98
|
+
line = 'f none /export/home/martin/.profile 0755 mcarpenter staff'
|
99
|
+
proto = Solaris::Prototype.from_line( line )
|
100
|
+
assert( proto.valid? )
|
101
|
+
proto.ftype = :invalid
|
102
|
+
assert( ! proto.valid? )
|
103
|
+
proto.ftype = :d
|
104
|
+
assert( proto.valid? )
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
require 'solaris'
|
4
|
+
|
5
|
+
# Unit tests for top level require.
|
6
|
+
class TestSolaris < Test::Unit::TestCase #:nodoc:
|
7
|
+
|
8
|
+
def test_solaris
|
9
|
+
assert_nothing_raised { Solaris }
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_solaris_prototype
|
13
|
+
assert_nothing_raised { Solaris::Prototype }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: solaris-prototype
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Martin Carpenter
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-15 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Parse and write Solaris package prototype records
|
15
|
+
email: mcarpenter@free.fr
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- LICENSE
|
20
|
+
- Rakefile
|
21
|
+
- README.rdoc
|
22
|
+
files:
|
23
|
+
- lib/solaris/prototype.rb
|
24
|
+
- lib/solaris.rb
|
25
|
+
- test/test_solaris.rb
|
26
|
+
- test/test_prototype.rb
|
27
|
+
- LICENSE
|
28
|
+
- Rakefile
|
29
|
+
- README.rdoc
|
30
|
+
homepage: http://mcarpenter.org/projects/solaris-prototype
|
31
|
+
licenses:
|
32
|
+
- BSD
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.10
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: Parse and write Solaris package prototype records
|
55
|
+
test_files:
|
56
|
+
- test/test_solaris.rb
|
57
|
+
- test/test_prototype.rb
|