qrpm 0.0.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84aec760efd4d34c3de41e77edeeb5cc925ee195bea84243dad283c2ec50005e
4
- data.tar.gz: 99a8f384f3913952ce99ad80f0be8718d3cb4a91d882a5eb82675a5cc63b41b3
3
+ metadata.gz: ed3b4b8014d9d4c6c8ca2f32e5d9a1809c3580bf30e65109bb3211d5a1ab8894
4
+ data.tar.gz: 8266de1abdbbcb6bfe1c1b17eeb88a511a1d7901aa24fe966c9d4a36a401468e
5
5
  SHA512:
6
- metadata.gz: 7416eba4e7747d1fb5603d62a985671e2b8ba40c90d95636c737dbd1c998a3431d2ffeba919e5cff1575efe8dd88b3f43173bddf48e22a3de7cae2e5c30ed868
7
- data.tar.gz: 17108a42af16ffe022c72dda457d4d868e16e98a807e1e61296df1a9f2da02cf7a0ef3322334d04b30b85e782723587bad7b6bb15b537fc4d339fba1c14bc6ae
6
+ metadata.gz: 0223c49eea6b54208c2581ab434a13f8fb1853a44b8f53142401f9d781ff1f490b5b27833a6b63e2efe0881feec546c4549c89d1345e5fb531ddf9a41651b987
7
+ data.tar.gz: b495af8ac986d3032b764bc1cdac6200f57b2f0d967c1950de7edc6da895f21d5c1ce623185d3d98c45ceb18a4b269e2c63f204ae1701d1f460154bb6495cc84
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.7.1
1
+ ruby-3.1.2
data/NOTES ADDED
@@ -0,0 +1,7 @@
1
+
2
+ Random notes that should make it into the documention
3
+
4
+ o Directory nodes are top-level array definitions, optionally suffix with a /
5
+ o Only DirectoryNode keys can include a '/'
6
+ o Only DirectoryNode keys can include variables. What about this:
7
+ o DirectoryNodes can't be referenced
data/TODO ADDED
@@ -0,0 +1,30 @@
1
+ o Rule: Symbol keys are variables, String keys are directories
2
+
3
+ o Use Nodes everywhere -> makes a lot of stuff much easier
4
+
5
+ o Check "dir: file" vs. "dir:\n - file"
6
+
7
+ o Allow shell escapes to return arrays and hashes
8
+
9
+ o Allow directories within directories:
10
+ dir/
11
+ - file
12
+ - subdir/
13
+ - element # Oops: Illegal YAML syntax
14
+
15
+ o What happens if directory declarations maps to the same:
16
+ dir1: dir
17
+ dir2: dir
18
+ $dir1:
19
+ - file
20
+ $dir2:
21
+ - file
22
+
23
+ o Use same naming everywhere: field vs. value, name vs. path etc.
24
+ - "fields" are variables that also are RPM fields
25
+ - "variables" are QRPM variables
26
+
27
+ o Better references to source in error messages: Read input file(s) in parallel
28
+ with parsing of the YAML document (doesn't work with YAML merge/include). Maybe
29
+ decorate strings with lineno/charno and if the YAML module fails we catch the
30
+ error and remove the decoration from the error message
data/doc/pg.yml ADDED
@@ -0,0 +1,37 @@
1
+
2
+ # Default Redhat Postgres definititions
3
+ pg:
4
+ name: "postgres" # Name of the package. It is also the default name for package-specific diretories
5
+ vendor: "redhat"
6
+ version: null # To be specified explicitly or detected dynamically using detect.pg.version
7
+ major_version: $(sed 's/\..*//' <<<${{pg.version}})
8
+ pckdir: pgsql
9
+ etcdir: $pg.vardir/data
10
+ vardir: $vardir/$pg.pckdir
11
+ libdir: $libdir/$pg.pckdir # Assuming libdir points to /usr/lib64
12
+ extdir: $pg.libdir/extension
13
+ sharedir: $sharedir/$pg.pckdir
14
+
15
+ conf_file: $pg.etcdir/postgresql.conf
16
+ hba_file: $pg.etcdir/pg_hba.conf
17
+ ident_file: $pg.etcdir/pg_ident.conf
18
+
19
+ # Detections
20
+ detect:
21
+ pg:
22
+ version: $(pg_config --version | sed 's/^[^0-9]* \([0-9]\+\).*$/\1/')
23
+
24
+ # pgdg overrides
25
+ pg:
26
+ name: postgresql$pg.version
27
+ vendor: "pgdg"
28
+ version: null
29
+ vardir: $vardir/$pg.pckdir/$pg.major_version
30
+ usrdir: /usr/pgsql-$pg.major_version
31
+ libdir: $pg.usrdir/lib
32
+ extdir: $pg.libdir/extension
33
+ sharedir: $pg.usrdir/share
34
+
35
+ pg.version: $detect.pg.version
36
+
37
+
data/doc/qrpm2.rb ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+
5
+ p YAML.load(IO.read("t.yml"))
6
+
7
+ exit
8
+
9
+
10
+
11
+
12
+
13
+ require 'indented_io'
14
+
15
+ s = "member"
16
+
17
+ s =~ /^(\w+)|\[(\d+)\](?:\.|$)/
18
+ p $1
19
+ p $2
20
+
21
+
22
+ __END__
23
+
24
+ a = "1. $a 2. \\$a 3. \\\\$a 4. \\\\\\$a 5. \\\\\\\\$a rest"
25
+ b = "1. ${a} 2. \\${a} 3. \\\\${a} 4. \\\\\\${a} 5. \\\\\\\\${a} rest"
26
+ c = "1. $(a)"
27
+ d = "1. $a $(b $b ${b} ${{b}}) $c \\"
28
+
29
+ IDENT_RE = /(?:[\w_][\w\d_.]*)/
30
+
31
+ # Return an array of prefix/interpolated-variable tuples. The prefix is the
32
+ # string leading up to the variable. $NAME, ${NAME}, and $(COMMAND)
33
+ # interpolations are recognized
34
+ def parse_string(path, string)
35
+ r = string.scan(/(.*?)(\\*)(\$#{IDENT_RE}|\$\{#{IDENT_RE}\}|\$\(.+\)|$)/).map {
36
+ |prefix, backslashes, interpolation|
37
+ p [prefix, backslashes, interpolation]
38
+
39
+
40
+ str = prefix + '\\' * (backslashes.size / 2)
41
+ if backslashes.size % 2 == 0
42
+ var = interpolation
43
+ else
44
+ str += '\\' * (backslashes.size % 2) + interpolation
45
+ end
46
+ [str, var]
47
+ }[0..-2]
48
+ puts
49
+ r
50
+ end
51
+
52
+ #parse_string("a", a).each { |e| p e }
53
+ #exit
54
+
55
+ for s in [a, b, c, d]
56
+ puts "\"#{s}\""
57
+ indent {
58
+ parse_string("fake", s).each { |a|
59
+ p a
60
+ }
61
+ }
62
+ puts
63
+ end
64
+
65
+ #p a.scan(/\S+\s\S+/)
66
+
67
+
68
+ exit
69
+
data/doc/qrpm2.yml ADDED
@@ -0,0 +1,55 @@
1
+ # Qrpm with "functions"
2
+ ---
3
+
4
+ # User-code
5
+ #
6
+ pg:
7
+ vendor: pgdg
8
+
9
+ $user_dir:
10
+ - $pg.postgresql_conf
11
+
12
+ # Standard global variables
13
+ # platform (redhat/debian/etc)
14
+ # vendor (only defined for third-party packages)
15
+ # domain (the network)
16
+ # host (the host)
17
+ #
18
+ # The standard variables are ordered
19
+
20
+ pg:
21
+ etcdir: $(detect)
22
+ datadir: $(detect)
23
+ postgresql_conf: ${pg.etcdir}/postgresql.conf
24
+ pg_hba_conf: ${pg.etcdir}/pg_hba.conf
25
+ pg_ident_conf: ${pg.etcdir}/pg_ident.conf
26
+
27
+ pg(platform=redhat):
28
+ etcdir: ${pg.datadir}
29
+ datadir: $pcklidir/data
30
+
31
+ pg(platform=debian):
32
+ etcdir: $pcketcdir
33
+ datadir: /var/lib/pgsql/data
34
+
35
+ # 'plaform=*' to make this more specific than the default. Not needed if
36
+ # standard variables are ordered
37
+ pg(platform=*,vendor=pgdg):
38
+ datadir: $pcklibdir/${pg.version}/data
39
+
40
+ pg(platform=debian,vendor=pgdg):
41
+ etcdir: $pcketcdir/${pg.version}
42
+
43
+ pg(platform=redhat,vendor=pgdg):
44
+ etcdir: ${pg.datadir}
45
+
46
+ # nested expressions
47
+ #
48
+ pg(vendor=pgdg):
49
+ datadir: $pcklibdir/${pg.version}/data
50
+ platform=redhat:
51
+ etcdir: ${pg.datadir}
52
+ platform=debian:
53
+ etcdir: $pckectdir/${pg.version}
54
+
55
+
data/example/configure ADDED
File without changes
data/example/make ADDED
File without changes
@@ -0,0 +1,49 @@
1
+
2
+ Name: my_package_name
3
+ Summary: This is a summary of the package
4
+ Version: 1.2.3
5
+ Release: 4
6
+ License: GPL
7
+ Packager: clr
8
+ Requires: ruby
9
+ Requires: httpd
10
+ Requires: postgresql13
11
+ Source: %{name}.tar.gz
12
+ BuildRoot: /tmp/d20220502-22446-8neiew/tmp/%{name}-%{version}
13
+
14
+ %description
15
+ Optional longer description of the package
16
+
17
+ %prep
18
+ %setup -n my_package_name
19
+
20
+ %build
21
+ my_configure; my_make
22
+
23
+ %install
24
+ mkdir -p %{buildroot}/usr/bin %{buildroot}/usr/sbin %{buildroot}/usr/share/my_package_name %{buildroot}/var/lib
25
+ cp bin/a_file %{buildroot}/usr/bin/a_file
26
+ cp bin/another_file %{buildroot}/usr/bin/another_file
27
+ cp bin/a_file %{buildroot}/usr/bin/an_alias
28
+ cp share/some_data %{buildroot}/usr/share/my_package_name/some_data
29
+ cp share/some_other_data %{buildroot}/var/lib/some_other_data
30
+ touch %{buildroot}/usr/sbin/a_file
31
+
32
+ %files
33
+ /usr/bin/a_file
34
+ /usr/bin/another_file
35
+ /usr/bin/an_alias
36
+ /usr/share/my_package_name/some_data
37
+ /var/lib/some_other_data
38
+ %ghost /usr/sbin/a_file
39
+
40
+ %clean
41
+ %if "%{clean}" != ""
42
+ rm -rf %{_topdir}/BUILD/%{name}
43
+ [ $(basename %{buildroot}) == "%{name}-%{version}-%{release}.%{_target_cpu}" ] && rm -rf %{buildroot}
44
+ %endif
45
+
46
+ %post
47
+
48
+ ln -sf /bin/a_file /usr/sbin/a_file
49
+
data/example.yml ADDED
@@ -0,0 +1,84 @@
1
+ # QRPM configuration file. See https://github.com/clrgit/qrpm
2
+
3
+ # program ::= directory...
4
+ # directory ::= field... directory...
5
+ # field ::= key '*' value
6
+ # directory ::= array(string)
7
+ #
8
+ # TODO
9
+ # o Use '@' instead of '$'. Yields @name and @{name} that doesn't interfere
10
+ # with bash expansion
11
+ #
12
+ #
13
+ # ${{name}} in $(...)
14
+ # QRPM dependency check variable definitions and needs to be able to detect
15
+ # variable usages in $(...) constructs
16
+
17
+ # @include git-project
18
+ # -> version: $(cd ${{srcdir}}; git tag | tail -1 | sed 's/^v//')
19
+ #
20
+ # @include postgres-project prefix: pg_
21
+ # -> pg_name
22
+ # pg_version
23
+ # pg_libdir
24
+ # pg_sharedir
25
+ #
26
+ # @include postgres-project git@github.com:... commit-id
27
+ #
28
+ # @include redhat/httpd
29
+ # @include redhat/pg
30
+ # @include pgdg
31
+ #
32
+ # pg.version: 14
33
+ # pg: pgdg[14]
34
+
35
+ name: $pg_name-url_encode
36
+ summary: Adds the 'url_encode' extension to postgres ${pg.version}
37
+ description: RPM wrapper for the postgres url_encode extension (https://github.com/okbob/url_encode)
38
+ version: $(cd ${{srcdir}}; git tag | tail -1 | sed 's/^v//')
39
+ # ^Oops, hardcoded FIXME: Have a dependency graph and use some standard algorithm
40
+
41
+ include:
42
+ - ./qrpm.includes
43
+
44
+ requires:
45
+ - $pg_name-server
46
+ - $pg_name-libs
47
+
48
+ a: $b
49
+ b: $c
50
+ c: $a
51
+ # Idea
52
+ #submod: url_encode
53
+ #subdir: url_encode
54
+ #patches:
55
+ # - patch/patch1.patch
56
+ srcdir: url_encode
57
+
58
+ root: ""
59
+
60
+ pg:
61
+ name: $(rpm -q --qf '%{NAME}\n' -f $(readlink -f $(which pg_config)))
62
+ version: $(pg_config --version | sed 's/^[^0-9]* \([0-9]\+\).*$/\1/')
63
+ major: $version
64
+ libdir: $(pg_config --libdir)
65
+ sharedir: $(pg_config --sharedir)
66
+
67
+ #init: # FIXME Doesn't work atm
68
+ # - git submodule init
69
+ # - git submodule update
70
+
71
+ make:
72
+ - cd $srcdir; make
73
+
74
+ ${pg.sharedir}/extension:
75
+ - $srcdir/url_encode.control
76
+ - $srcdir/sql/url_encode--1.2.sql
77
+
78
+ ${pg.libdir}:
79
+ - $srcdir/src/url_encode.so
80
+ - $srcdir/postgresql$version
81
+
82
+ $root/somedir:
83
+ - $srcdir/somefile
84
+
data/exe/qrpm CHANGED
@@ -7,30 +7,69 @@ require_relative '../lib/qrpm.rb'
7
7
 
8
8
  require 'yaml'
9
9
  require 'shellopts'
10
- require 'indented_io'
11
10
 
12
11
  # TODO
13
12
  # o Fix BuildRoot (contains absolute path)
14
- # o Enable escape of $
15
- # o Separate standard variable from user-variables in dump
13
+ #
14
+ # + Separate standard variables from user-variables in dump
15
+ # + Enable escape of $
16
+ # + Support for $(...) constructs
16
17
 
17
18
  begin
18
19
  SPEC = %(
19
- @ Quick RPM builder
20
+ @ Make simple RPMs simple
20
21
 
21
- 'qrpm' creates a RPM package from a simple YAML specification file
22
+ -- VARIABLE=VALUE... [QRPM-FILE]
22
23
 
23
- A template YAML qrpm configuration file can be generated by the --template
24
- option. It is in YAML format with the extension that a single '__END__'
25
- terminates the file and that $NAME or ${NAME} are variables that will be
26
- expanded. The variables can either be specified in the configuration file
27
- or given on the command line in <variable>=<value> format
24
+ 'qrpm' creates a RPM package from a qrpm.yml specification file. It aims at
25
+ packaging shell scripts or simple executables/libraries with minimum effort
28
26
 
29
- -- VARIABLE=VALUE... [QRPM-FILE]
27
+ The qrpm.yml specification file is a YAML file. The simplest qrpm file
28
+ contains just one line:
30
29
 
31
- -t,template=OFILE?
32
- Generate a template qrpm.yml file in the current directory. Customize it
33
- to create RPM packages of your project
30
+ $bindir: my_executable_script
31
+
32
+ Running qrpm using this file will yield a RPM package that installs the
33
+ script into the standard /usr/bin directory. The name of the package
34
+ is set to the name of the current directory and version to the latest tag
35
+ in git (which needs to be present). Other defaults are detailed below
36
+
37
+ VARIABLES
38
+
39
+ The configuration file can define and use variables. They are defined by
40
+ key/value definitions and the value can refer to values of other
41
+ variables using $NAME or ${NAME}. Variables can also be given on the
42
+ command line in <variable>=<value> format
43
+
44
+ $(...) constructs are commands that are executed by bash(1). The parser
45
+ considers everything from the opening '$(' to the last ')' on the line as
46
+ part of the command so only one command is allowed. This restriction keeps
47
+ the parser simple, it may change in the future
48
+
49
+ INCLUDE FILES
50
+
51
+ The qrpm file can include other files that are searched for in a list of
52
+ directories. Relative paths are relative to the directory of the qrpm file
53
+ (but see the -C option). The search directories can be set on the command
54
+ line using the -I option
55
+
56
+ BUILT-IN VARIABLES
57
+
58
+ INSTALLATION DIRECTORIES
59
+
60
+ OPTIONS
61
+
62
+ -f,force
63
+ Create package even if repository is dirty. Normally qrpm checks if the
64
+ current directory is clean
65
+
66
+ -C,directory=EDIR
67
+ Change to directory before doing anything else but include the current
68
+ directory in the search path. This makes it possible to override parts of
69
+ a spec file
70
+
71
+ +I,include=EDIR
72
+ Include directory, later definitions are searched first
34
73
 
35
74
  -s,spec=OFILE?
36
75
  Only create the spec file and not the RPM package. Use this option to
@@ -39,62 +78,115 @@ begin
39
78
  -S,source
40
79
  Create a source RPM file instead of a regular RPM file
41
80
 
42
- -f,force
43
- Create package even if repository is dirty. Normally qrpm checks if the
44
- current directory is a Git directory and then if there are no changed
45
- files
81
+ -t,template=OFILE?
82
+ Generate a QRPM template. It is in YAML format with the extension that a
83
+ single '__END__' terminates the file immediately. The name of the file
84
+ defaults to 'qrpm.yml'. It is an error if the file exists
46
85
 
47
- -C,directory=EDIR
48
- Change to directory before doing anything else
86
+ -T,force-template=OFILE?
87
+ Like --template but overwrites file if it exists
88
+
89
+ -b,builddir=NPATH?
90
+ Use the given path as the RPM build dir, default is 'builddir'. Doesn't
91
+ remove the directory afterwards. It it is an error if the directory exists
92
+
93
+ -B,force-builddir=PATH?
94
+ Like --builddir but overwrites the directory if it exists beforehand
49
95
 
50
96
  -d,dump
51
- Dump internal data and exit
97
+ Dump internal data and exit. For debug
52
98
  )
53
99
 
54
- opts, args = ShellOpts.process(SPEC, ARGV)
100
+ opts, args = ShellOpts.process(SPEC, ARGV, verbose: true, quiet: true)
55
101
 
56
- Dir.chdir(opts.directory) if opts.directory?
57
-
58
- if opts.template?
59
- outfile = opts.template || Qrpm::QRPM_CONFIG_FILE
102
+ if opts.template? || opts.force_template?
103
+ outfile = opts.template || opts.force_template || Qrpm::QRPM_CONFIG_FILE
104
+ opts.force_template? || !File.exists?(outfile) or ShellOpts.error "Won't overwrite existing file: #{outfile}"
60
105
  FileUtils::cp Qrpm::QRPM_CONFIG_FILE_TEMPLATE, outfile
106
+ puts "Generated #{outfile}" if !opts.quiet?
61
107
  exit
62
108
  end
63
109
 
64
- # Collect var=val settings in the dict hash and sets the configuration file
65
- dict = {}
110
+ # Process arguments. The overrides hash is constructed from var=val arguments
111
+ # on the command line
112
+ overrides = {}
113
+ file = nil
66
114
  while arg = args.extract(0..1)
67
115
  if arg =~ /^(.*?)=(.*)$/
68
- dict[$1] = $2
69
- else
116
+ overrides[$1] = $2
117
+ elsif file.nil?
70
118
  file = arg
71
- break
119
+ else
120
+ args.expect(-1, "More than one file argument")
72
121
  end
73
122
  end
74
- args.empty? or args.expect(0) # Generates an illegal-number-of-arguments error
123
+ args.expect(0)
124
+
125
+ # Compute/normalize currdir and qrpmdir and add them to the dictionary
126
+ currdir = overrides["currdir"] = File.expand_path(overrides["currdir"] || Dir.getwd)
127
+ qrpmdir = overrides["qrpmdir"] = File.expand_path(overrides["qrpmdir"] || opts.directory || ".")
128
+
129
+ # Compute builddir
130
+ if opts.builddir? && opts.force_builddir?
131
+ ShellOpts.error "Can't use both --builddir and --force-builddir"
132
+ elsif opts.builddir? || opts.force_builddir?
133
+ builddir = opts.builddir || opts.force_builddir || "builddir"
134
+ opts.force_builddir? || !File.exist?(builddir) or
135
+ ShellOpts.error "Build directory 'builddir' exists - use -B to override"
136
+ builddir = File.expand_path(builddir)
137
+ else
138
+ builddir = nil
139
+ end
140
+
141
+ # Check if repository is clean
142
+ opts.force? || opts.dump? || `git status --porcelain | grep -v '??' 2>/dev/null` == "" or
143
+ ShellOpts.error "Repository is dirty"
75
144
 
76
145
  # Check configuration file
77
146
  file ||= Qrpm::QRPM_CONFIG_FILE
78
- ::File.exist?(file) or raise "Can't find '#{file}'"
147
+ ::File.exist?(file) or ShellOpts.error "Can't find '#{file}'"
148
+
149
+ # Create lexer
150
+ lexer = Qrpm::Lexer.new([currdir, qrpmdir].uniq, opts.include.reverse)
79
151
 
80
152
  # Load the qrpm configuration file
81
- yaml = YAML.load(IO.read(file).sub(/^__END__\s*$/m, ""))
153
+ conf = lexer.lex(File.expand_path file)
154
+
155
+ # Change to qrpm directory
156
+ Dir.chdir(qrpmdir)
82
157
 
83
- # Parse QRPM file
84
- rpm = Qrpm::Parser.parse(dict, yaml)
158
+ # Parse QRPM configuration file. Include paths are still resolved with the
159
+ # context of the original directory while filesystem paths are relative to
160
+ # the source directory
161
+ compiler = Qrpm::Compiler.new(overrides)
162
+ qrpm = compiler.compile(conf)
163
+ rpm = qrpm.rpm
85
164
 
86
165
  if opts.dump?
87
- rpm.dump
166
+ puts "Compiler"
167
+ indent { compiler.dump }
168
+
169
+ puts "Qrpm"
170
+ indent { qrpm.dump_parts }
171
+
172
+ puts "Rpm"
173
+ indent { rpm.dump }
174
+
88
175
  exit
89
176
  end
90
177
 
91
- # Check if repository is clean
92
- opts.force? || `git status --porcelain 2>/dev/null` == "" or raise "Repository is dirty"
93
-
178
+ # Create spec/srpm/rpm file
94
179
  target = (opts.spec? ? :spec : (opts.source? ? :srpm : :rpm))
95
- rpm.build(target: target, file: opts.spec)
180
+ files = rpm.build(
181
+ target: target,
182
+ file: opts.spec,
183
+ verbose: opts.verbose?,
184
+ destdir: currdir,
185
+ builddir: builddir)
186
+
187
+ puts "Built #{files.map { |f| File.basename(f) }.join(" ")}" if !opts.quiet?
96
188
 
97
189
  rescue RuntimeError => ex
98
- ShellOpts.error ex.message
190
+ ShellOpts.failure ex.message
99
191
  end
100
192