qrpm 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5a7181b2cc45c65645e039fc5fba4d758698e2558acafe9f9173a955f7af7895
4
+ data.tar.gz: 714b179b5f0f235ddd7b6098ea674579fc8dec671db6d76570e9c9128d7edae7
5
+ SHA512:
6
+ metadata.gz: eaf5dc6516f01dcc9a912f1982f7008f2d1ff667aff8cabf9197945726d43690bc4d28836a186d2a3f5b245f17ecf2d8c7744facbdd7fe6f81d8d32aaf6ce3c3
7
+ data.tar.gz: eb40981a98a3408f545ef8b42ce6a9f1f70657393886542857911f74865759e2227de458648a04c94a0b9edcc3d18a8a5b54ca3035f6c15fc8ddca5a057f7501
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.7.1
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in qrpm.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Qrpm
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/qrpm`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'qrpm'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install qrpm
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/qrpm.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "qrpm"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/clean ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/bash
2
+
3
+ rm -rf example/{my_package_name,tmp,my_package_name.tar.gz}
data/cmd ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/bash
2
+
3
+ set -e
4
+
5
+ VERSION=1.2.4
6
+ PG_VERSION=13
7
+
8
+ rm -f example/*.rpm
9
+ #sudo rpm -e my_package_name 2>/dev/null || true
10
+ bundle exec exe/qrpm $@ --force -C example VERSION=$VERSION PG_VERSION=$PG_VERSION qrpm.yml
11
+ #sudo rpm -i example/my_package_name-1.2.3-4.x86_64.rpm
12
+
@@ -0,0 +1 @@
1
+ hej
File without changes
data/example/qrpm.yml ADDED
@@ -0,0 +1,31 @@
1
+
2
+ name: my_package_name
3
+ summary: This is a summary of the package
4
+ description: Optional longer description of the package
5
+ version: 1.2.3
6
+ release: 4
7
+ packager: null
8
+ requires:
9
+ - ruby
10
+ - httpd
11
+ - postgresql13
12
+
13
+ make: # List of commands to build project
14
+ - echo "Hej du" > bin/another_file
15
+
16
+ bindir:
17
+ - bin/a_file
18
+ - bin/another_file
19
+ - name: an_alias
20
+ file: bin/a_file
21
+
22
+ sbindir:
23
+ - link: /bin/a_file
24
+
25
+ pcksharedir:
26
+ - share/some_data
27
+
28
+ vardir:
29
+ - share/some_other_data
30
+
31
+
@@ -0,0 +1 @@
1
+ hejdu
File without changes
data/exe/qrpm ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #$LOAD_PATH.unshift "/home/clr/prj/shellopts/lib"
4
+
5
+ require_relative '../lib/qrpm/qrpm.rb'
6
+ require_relative '../lib/qrpm.rb'
7
+
8
+ require 'yaml'
9
+ require 'shellopts'
10
+ require 'indented_io'
11
+
12
+ # TODO
13
+ # o Fix BuildRoot (contains absolute path)
14
+ # o Enable escape of $
15
+
16
+ begin
17
+ SPEC = %(
18
+ @ Quick RPM builder
19
+
20
+ 'qrpm' creates a RPM package from a simple YAML specification file
21
+
22
+ A template YAML qrpm configuration file can be generated by the --template
23
+ option. It is in YAML format with the extension that a single '__END__'
24
+ terminates the file and that $NAME or ${NAME} are variables that will be
25
+ expanded. The variables can either be specified in the configuration file
26
+ or given on the command line in <variable>=<value> format
27
+
28
+ -- VARIABLE=VALUE... [QRPM-FILE]
29
+
30
+ -t,template=OFILE?
31
+ Generate a template qrpm.yml file in the current directory. Customize it
32
+ to create RPM packages of your project
33
+
34
+ -s,spec=OFILE?
35
+ Only create the spec file and not the RPM package. Use this option to
36
+ inspect what RPM is going to do
37
+
38
+ -S,source
39
+ Create a source RPM file instead of a regular RPM file
40
+
41
+ -f,force
42
+ Create package even if repository is dirty. Normally qrpm checks if the
43
+ current directory is a Git directory and then if there are no changed
44
+ files
45
+
46
+ -C,directory=EDIR
47
+ Change to directory before doing anything else
48
+
49
+ -d,dump
50
+ Dump internal data and exit
51
+ )
52
+
53
+ opts, args = ShellOpts.process(SPEC, ARGV)
54
+
55
+ Dir.chdir(opts.directory) if opts.directory?
56
+
57
+ if opts.template?
58
+ outfile = opts.template || Qrpm::QRPM_CONFIG_FILE
59
+ FileUtils::cp Qrpm::QRPM_CONFIG_FILE_TEMPLATE, outfile
60
+ exit
61
+ end
62
+
63
+ # Collect var=val settings in the dict hash and sets the configuration file
64
+ dict = {}
65
+ while arg = args.extract(0..1)
66
+ if arg =~ /^(.*?)=(.*)$/
67
+ dict[$1] = $2
68
+ else
69
+ file = arg
70
+ break
71
+ end
72
+ end
73
+ args.empty? or args.expect(0) # Generates an illegal-number-of-arguments error
74
+
75
+ # Check configuration file
76
+ file ||= QRPM_CONFIG_FILE
77
+ ::File.exist?(file) or raise "Can't find '#{file}'"
78
+
79
+ # Check if repository is clean
80
+ opts.force? || `git status --porcelain 2>/dev/null` == "" or raise "Repository is dirty"
81
+
82
+ # Load the qrpm configuration file
83
+ yaml = YAML.load(IO.read(file).sub(/^__END__\s*$/m, ""))
84
+
85
+ # Parse QRPM file
86
+ rpm = Qrpm::Parser.parse(dict, yaml)
87
+
88
+ if opts.dump?
89
+ rpm.dump
90
+ exit
91
+ end
92
+
93
+ target = (opts.spec? ? :spec : (opts.source? ? :srpm : :rpm))
94
+ rpm.build(target: target, file: opts.spec)
95
+
96
+ rescue RuntimeError => ex
97
+ ShellOpts.error ex.message
98
+ end
99
+
data/lib/qrpm/node.rb ADDED
@@ -0,0 +1,54 @@
1
+
2
+ module Qrpm
3
+ class Node
4
+ attr_reader :directory # Destination directory
5
+ attr_reader :name # Defaults to last element of file/link
6
+ def path() "#{directory}/#{name}" end
7
+
8
+ def initialize(directory, name)
9
+ @directory, @name = directory, name
10
+ end
11
+
12
+ def file?() self.class == Qrpm::File end
13
+ def link?() self.class == Qrpm::Link end
14
+
15
+ def dump(&block)
16
+ puts self.class
17
+ indent {
18
+ puts "directory: #{directory}"
19
+ puts "name : #{name}"
20
+ yield if block_given?
21
+ }
22
+ end
23
+ end
24
+
25
+ class File < Node
26
+ attr_reader :file # Path to file in the source repository
27
+ attr_reader :perm # Defaults to nil - using the current permissions
28
+ def initialize(directory, name, file, perm = nil)
29
+ super(directory, name || file.sub(/.*\//, ""))
30
+ @file, @perm = file, perm
31
+ end
32
+ def dump
33
+ super {
34
+ puts "file : #{file}"
35
+ puts "perm : #{perm}"
36
+ }
37
+ end
38
+ end
39
+
40
+ class Link < Node
41
+ attr_reader :link # Destination file of link
42
+
43
+ def initialize(directory, name, link)
44
+ super(directory, name || link.sub(/.*\//, ""))
45
+ @link = link
46
+ end
47
+ def dump
48
+ super {
49
+ puts "link : #{link}"
50
+ }
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,173 @@
1
+
2
+ module Qrpm
3
+ class Parser
4
+ DICT_FIELDS = (Rpm::FIELDS - %w(requires)).map { |f| [f, true] }.to_h
5
+
6
+ attr_reader :fields # Hash from field to value (which can be of any type)
7
+ attr_reader :dirs # Hash from directory to list of entries
8
+ attr_reader :files # List of files
9
+ attr_reader :rpm # Resulting RPM object
10
+
11
+ def initialize(fields)
12
+ @fields = fields.dup
13
+ @dirs = {}
14
+ @files = []
15
+ end
16
+
17
+ def parse(yaml)
18
+ # Collect .qrpm file variables and directories and the list of required
19
+ # packages. Variables are merged into +fields+
20
+ yaml.each { |k,v|
21
+ if k =~ /[\/.]/ || DIRS.key?(k) || DIRS.key?(k.sub(/^pck/, ""))
22
+ (dirs[k] ||= []).concat v
23
+ elsif k =~ /^[\w_]+$/
24
+ fields[k] = v if !fields.key?(k)
25
+ else
26
+ raise "Illegal key/value: #{k}: #{v}"
27
+ end
28
+ }
29
+
30
+ # Check for mandatory variables
31
+ Rpm::MANDATORY_FIELDS.each { |f|
32
+ fields.key?(f) or raise "Missing mandatory variable: #{f}"
33
+ }
34
+
35
+ # Defaults for description and packager fields
36
+ fields["description"] ||= fields["summary"]
37
+ fields["packager"] ||= ENV['USER']
38
+ fields["release"] ||= "0"
39
+ fields["license"] ||= "GPL"
40
+
41
+ # Expand variables in fields. The expansion mechanism doesn't depend on the order
42
+ # of the variables
43
+ expand_fields
44
+
45
+ # Replace symbolic directory names
46
+ @dirs = dirs.map { |dir, files|
47
+ if DIRS.key?(dir)
48
+ dir = DIRS[dir]
49
+ elsif dir =~ /^pck(.*)$/ && DIRS.key?($1)
50
+ dir = "#{DIRS[$1]}/#{fields["name"]}"
51
+ end
52
+ [dir, files]
53
+ }.to_h
54
+
55
+ # Build files
56
+ dirs.each { |dir, nodes|
57
+ nodes.each { |node|
58
+ case node
59
+ when Hash
60
+ node = node.dup
61
+ if node.key?("file")
62
+ name = node.delete("name")
63
+ file = node.delete("file")
64
+ perm = node.delete("perm")
65
+ node.empty? or raise "Illegal keys for file in directory #{dir}: #{node.keys}"
66
+ files << Qrpm::File.new(dir, name, file, perm)
67
+ elsif node.key?("link")
68
+ name = node.delete("name")
69
+ link = node.delete("link")
70
+ node.empty? or raise "Illegal keys for link in directory #{dir}: #{node.keys}"
71
+ files << Qrpm::Link.new(dir, name, link)
72
+ else
73
+ raise "Need either a 'file' or 'link' field for directory #{dir}"
74
+ end
75
+ when String
76
+ files << Qrpm::File.new(dir, nil, node, nil)
77
+ else
78
+ raise "Illegal value for directory #{dir}: #{node}"
79
+ end
80
+ }
81
+ }
82
+
83
+ @rpm = Rpm.new(fields, files)
84
+ end
85
+
86
+ def self.parse(dict, yaml)
87
+ Parser.new(dict).parse(yaml)
88
+ end
89
+
90
+ private
91
+ MANDATORY_FIELDS = %w(name summary version)
92
+
93
+ DIRS = {
94
+ "etcdir" => "/etc",
95
+ "bindir" => "/usr/bin",
96
+ "sbindir" => "/usr/sbin",
97
+ "libdir" => "/usr/lib",
98
+ "libexecdir" => "/usr/libexec",
99
+ "sharedir" => "/usr/share",
100
+ "vardir" => "/var/lib",
101
+ "spooldir" => "/var/spool",
102
+ "rundir" => "/var/run",
103
+ "lockdir" => "/var/lock",
104
+ "cachedir" => "/var/cache",
105
+ "tmpdir" => "/tmp",
106
+ "logdir" => "/var/log"
107
+ }
108
+
109
+ # Returns array of variables in the object. Variables can be either '$name' or
110
+ # '${name}'. The variables are returned in left-to-right order
111
+ #
112
+ def collect_variables(object, include_keys: false)
113
+ case object
114
+ when Array; object.map { |obj| collect_variables(obj) }
115
+ when Hash; object.map { |k,v| (include_keys ? collect_variables(k) : []) + collect_variables(v) }
116
+ when String; object.scan(/\$([\w_]+)|\$\{([\w_]+)\}/)
117
+ when Integer, Float, true, false, nil; []
118
+ else
119
+ raise "Illegal object: #{object}"
120
+ end.flatten.compact.uniq
121
+ end
122
+
123
+ # Expand variables in the given string
124
+ #
125
+ # The method takes case to substite left-to-rigth to avoid a variable expansion
126
+ # to infer with the name of an immediately preceding variable. Eg. $a$b; if $b
127
+ # is resolved to 'c' then a search would otherwise be made for a variable named
128
+ # '$ac'
129
+ #
130
+ def expand_variables(object, include_key: false)
131
+ case object
132
+ when Array; object.map { |e| expand_variables(e) }
133
+ when Hash; object.map { |k,v| [expand_variables(k), expand_variables(v)] }.to_h
134
+ when String
135
+ s = object.dup
136
+ collect_variables(object).each { |k| s.sub!(/\$#{k}|\$\{#{k}\}/, fields[k].to_s) }
137
+ s
138
+ when Integer, Float, true, false, nil; object
139
+ else
140
+ raise "Illegal object: #{object}"
141
+ end
142
+ end
143
+
144
+ # Expands fields (but not directories). The algorithm allows fields to be
145
+ # defined in any order
146
+ #
147
+ def expand_fields
148
+ variables = fields.map { |k,v| [k, collect_variables(v)] }.to_h
149
+ variables.values.flatten.uniq.each { |var|
150
+ fields[var].nil? || fields[var].is_a?(String) or "Can't use '#{var}' as variable"
151
+ }
152
+
153
+ @fields, unresolved = fields.partition { |k,v| variables[k].empty? }.map(&:to_h)
154
+ changed = true
155
+ while changed && !unresolved.empty?
156
+ changed = false
157
+ unresolved.delete_if { |k,v|
158
+ if variables[k].all? { |var| fields.key? var }
159
+ fields[k] = expand_variables(unresolved[k])
160
+ changed = true
161
+ end
162
+ }
163
+ end
164
+ unresolved.empty? or raise "Unresolved variables: #{unresolved.join(", ")}"
165
+ end
166
+
167
+ def expand_dirs
168
+ @dirs = expand_variables(dirs)
169
+ end
170
+ end
171
+ end
172
+
173
+
data/lib/qrpm/qrpm.rb ADDED
@@ -0,0 +1,63 @@
1
+
2
+ __END__
3
+ # Returns array of variables in the string. Variables can be either '$name' or
4
+ # '${name}'. The variables are returned in left-to-right order
5
+ #
6
+ def collect_exprs(expr)
7
+ expr.scan(/\$([\w_]+)|\$\{([\w_]+)\}/).flatten.compact
8
+ end
9
+
10
+ # Expand variables in the given string
11
+ #
12
+ # The method takes case to substite left-to-rigth to avoid a variable expansion
13
+ # to infer with the name of an immediately preceding variable. Eg. $a$b; if $b
14
+ # is resolved to 'c' then a search would otherwise be made for a variable named
15
+ # '$ac'
16
+ #
17
+ def expand_expr(dict, value)
18
+ value = value.dup
19
+ collect_exprs(value).each { |k| value.sub!(/\$#{k}|\$\{#{k}\}/, dict[k]) }
20
+ value
21
+ end
22
+
23
+ def expand_dict(dict)
24
+ expressions = dict.map { |k,v| [k, collect_exprs(v)] }.to_h
25
+ result = expressions.select { |k, v| v.empty? }.map { |k,v| [k, dict[k]] }.to_h
26
+ unresolved = dict.keys - result.keys
27
+
28
+ changed = true
29
+ while changed && !unresolved.empty?
30
+ changed = false
31
+ unresolved.delete_if { |k|
32
+ if expressions[k].all? { |var| result.key? var }
33
+ result[k] = expand_expr(result, dict[k])
34
+ changed = true
35
+ end
36
+ }
37
+ end
38
+ unresolved.empty? or raise "Unresolved variables: #{unresolved.join(", ")}"
39
+
40
+ result
41
+ end
42
+
43
+ # +value+ will typically be a dirs hash
44
+ def expand_object(dict, object)
45
+ case object
46
+ when Array; object.map { |v| expand_object(dict, v) }
47
+ when Hash
48
+ object.map { |k,v|
49
+ key = expand_expr(dict, k)
50
+ object = expand_object(dict, v)
51
+ [key, object]
52
+ }.to_h
53
+ when String
54
+ expand_expr(dict, object)
55
+ else
56
+ object
57
+ end
58
+ end
59
+
60
+ def expand_dirs(dict, dirs)
61
+ expand_object(dict, dirs)
62
+ end
63
+
@@ -0,0 +1,25 @@
1
+ module Qrpm
2
+ class RpmBuilder
3
+ def initialize
4
+ end
5
+
6
+ def build
7
+ # Create directories
8
+
9
+ # Collect sources
10
+
11
+ # Copy sources
12
+
13
+ # Create spec file
14
+ end
15
+
16
+
17
+ end
18
+
19
+
20
+
21
+
22
+ def render(dict, files)
23
+
24
+ end
25
+ end
data/lib/qrpm/rpm.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'erb'
2
+ require 'fileutils'
3
+
4
+ module Qrpm
5
+ class Rpm
6
+ # Defines the following member methods:
7
+ #
8
+ # name Package name
9
+ # version Version
10
+ # release Release
11
+ # license License (defaults to GPL)
12
+ # summary Short one-line description of package
13
+ # description Description
14
+ # packager Name of the packager (defaults to the value of the $USER
15
+ # environment variable)
16
+ # require Array of required packages
17
+ # make Controls the build process:
18
+ # null Search the top-level directory for configure or
19
+ # make files and runs them. Skip building if not
20
+ # found. This is the default
21
+ # true Expect the top-level directory to contain
22
+ # configure make files and runs them. It is an
23
+ # error if the Makefile is missing
24
+ # (array of commands)
25
+ # Runs the commands to build the project
26
+ #
27
+ FIELDS = %w(name version release group license summary description packager requires make)
28
+ MANDATORY_FIELDS = %w(name summary version)
29
+ TEMPLATE = "#{::File.dirname(__FILE__)}/template.erb"
30
+
31
+ RPM_DIRS = %w(SOURCES BUILD RPMS SPECS SRPMS tmp)
32
+
33
+ # Field accessor methods
34
+ FIELDS.each { |f| eval "def #{f}() @fields[\"#{f}\"] end" }
35
+
36
+ attr_reader :fields
37
+ attr_reader :nodes
38
+
39
+ # The content of the SPEC file
40
+ attr_reader :spec
41
+
42
+ def files() @files ||= nodes.select(&:file?) end
43
+ def links() @lines ||= nodes.select(&:link?) end
44
+
45
+ def has_configure?() ::File.exist? "configure" end
46
+ def has_make?() ::File.exist? "make" end
47
+
48
+ def initialize(fields, nodes, template: TEMPLATE)
49
+ @fields, @nodes = fields, nodes
50
+ @template = template
51
+ end
52
+
53
+ def build(target: :rpm, file: nil)
54
+ Dir.mktmpdir { |rootdir|
55
+ rootdir = "/home/clr/prj/qrpm/tmp"
56
+ FileUtils.rm_rf(rootdir)
57
+ FileUtils.mkdir_p(rootdir)
58
+
59
+ spec_file = file || "#{name}.spec"
60
+ tar_file = "#{name}.tar.gz"
61
+ spec_path = "#{rootdir}/SPECS/#{spec_file}"
62
+ tar_path = "#{rootdir}/SOURCES/#{tar_file}"
63
+
64
+ # Create directories
65
+ RPM_DIRS.each { |dir| FileUtils.mkdir_p "#{rootdir}/#{dir}" }
66
+
67
+ # Directory for tarball creation. This lives inside the RPM directory
68
+ # structure and is removed before we start rpmbuild
69
+ tarroot = "#{rootdir}/tmp/#{name}"
70
+ FileUtils.mkdir(tarroot)
71
+
72
+ # Copy files
73
+ FileUtils.cp_r(".", tarroot, preserve: true)
74
+
75
+ # Roll tarball and put it in the SOURCES directory
76
+ system "tar zcf #{tar_path} -C #{rootdir}/tmp #{name}" or raise "Can't roll tarball"
77
+
78
+ # Remove temporary tar dir
79
+ FileUtils.rm_rf tarroot
80
+
81
+ # Create spec file
82
+ renderer = ERB.new(IO.read(@template).sub(/^__END__\n.*/m, ""), trim_mode: "-")
83
+ @spec = renderer.result(binding)
84
+
85
+ # Emit spec or build RPM
86
+ if target == :spec
87
+ IO.write(spec_file, @spec)
88
+ else
89
+ IO.write(spec_path, @spec)
90
+ system "rpmbuild -v -ba --define \"_topdir #{rootdir}\" #{rootdir}/SPECS/#{name}.spec" or
91
+ raise "Failed building RPM file"
92
+ if target == :srpm
93
+ system "cp #{rootdir}/SRPMS/* ." or raise "Failed copying SRPM file"
94
+ elsif target == :rpm
95
+ system "cp #{rootdir}/RPMS/*/#{name}-[0-9]* ." or raise "Failed copying RPM file"
96
+ else
97
+ raise ArgumentError, "Not a valid value for :target - #{target.inspect}"
98
+ end
99
+ end
100
+ }
101
+ end
102
+
103
+ def dump
104
+ puts self.class
105
+ indent {
106
+ puts "fields"
107
+ indent { fields.each { |k,v| puts "#{k}: #{v.inspect}" } }
108
+ puts "nodes"
109
+ indent { nodes.map(&:dump) }
110
+ }
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,73 @@
1
+
2
+ Name: <%= name %>
3
+ Summary: <%= summary %>
4
+ Version: <%= version %>
5
+ Release: <%= release %>
6
+ License: <%= license %>
7
+ Packager: <%= packager %>
8
+ <% if group -%>
9
+ Group: <%= group %>
10
+ <% end -%>
11
+ <% for pck in requires || [] -%>
12
+ Requires: <%= pck %>
13
+ <% end -%>
14
+ Source: %{name}.tar.gz
15
+ BuildRoot: <%= rootdir %>/tmp/%{name}-%{version}
16
+
17
+ %description
18
+ <%= description %>
19
+
20
+ %prep
21
+ %setup -n <%= name %>
22
+
23
+ %build
24
+ <% if make.nil? -%>
25
+ <% if has_configure? -%>
26
+ ./configure
27
+ <% end -%>
28
+ <% if has_make? -%>
29
+ make
30
+ <% end -%>
31
+ <% elsif make == false -%>
32
+ <% elsif make == true -%>
33
+ <% if has_configure? -%>
34
+ ./configure
35
+ <% end -%>
36
+ make
37
+ <% elsif make.is_a? Array -%>
38
+ <% for cmd in make -%>
39
+ <%= cmd %>
40
+ <% end -%>
41
+ <% end -%>
42
+
43
+ %install
44
+ mkdir -p <%= nodes.map { |f| "%{buildroot}#{f.directory}" }.uniq.join(" ") %>
45
+ <% for file in files -%>
46
+ cp <%= file.file %> %{buildroot}<%= file.path %>
47
+ <% end -%>
48
+ <% for link in links -%>
49
+ touch %{buildroot}<%= link.path %>
50
+ <% end -%>
51
+
52
+ %files
53
+ <% for file in files -%>
54
+ <%= file.path %>
55
+ <% end -%>
56
+ <% for link in links -%>
57
+ %ghost <%= link.path %>
58
+ <% end -%>
59
+
60
+ %clean
61
+ %if "%{clean}" != ""
62
+ rm -rf %{_topdir}/BUILD/%{name}
63
+ [ $(basename %{buildroot}) == "%{name}-%{version}-%{release}.%{_target_cpu}" ] && rm -rf %{buildroot}
64
+ %endif
65
+
66
+ %post
67
+ <% for file in files.select(&:perm) -%>
68
+ chmod <%= file.perm %> <%= file.path %>
69
+ <% end -%>
70
+ <% for file in links -%>
71
+ ln -sf <%= link.link %> <%= link.path %>
72
+ <% end -%>
73
+
@@ -0,0 +1,88 @@
1
+
2
+ # Package information
3
+ #
4
+ name: # Name of package. It is used in the package name
5
+ summary: # Short summary of package
6
+ description: # Optional longer description
7
+ version: # Version
8
+ release: # Release. Optional
9
+ packager: # Packager, default $USER
10
+ requires: # List of required packages
11
+
12
+ # Build information
13
+ #
14
+ make: null # make can be undefined or null (use make if present), false
15
+ # (don't use make), true (use make), or a list of shell
16
+ # commands to build the project
17
+
18
+ # Directories, files, and links
19
+ #
20
+ # This section contains entries that are (possibly empty) directories with a
21
+ # array of files or links. Directories can either identify a builtin standard
22
+ # directory or be a path to a directory. In the typical case, the directory
23
+ # will contain a simple list of files from the build directory:
24
+ #
25
+ # bindir:
26
+ # - my_bin_files/my_program
27
+ # - my_sh_files/my_shell_script
28
+ #
29
+ # /opt/my_files:
30
+ # - src/my_data
31
+ #
32
+ # The example will create the following files and directories
33
+ #
34
+ # /usr/bin/my_program
35
+ # /usr/bin/my_shell_script
36
+ # /opt/my_files/
37
+ # /opt/my_files/my_data
38
+ #
39
+ # Files can also be specified using the following attributes
40
+ #
41
+ # name: Destination file name. Default is the last path component in :file
42
+ # file: Path to source file
43
+ # perm: Octal permissions. Defaults are the source file's permissions
44
+ #
45
+ # It is used like this
46
+ #
47
+ # /opt/my_files
48
+ # - name: data
49
+ # file: src/my_data
50
+ # perm: 600
51
+ #
52
+ # This will copy src/my_data to a 'data' file in the /opt/my_files directory
53
+ # with permissions 0600
54
+ #
55
+ # Links can only be specified using attributes
56
+ #
57
+ # name: Destination file name. Default is the last path component in :link
58
+ # link: Path to the file that will be pointed to by the link
59
+ #
60
+ # To create a symbolic link in /var/lib/ from my_app to /opt/my_files/data:
61
+ #
62
+ # libdir:
63
+ # - name: my_app
64
+ # link: /opt/my_files/data
65
+ #
66
+ # The following standard directories are defined:
67
+ #
68
+ # etcdir /etc Configuration files
69
+ # bindir /usr/bin Executables
70
+ # sbindir /usr/sbin System executables
71
+ # libdir /usr/lib Libraries (both binary and clear text)
72
+ # libexecdir /usr/libexec Executable subprograms (not meant to be
73
+ # called indepentently)
74
+ # sharedir /usr/share Constant data files. FIXME: Always a subdir
75
+ # vardir /var/lib Variable data files
76
+ # spooldir /var/spool Spool files
77
+ # rundir /var/run Run files
78
+ # lockdir /var/lock Lock files
79
+ # cachedir /var/cache Cache directory
80
+ # tmpdir /tmp Temporary directory (deleted when the '
81
+ # machine starts)
82
+ # logdir /var/log Log directory
83
+ #
84
+ # Each standard directory can also be prefixed a 'pck'. That will create a
85
+ # subdirectory with the package's name in the base standard directory. Eg.
86
+ # 'pcketcdir' will create the directory '/etc/<name>'
87
+ #
88
+
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qrpm
4
+ VERSION = "0.0.1"
5
+ end
data/lib/qrpm.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "qrpm/version"
4
+ require_relative "qrpm/node.rb"
5
+ require_relative "qrpm/rpm.rb"
6
+ require_relative "qrpm/parser.rb"
7
+
8
+ module Qrpm
9
+ class Error < RuntimeError; end
10
+
11
+ QRPM_CONFIG_FILE = "qrpm.yml"
12
+
13
+ QRPM_SHARE_DIR = "#{::File.dirname(__FILE__)}/../lib/qrpm"
14
+ QRPM_CONFIG_FILE_TEMPLATE = "#{QRPM_SHARE_DIR}/template.yml"
15
+ QRPM_ERB_FILE = "#{QRPM_SHARE_DIR}/template.erb"
16
+ end
data/packager.sh ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/bash
2
+
3
+ # This scripts creates and build a simple RPM package
4
+ #
5
+ # Prerequisites:
6
+ # - rpm-build, make and gcc (as it's a c file) packages must be installed
7
+ #
8
+
9
+ # Ref. http://aerostitch.github.io/linux_and_unix/RedHat/build_sample_rpm.html
10
+
11
+ # Holds the name of the root directory containing the necessary structure to
12
+ # build RPM packages.
13
+ RPM_ROOT_DIR=~/rpm_factory
14
+
15
+ PKG_NAME=dummy_package
16
+ PKG_TAR=/tmp/${PKG_NAME}.tar.gz
17
+ BINARY_FILE=hello_world
18
+ # Recreate the root directory and its structure if necessary
19
+ mkdir -p ${RPM_ROOT_DIR}/{SOURCES,BUILD,RPMS,SPECS,SRPMS,tmp}
20
+ pushd $RPM_ROOT_DIR
21
+ cp ${PKG_TAR} ${RPM_ROOT_DIR}/SOURCES/
22
+
23
+ # Creating a basic spec file
24
+ cat << __EOF__ > ${RPM_ROOT_DIR}/SPECS/${PKG_NAME}.spec
25
+ Summary: This package is a sample for quickly build dummy RPM package.
26
+ Name: $PKG_NAME
27
+ Version: 1.0
28
+ Release: 0
29
+ License: GPL
30
+ Packager: $USER
31
+ Group: Development/Tools
32
+ Source: %{name}.tar.gz
33
+ BuildRequires: coreutils
34
+ BuildRoot: ${RPM_ROOT_DIR}/tmp/%{name}-%{version}
35
+
36
+ %description
37
+ %{summary}
38
+
39
+ %prep
40
+ %setup -n ${PKG_NAME}
41
+
42
+ %build
43
+ make $BINARY_FILE
44
+
45
+ %install
46
+ mkdir -p "%{buildroot}/opt/${PKG_NAME}"
47
+ cp $BINARY_FILE "%{buildroot}/opt/${PKG_NAME}/"
48
+
49
+ %files
50
+ /opt/${PKG_NAME}/hello_world
51
+
52
+ %clean
53
+ %if "%{clean}" != ""
54
+ rm -rf %{_topdir}/BUILD/%{name}
55
+ [ $(basename %{buildroot}) == "%{name}-%{version}-%{release}.%{_target_cpu}" ] && rm -rf %{buildroot}
56
+ %endif
57
+
58
+ %post
59
+ chmod 755 -R /opt/${PKG_NAME}
60
+ __EOF__
61
+
62
+ rpmbuild -v -bb --define "_topdir ${RPM_ROOT_DIR}" SPECS/${PKG_NAME}.spec
63
+ popd
64
+
65
+
data/packager.yml ADDED
@@ -0,0 +1,32 @@
1
+
2
+ name: my_package_name$pg_version
3
+ summary: This is a summary of the package
4
+ description: Optional longer description of the package
5
+ version: 1.2.3
6
+ release: $pg_version.$perm
7
+ packager: null
8
+ requires:
9
+ - ruby
10
+ - apache
11
+ - postgres$pg_version
12
+
13
+ pg_version: 13
14
+ perm: 755
15
+ root: example
16
+
17
+ bindir:
18
+ - $root/bin/a_file
19
+ - $root/bin/another_file
20
+ - name: an_alias
21
+ file: $root/bin/a_file
22
+
23
+ sbindir:
24
+ - link: /bin/a_file
25
+
26
+ pcksharedir:
27
+ - $root/share/some_data
28
+
29
+ vardir:
30
+ - $root/share/some_other_data
31
+
32
+
data/program.sh ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/bash
2
+
3
+ # Ref. http://aerostitch.github.io/linux_and_unix/RedHat/build_sample_rpm.html
4
+
5
+ PKG_NAME=dummy_package
6
+ PKG_DIR=/tmp/${PKG_NAME}
7
+ mkdir -p ${PKG_DIR}
8
+
9
+ cat << __EOF__ > ${PKG_DIR}/hello_world.c
10
+ #include <stdio.h>
11
+ int main(){
12
+ printf("Hello world!\n");
13
+ return 0;
14
+ }
15
+ __EOF__
16
+
17
+ pushd ${PKG_DIR}/..
18
+ tar czvf ${PKG_NAME}.tar.gz ${PKG_NAME}
19
+ popd
data/qrpm.gemspec ADDED
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/qrpm/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "qrpm"
7
+ spec.version = Qrpm::VERSION
8
+ spec.authors = ["Claus Rasmussen"]
9
+ spec.email = ["claus.l.rasmussen@gmail.com"]
10
+
11
+ spec.summary = "Gem qrpm"
12
+ spec.description = "Gem qrpm"
13
+ spec.homepage = "http://www.nowhere.com/"
14
+ spec.required_ruby_version = ">= 2.4.0"
15
+
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "shellopts", "~> 2.0.0"
31
+ spec.add_dependency "indented_io"
32
+
33
+ # Uncomment to register a new dependency of your gem
34
+ # spec.add_dependency "example-gem", "~> 1.0"
35
+
36
+ # For more information and examples about making a new gem, checkout our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+
39
+ # Add your production dependencies here
40
+ # spec.add_dependency GEM [, VERSION]
41
+
42
+ # Add your development dependencies here
43
+ # spec.add_development_dependency GEM [, VERSION]
44
+
45
+ # Also un-comment in spec/spec_helper to use simplecov
46
+ # spec.add_development_dependency "simplecov"
47
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qrpm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Claus Rasmussen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-05-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: shellopts
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: indented_io
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Gem qrpm
42
+ email:
43
+ - claus.l.rasmussen@gmail.com
44
+ executables:
45
+ - qrpm
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".rspec"
50
+ - ".ruby-version"
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - bin/console
55
+ - bin/setup
56
+ - clean
57
+ - cmd
58
+ - example/bin/a_file
59
+ - example/bin/another_file
60
+ - example/qrpm.yml
61
+ - example/share/some_data
62
+ - example/share/some_other_data
63
+ - exe/qrpm
64
+ - lib/qrpm.rb
65
+ - lib/qrpm/node.rb
66
+ - lib/qrpm/parser.rb
67
+ - lib/qrpm/qrpm.rb
68
+ - lib/qrpm/render.rb
69
+ - lib/qrpm/rpm.rb
70
+ - lib/qrpm/template.erb
71
+ - lib/qrpm/template.yml
72
+ - lib/qrpm/version.rb
73
+ - packager.sh
74
+ - packager.yml
75
+ - program.sh
76
+ - qrpm.gemspec
77
+ homepage: http://www.nowhere.com/
78
+ licenses: []
79
+ metadata:
80
+ homepage_uri: http://www.nowhere.com/
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 2.4.0
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubygems_version: 3.1.4
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Gem qrpm
100
+ test_files: []