solaris-prototype 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+
@@ -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).
@@ -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
+
@@ -0,0 +1,8 @@
1
+
2
+ # Namespace for child classes.
3
+ module Solaris
4
+
5
+ require 'solaris/prototype'
6
+
7
+ end # Solaris
8
+
@@ -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