Class: Bibliothecary::Parsers::Pypi

Inherits:
Object
  • Object
show all
Includes:
Analyser
Defined in:
lib/bibliothecary/parsers/pypi.rb

Constant Summary collapse

INSTALL_REGEXP =
/install_requires\s*=\s*\[([\s\S]*?)\]/
REQUIRE_REGEXP =
/([a-zA-Z0-9]+[a-zA-Z0-9\-_\.]+)([><=\w\.,]+)?/
REQUIREMENTS_REGEXP =
/^#{REQUIRE_REGEXP}/
MANIFEST_REGEXP =
/.*require[^\/]*(\/)?[^\/]*\.(txt|pip)$/

Class Method Summary collapse

Methods included from Analyser

create_analysis, create_error_analysis, included

Class Method Details

.map_dependencies(packages, type) ⇒ Object



39
40
41
42
43
44
45
46
47
48
# File 'lib/bibliothecary/parsers/pypi.rb', line 39

def self.map_dependencies(packages, type)
  return [] unless packages
  packages.map do |name, info|
    {
      name: name,
      requirement: map_requirements(info),
      type: type
    }
  end
end

.map_requirements(info) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/bibliothecary/parsers/pypi.rb', line 50

def self.map_requirements(info)
  if info.is_a?(Hash)
    if info['version']
      info['version']
    elsif info['git']
      info['git'] + '#' + info['ref']
    else
      '*'
    end
  else
    info || '*'
  end
end

.mappingObject



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/bibliothecary/parsers/pypi.rb', line 11

def self.mapping
  {
    lambda { |p| MANIFEST_REGEXP.match(p) } => {
      kind: 'manifest',
      parser: :parse_requirements_txt,
      can_have_lockfile: false
    },
    match_filename("setup.py") => {
      kind: 'manifest',
      parser: :parse_setup_py,
      can_have_lockfile: false
    },
    match_filename("Pipfile") => {
      kind: 'manifest',
      parser: :parse_pipfile
    },
    match_filename("Pipfile.lock") => {
      kind: 'lockfile',
      parser: :parse_pipfile_lock
    }
  }
end

.parse_pipfile(file_contents) ⇒ Object



34
35
36
37
# File 'lib/bibliothecary/parsers/pypi.rb', line 34

def self.parse_pipfile(file_contents)
  manifest = TomlRB.parse(file_contents)
  map_dependencies(manifest['packages'], 'runtime') + map_dependencies(manifest['dev-packages'], 'develop')
end

.parse_pipfile_lock(file_contents) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/bibliothecary/parsers/pypi.rb', line 64

def self.parse_pipfile_lock(file_contents)
  manifest = JSON.parse(file_contents)
  deps = []
  manifest.each do |group, dependencies|
    next if group == "_meta"
    group = 'runtime' if group == 'default'
    dependencies.each do |name, info|
      deps << {
        name: name,
        requirement: map_requirements(info),
        type: group
      }
    end
  end
  deps
end

.parse_requirements_txt(manifest) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/bibliothecary/parsers/pypi.rb', line 98

def self.parse_requirements_txt(manifest)
  deps = []
  manifest.split("\n").each do |line|
    match = line.delete(' ').match(REQUIREMENTS_REGEXP)
    next unless match
    deps << {
      name: match[1],
      requirement: match[2] || '*',
      type: 'runtime'
    }
  end
  deps
end

.parse_setup_py(manifest) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/bibliothecary/parsers/pypi.rb', line 81

def self.parse_setup_py(manifest)
  match = manifest.match(INSTALL_REGEXP)
  return [] unless match
  deps = []
  match[1].gsub(/',(\s)?'/, "\n").split("\n").each do |line|
    next if line.match(/^#/)
    match = line.match(REQUIRE_REGEXP)
    next unless match
    deps << {
      name: match[1],
      requirement: match[2] || '*',
      type: 'runtime'
    }
  end
  deps
end