fpm 1.16.0 → 1.18.0
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 +4 -4
- data/CHANGELOG.rst +23 -0
- data/lib/fpm/command.rb +6 -3
- data/lib/fpm/package/cpan.rb +89 -27
- data/lib/fpm/package/deb.rb +39 -6
- data/lib/fpm/package/dir.rb +0 -4
- data/lib/fpm/package/gem.rb +1 -1
- data/lib/fpm/package/pacman.rb +8 -4
- data/lib/fpm/package/pyfpm/parse_requires.py +24 -0
- data/lib/fpm/package/python.rb +404 -176
- data/lib/fpm/package/rpm.rb +8 -4
- data/lib/fpm/package/virtualenv.rb +26 -2
- data/lib/fpm/package.rb +5 -6
- data/lib/fpm/rake_task.rb +30 -4
- data/lib/fpm/util.rb +23 -10
- data/lib/fpm/version.rb +1 -1
- data/templates/sh.erb +1 -1
- metadata +11 -11
- data/lib/fpm/package/pyfpm/get_metadata.py +0 -115
data/lib/fpm/package/rpm.rb
CHANGED
|
@@ -156,7 +156,7 @@ class FPM::Package::RPM < FPM::Package
|
|
|
156
156
|
|
|
157
157
|
option "--macro-expansion", :flag,
|
|
158
158
|
"install-time macro expansion in %pre %post %preun %postun scripts " \
|
|
159
|
-
"(see: https://rpm.
|
|
159
|
+
"(see: https://rpm-software-management.github.io/rpm/manual/scriptlet_expansion.html)", :default => false
|
|
160
160
|
|
|
161
161
|
option "--verifyscript", "FILE",
|
|
162
162
|
"a script to be run on verification" do |val|
|
|
@@ -175,7 +175,7 @@ class FPM::Package::RPM < FPM::Package
|
|
|
175
175
|
rpm_trigger = []
|
|
176
176
|
option "--trigger-#{trigger_type}", "'[OPT]PACKAGE: FILEPATH'", "Adds a rpm trigger script located in FILEPATH, " \
|
|
177
177
|
"having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. " \
|
|
178
|
-
"See:
|
|
178
|
+
"See: https://rpm-software-management.github.io/rpm/manual/triggers.html" do |trigger|
|
|
179
179
|
match = trigger.match(/^(\[.*\]|)(.*): (.*)$/)
|
|
180
180
|
@logger.fatal("Trigger '#{trigger_type}' definition can't be parsed ('#{trigger}')") unless match
|
|
181
181
|
opt, pkg, file = match.captures
|
|
@@ -199,8 +199,8 @@ class FPM::Package::RPM < FPM::Package
|
|
|
199
199
|
# If and only if any of the above are done, then also replace ' with \', " with \", and \ with \\\\
|
|
200
200
|
# to accommodate escape and quote processing that rpm will perform in that case (but not otherwise)
|
|
201
201
|
def rpm_fix_name(name)
|
|
202
|
-
if name.match?(/[ \t
|
|
203
|
-
name = name.gsub(/(\ |\t|\[|\]|\*|\?|\%|\$|'|"|\\)/, {
|
|
202
|
+
if name.match?(/[ \t*?%${}\[\]]/)
|
|
203
|
+
name = name.gsub(/(\ |\t|\[|\]|\*|\?|\%|\$|'|"|\{|\}|\\)/, {
|
|
204
204
|
' ' => '?',
|
|
205
205
|
"\t" => '?',
|
|
206
206
|
'%' => '[%]',
|
|
@@ -209,6 +209,10 @@ class FPM::Package::RPM < FPM::Package
|
|
|
209
209
|
'*' => '[*]',
|
|
210
210
|
'[' => '[\[]',
|
|
211
211
|
']' => '[\]]',
|
|
212
|
+
#'{' => '[\{]',
|
|
213
|
+
#'}' => '[\}]',
|
|
214
|
+
'{' => '?',
|
|
215
|
+
'}' => '?',
|
|
212
216
|
'"' => '\\"',
|
|
213
217
|
"'" => "\\'",
|
|
214
218
|
'\\' => '\\\\\\\\',
|
|
@@ -36,7 +36,7 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
|
36
36
|
:default => nil
|
|
37
37
|
|
|
38
38
|
option "--setup-install", :flag, "After building virtualenv run setup.py install "\
|
|
39
|
-
"useful when building a virtualenv for packages and including their requirements from "
|
|
39
|
+
"useful when building a virtualenv for packages and including their requirements from "\
|
|
40
40
|
"requirements.txt"
|
|
41
41
|
|
|
42
42
|
option "--system-site-packages", :flag, "Give the virtual environment access to the "\
|
|
@@ -158,6 +158,31 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
|
158
158
|
end
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
+
# [2025-09-30] virtualenv-tools seems broken?
|
|
162
|
+
# The --update-path will look for a VIRTUAL_ENV= line in bin/activate,
|
|
163
|
+
# however, the version I tested looks for it with quotations, like VIRTUAL_ENV='
|
|
164
|
+
# And at time of writing, my `virtualenv` tool doesn't use quotations on this variable
|
|
165
|
+
#
|
|
166
|
+
# Maybe best case we can patch it here instead. The path update tool
|
|
167
|
+
# looks for the original virtualenv path and I think updates any bin
|
|
168
|
+
# files which point to it.
|
|
169
|
+
patched = []
|
|
170
|
+
activate_bin = File.join(virtualenv_build_folder, "bin/activate")
|
|
171
|
+
fd = File.open(activate_bin)
|
|
172
|
+
fd.each_line do |line|
|
|
173
|
+
re = /^VIRTUAL_ENV=([^'"].*)$/
|
|
174
|
+
match = line.match(re)
|
|
175
|
+
if match
|
|
176
|
+
# Quote the VIRTUAL_ENV var assignment to help virtualenv-tools work?
|
|
177
|
+
patched << "VIRTUAL_ENV='#{match}'\n"
|
|
178
|
+
else
|
|
179
|
+
patched << line
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
fd.close
|
|
183
|
+
File.write(activate_bin, patched.join)
|
|
184
|
+
|
|
185
|
+
# Rewrite the base path inside the virtualenv to prepare it to be packaged.
|
|
161
186
|
::Dir.chdir(virtualenv_build_folder) do
|
|
162
187
|
safesystem("virtualenv-tools", "--update-path", virtualenv_folder)
|
|
163
188
|
end
|
|
@@ -191,7 +216,6 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
|
191
216
|
dir.input(".")
|
|
192
217
|
@staging_path = dir.staging_path
|
|
193
218
|
dir.cleanup_build
|
|
194
|
-
|
|
195
219
|
end # def input
|
|
196
220
|
|
|
197
221
|
# Delete python precompiled files found in a given folder.
|
data/lib/fpm/package.rb
CHANGED
|
@@ -3,7 +3,6 @@ require "fpm/util" # local
|
|
|
3
3
|
require "pathname" # stdlib
|
|
4
4
|
require "find"
|
|
5
5
|
require "tmpdir" # stdlib
|
|
6
|
-
require "ostruct"
|
|
7
6
|
require "backports/latest"
|
|
8
7
|
require "socket" # stdlib, for Socket.gethostname
|
|
9
8
|
require "shellwords" # stdlib, for Shellwords.escape
|
|
@@ -227,7 +226,7 @@ class FPM::Package
|
|
|
227
226
|
def converted_from(origin)
|
|
228
227
|
# nothing to do by default. Subclasses may implement this.
|
|
229
228
|
# See the RPM package class for an example.
|
|
230
|
-
end # def
|
|
229
|
+
end # def converted_from
|
|
231
230
|
|
|
232
231
|
# Add a new source to this package.
|
|
233
232
|
# The exact behavior depends on the kind of package being managed.
|
|
@@ -325,7 +324,7 @@ class FPM::Package
|
|
|
325
324
|
|
|
326
325
|
def template_dir
|
|
327
326
|
File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "templates"))
|
|
328
|
-
end
|
|
327
|
+
end # def template_dir
|
|
329
328
|
|
|
330
329
|
def template(path)
|
|
331
330
|
template_path = File.join(template_dir, path)
|
|
@@ -438,7 +437,7 @@ class FPM::Package
|
|
|
438
437
|
|
|
439
438
|
help = "(#{type} only) #{help}"
|
|
440
439
|
@options << [flag, param, help, options, block]
|
|
441
|
-
end # def
|
|
440
|
+
end # def option
|
|
442
441
|
|
|
443
442
|
# Apply the options for this package on the clamp command
|
|
444
443
|
#
|
|
@@ -511,7 +510,7 @@ class FPM::Package
|
|
|
511
510
|
File.chmod(0755, out)
|
|
512
511
|
end
|
|
513
512
|
end
|
|
514
|
-
end
|
|
513
|
+
end # def write_scripts
|
|
515
514
|
|
|
516
515
|
# Get the contents of the script by a given name.
|
|
517
516
|
#
|
|
@@ -548,7 +547,7 @@ class FPM::Package
|
|
|
548
547
|
else
|
|
549
548
|
@provides = value
|
|
550
549
|
end
|
|
551
|
-
end
|
|
550
|
+
end # def provides=
|
|
552
551
|
|
|
553
552
|
# General public API
|
|
554
553
|
public(:type, :initialize, :convert, :input, :output, :to_s, :cleanup, :files,
|
data/lib/fpm/rake_task.rb
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
require "fpm/namespace"
|
|
2
|
-
require "ostruct"
|
|
3
2
|
require "rake"
|
|
4
3
|
require "rake/tasklib"
|
|
5
4
|
|
|
6
5
|
class FPM::RakeTask < Rake::TaskLib
|
|
6
|
+
class Options
|
|
7
|
+
attr_accessor :args
|
|
8
|
+
|
|
9
|
+
def initialize(defaults=nil)
|
|
10
|
+
if defaults.nil?
|
|
11
|
+
@h = Hash.new
|
|
12
|
+
else
|
|
13
|
+
@h = defaults
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def method_missing(m, *args)
|
|
18
|
+
if m.end_with?("=")
|
|
19
|
+
raise ArgumentError, "#{self.class.name}##{m} ... Expected 1 arg, got #{args.length}" if args.length != 1
|
|
20
|
+
@h[m[0...-1]] = args[0]
|
|
21
|
+
else
|
|
22
|
+
raise ArgumentError, "Expected 0 arg, got #{args.length}" if args.length != 0
|
|
23
|
+
return @h[m]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_h
|
|
28
|
+
return @h
|
|
29
|
+
end
|
|
30
|
+
end # Options
|
|
31
|
+
|
|
7
32
|
attr_reader :options
|
|
8
33
|
|
|
9
34
|
def initialize(package_name, opts = {}, &block)
|
|
10
|
-
|
|
35
|
+
#@options = OpenStruct.new(:name => package_name.to_s)
|
|
36
|
+
@options = Options.new(:name => package_name.to_s)
|
|
11
37
|
@source, @target = opts.values_at(:source, :target).map(&:to_s)
|
|
12
38
|
@directory = File.expand_path(opts[:directory].to_s)
|
|
13
39
|
|
|
@@ -18,8 +44,8 @@ class FPM::RakeTask < Rake::TaskLib
|
|
|
18
44
|
|
|
19
45
|
task(options.name) do |_, task_args|
|
|
20
46
|
block.call(*[options, task_args].first(block.arity)) if block_given?
|
|
21
|
-
abort("Must specify args")
|
|
22
|
-
@args = options.
|
|
47
|
+
abort("Must specify args") if options.args.nil?
|
|
48
|
+
@args = options.args
|
|
23
49
|
run_cli
|
|
24
50
|
end
|
|
25
51
|
end
|
data/lib/fpm/util.rb
CHANGED
|
@@ -38,7 +38,7 @@ module FPM::Util
|
|
|
38
38
|
shell = ENV["SHELL"]
|
|
39
39
|
return "/bin/sh" if shell.nil? || shell.empty?
|
|
40
40
|
return shell
|
|
41
|
-
end
|
|
41
|
+
end # def default_shell
|
|
42
42
|
|
|
43
43
|
############################################################################
|
|
44
44
|
# execmd([env,] cmd [,opts])
|
|
@@ -136,7 +136,7 @@ module FPM::Util
|
|
|
136
136
|
raise ExecutableNotFound.new(program)
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
-
logger.
|
|
139
|
+
logger.info("Running command", :args => args2)
|
|
140
140
|
|
|
141
141
|
stdout_r, stdout_w = IO.pipe
|
|
142
142
|
stderr_r, stderr_w = IO.pipe
|
|
@@ -250,7 +250,7 @@ module FPM::Util
|
|
|
250
250
|
end
|
|
251
251
|
end
|
|
252
252
|
# If no combination of ar and options omits timestamps, fall back to default.
|
|
253
|
-
@@ar_cmd = ["ar", "-
|
|
253
|
+
@@ar_cmd = ["ar", "-qcS"]
|
|
254
254
|
FileUtils.rm_f([testarchive, emptyfile])
|
|
255
255
|
return @@ar_cmd
|
|
256
256
|
end # def ar_cmd
|
|
@@ -259,7 +259,7 @@ module FPM::Util
|
|
|
259
259
|
def ar_cmd_deterministic?
|
|
260
260
|
ar_cmd if not defined? @@ar_cmd_deterministic
|
|
261
261
|
return @@ar_cmd_deterministic
|
|
262
|
-
end
|
|
262
|
+
end # def ar_cmd_deterministic?
|
|
263
263
|
|
|
264
264
|
# Get the recommended 'tar' command for this platform.
|
|
265
265
|
def tar_cmd
|
|
@@ -306,7 +306,7 @@ module FPM::Util
|
|
|
306
306
|
def tar_cmd_supports_sort_names_and_set_mtime?
|
|
307
307
|
tar_cmd if not defined? @@tar_cmd_deterministic
|
|
308
308
|
return @@tar_cmd_deterministic
|
|
309
|
-
end
|
|
309
|
+
end # def tar_cmd_supports_sort_names_and_set_mtime?
|
|
310
310
|
|
|
311
311
|
def copy_metadata(source, destination)
|
|
312
312
|
source_stat = File::lstat(source)
|
|
@@ -332,7 +332,15 @@ module FPM::Util
|
|
|
332
332
|
|
|
333
333
|
|
|
334
334
|
def copy_entry(src, dst, preserve=false, remove_destination=false)
|
|
335
|
-
|
|
335
|
+
st = File.lstat(src)
|
|
336
|
+
|
|
337
|
+
filetype = if st.ftype == "file" && st.nlink > 1
|
|
338
|
+
"hardlink"
|
|
339
|
+
else
|
|
340
|
+
st.ftype
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
case filetype
|
|
336
344
|
when 'fifo'
|
|
337
345
|
if File.respond_to?(:mkfifo)
|
|
338
346
|
File.mkfifo(dst)
|
|
@@ -350,18 +358,23 @@ module FPM::Util
|
|
|
350
358
|
raise UnsupportedSpecialFile.new("File is device which fpm doesn't know how to copy (#{File.ftype(src)}): #{src}")
|
|
351
359
|
when 'directory'
|
|
352
360
|
FileUtils.mkdir(dst) unless File.exist? dst
|
|
353
|
-
|
|
354
|
-
#
|
|
361
|
+
when 'hardlink'
|
|
362
|
+
# Handle hardlinks
|
|
363
|
+
# if the file with the same dev and inode has been copied already.
|
|
355
364
|
# hard link it's copy to `dst`, otherwise make an actual copy
|
|
356
|
-
st = File.lstat(src)
|
|
357
365
|
known_entry = copied_entries[[st.dev, st.ino]]
|
|
358
366
|
if known_entry
|
|
359
367
|
FileUtils.ln(known_entry, dst)
|
|
368
|
+
logger.debug("Copying hardlink", :src => src, :dst => dst, :link => known_entry)
|
|
360
369
|
else
|
|
361
370
|
FileUtils.copy_entry(src, dst, preserve, false,
|
|
362
371
|
remove_destination)
|
|
363
372
|
copied_entries[[st.dev, st.ino]] = dst
|
|
364
373
|
end
|
|
374
|
+
else
|
|
375
|
+
# Normal file, just copy it.
|
|
376
|
+
FileUtils.copy_entry(src, dst, preserve, false,
|
|
377
|
+
remove_destination)
|
|
365
378
|
end # else...
|
|
366
379
|
end # def copy_entry
|
|
367
380
|
|
|
@@ -439,7 +452,7 @@ module FPM::Util
|
|
|
439
452
|
# Ruby 3.1.0 and newer
|
|
440
453
|
return ERB.new(template_code, trim_mode: "-")
|
|
441
454
|
end
|
|
442
|
-
end
|
|
455
|
+
end # def erbnew
|
|
443
456
|
end # module FPM::Util
|
|
444
457
|
|
|
445
458
|
require 'fpm/util/tar_writer'
|
data/lib/fpm/version.rb
CHANGED
data/templates/sh.erb
CHANGED
|
@@ -137,7 +137,7 @@ function save_environment(){
|
|
|
137
137
|
|
|
138
138
|
# just piping env to a file doesn't quote the variables. This does
|
|
139
139
|
# filter out multiline junk, _, and functions. _ is a readonly variable.
|
|
140
|
-
env | grep -v "^_=" | grep -v "^[^=(]*()=" | egrep "^[^ ]+=" | while read ENVVAR ; do
|
|
140
|
+
env | grep -v "^_=" | grep -v "^[^=(]*()=" | grep -v "^BASH_FUNC_.*%%=" |egrep "^[^ ]+=" | while read ENVVAR ; do
|
|
141
141
|
local NAME=${ENVVAR%%=*}
|
|
142
142
|
# sed is to preserve variable values with dollars (for escaped variables or $() style command replacement),
|
|
143
143
|
# and command replacement backticks
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fpm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.18.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jordan Sissel
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-08-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: cabin
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.
|
|
19
|
+
version: 0.9.1
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.
|
|
26
|
+
version: 0.9.1
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: backports
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -114,14 +114,14 @@ dependencies:
|
|
|
114
114
|
requirements:
|
|
115
115
|
- - "~>"
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: 3.
|
|
117
|
+
version: 3.13.0
|
|
118
118
|
type: :development
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
122
|
- - "~>"
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: 3.
|
|
124
|
+
version: 3.13.0
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
126
|
name: insist
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -198,7 +198,7 @@ files:
|
|
|
198
198
|
- lib/fpm/package/pleaserun.rb
|
|
199
199
|
- lib/fpm/package/puppet.rb
|
|
200
200
|
- lib/fpm/package/pyfpm/__init__.py
|
|
201
|
-
- lib/fpm/package/pyfpm/
|
|
201
|
+
- lib/fpm/package/pyfpm/parse_requires.py
|
|
202
202
|
- lib/fpm/package/python.rb
|
|
203
203
|
- lib/fpm/package/rpm.rb
|
|
204
204
|
- lib/fpm/package/sh.rb
|
|
@@ -238,7 +238,7 @@ homepage: https://github.com/jordansissel/fpm
|
|
|
238
238
|
licenses:
|
|
239
239
|
- MIT-like
|
|
240
240
|
metadata: {}
|
|
241
|
-
post_install_message:
|
|
241
|
+
post_install_message:
|
|
242
242
|
rdoc_options: []
|
|
243
243
|
require_paths:
|
|
244
244
|
- lib
|
|
@@ -254,8 +254,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
254
254
|
- !ruby/object:Gem::Version
|
|
255
255
|
version: '0'
|
|
256
256
|
requirements: []
|
|
257
|
-
rubygems_version: 3.
|
|
258
|
-
signing_key:
|
|
257
|
+
rubygems_version: 3.0.3.1
|
|
258
|
+
signing_key:
|
|
259
259
|
specification_version: 4
|
|
260
260
|
summary: fpm - package building and mangling
|
|
261
261
|
test_files: []
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
from distutils.core import Command
|
|
2
|
-
import os
|
|
3
|
-
import sys
|
|
4
|
-
import pkg_resources
|
|
5
|
-
try:
|
|
6
|
-
import json
|
|
7
|
-
except ImportError:
|
|
8
|
-
import simplejson as json
|
|
9
|
-
|
|
10
|
-
PY3 = sys.version_info[0] == 3
|
|
11
|
-
|
|
12
|
-
if PY3:
|
|
13
|
-
def u(s):
|
|
14
|
-
return s
|
|
15
|
-
else:
|
|
16
|
-
def u(s):
|
|
17
|
-
if isinstance(u, unicode):
|
|
18
|
-
return u
|
|
19
|
-
return s.decode('utf-8')
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# Note, the last time I coded python daily was at Google, so it's entirely
|
|
23
|
-
# possible some of my techniques below are outdated or bad.
|
|
24
|
-
# If you have fixes, let me know.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class get_metadata(Command):
|
|
28
|
-
description = "get package metadata"
|
|
29
|
-
user_options = [
|
|
30
|
-
('load-requirements-txt', 'l',
|
|
31
|
-
"load dependencies from requirements.txt"),
|
|
32
|
-
("output=", "o", "output destination for metadata json")
|
|
33
|
-
]
|
|
34
|
-
boolean_options = ['load-requirements-txt']
|
|
35
|
-
|
|
36
|
-
def initialize_options(self):
|
|
37
|
-
self.load_requirements_txt = False
|
|
38
|
-
self.cwd = None
|
|
39
|
-
self.output = None
|
|
40
|
-
|
|
41
|
-
def finalize_options(self):
|
|
42
|
-
self.cwd = os.getcwd()
|
|
43
|
-
self.requirements_txt = os.path.join(self.cwd, "requirements.txt")
|
|
44
|
-
# make sure we have a requirements.txt
|
|
45
|
-
if self.load_requirements_txt:
|
|
46
|
-
self.load_requirements_txt = os.path.exists(self.requirements_txt)
|
|
47
|
-
|
|
48
|
-
def process_dep(self, dep):
|
|
49
|
-
deps = []
|
|
50
|
-
if hasattr(dep, 'marker') and dep.marker:
|
|
51
|
-
# PEP0508 marker present
|
|
52
|
-
if not dep.marker.evaluate():
|
|
53
|
-
return deps
|
|
54
|
-
|
|
55
|
-
if dep.specs:
|
|
56
|
-
for operator, version in dep.specs:
|
|
57
|
-
deps.append("%s %s %s" % (dep.project_name,
|
|
58
|
-
operator, version))
|
|
59
|
-
else:
|
|
60
|
-
deps.append(dep.project_name)
|
|
61
|
-
|
|
62
|
-
return deps
|
|
63
|
-
|
|
64
|
-
def run(self):
|
|
65
|
-
data = {
|
|
66
|
-
"name": self.distribution.get_name(),
|
|
67
|
-
"version": self.distribution.get_version(),
|
|
68
|
-
"author": u("%s <%s>") % (
|
|
69
|
-
u(self.distribution.get_author()),
|
|
70
|
-
u(self.distribution.get_author_email()),
|
|
71
|
-
),
|
|
72
|
-
"description": self.distribution.get_description(),
|
|
73
|
-
"license": self.distribution.get_license(),
|
|
74
|
-
"url": self.distribution.get_url(),
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if self.distribution.has_ext_modules():
|
|
78
|
-
data["architecture"] = "native"
|
|
79
|
-
else:
|
|
80
|
-
data["architecture"] = "all"
|
|
81
|
-
|
|
82
|
-
final_deps = []
|
|
83
|
-
|
|
84
|
-
if self.load_requirements_txt:
|
|
85
|
-
requirement = open(self.requirements_txt).readlines()
|
|
86
|
-
for dep in pkg_resources.parse_requirements(requirement):
|
|
87
|
-
final_deps.extend(self.process_dep(dep))
|
|
88
|
-
else:
|
|
89
|
-
if getattr(self.distribution, 'install_requires', None):
|
|
90
|
-
for dep in pkg_resources.parse_requirements(
|
|
91
|
-
self.distribution.install_requires):
|
|
92
|
-
final_deps.extend(self.process_dep(dep))
|
|
93
|
-
if getattr(self.distribution, 'extras_require', None):
|
|
94
|
-
for dep in pkg_resources.parse_requirements(
|
|
95
|
-
v for k, v in self.distribution.extras_require.items()
|
|
96
|
-
if k.startswith(':') and pkg_resources.evaluate_marker(k[1:])):
|
|
97
|
-
final_deps.extend(self.process_dep(dep))
|
|
98
|
-
|
|
99
|
-
data["dependencies"] = final_deps
|
|
100
|
-
|
|
101
|
-
output = open(self.output, "w")
|
|
102
|
-
if hasattr(json, 'dumps'):
|
|
103
|
-
def default_to_str(obj):
|
|
104
|
-
""" Fall back to using __str__ if possible """
|
|
105
|
-
# This checks if the class of obj defines __str__ itself,
|
|
106
|
-
# so we don't fall back to an inherited __str__ method.
|
|
107
|
-
if "__str__" in type(obj).__dict__:
|
|
108
|
-
return str(obj)
|
|
109
|
-
return json.JSONEncoder.default(self, obj)
|
|
110
|
-
|
|
111
|
-
output.write(json.dumps(data, indent=2, default=default_to_str))
|
|
112
|
-
else:
|
|
113
|
-
# For Python 2.5 and Debian's python-json
|
|
114
|
-
output.write(json.write(data))
|
|
115
|
-
output.close()
|