1 | import { SoftwarePackage } from '@stencila/schema'
|
2 | import path from 'path'
|
3 |
|
4 | import PackageGenerator from './PackageGenerator'
|
5 | import PythonSystemPackageLookup from './PythonSystemPackageLookup'
|
6 | import IUrlFetcher from './IUrlFetcher'
|
7 |
|
8 | const GENERATED_REQUIREMENTS_FILE = '.requirements.txt'
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | export default class PythonGenerator extends PackageGenerator {
|
14 | |
15 |
|
16 |
|
17 | private readonly pythonMajorVersion: number
|
18 |
|
19 | |
20 |
|
21 |
|
22 | private readonly systemPackageLookup: PythonSystemPackageLookup
|
23 |
|
24 |
|
25 |
|
26 | constructor (urlFetcher: IUrlFetcher, pkg: SoftwarePackage, folder?: string, pythonMajorVersion: number = 3) {
|
27 | super(urlFetcher, pkg, folder)
|
28 |
|
29 | this.pythonMajorVersion = pythonMajorVersion
|
30 | this.systemPackageLookup = PythonSystemPackageLookup.fromFile(path.join(__dirname, 'PythonSystemDependencies.json'))
|
31 | }
|
32 |
|
33 | |
34 |
|
35 |
|
36 |
|
37 | pythonVersionSuffix (): string {
|
38 | return this.pythonMajorVersion === 2 ? '' : `${this.pythonMajorVersion}`
|
39 | }
|
40 |
|
41 | |
42 |
|
43 |
|
44 | applies (): boolean {
|
45 | return this.package.runtimePlatform === 'Python'
|
46 | }
|
47 |
|
48 | |
49 |
|
50 |
|
51 | aptPackages (sysVersion: string): Array<string> {
|
52 | let aptRequirements: Array<string> = []
|
53 |
|
54 | this.package.softwareRequirements.map(requirement => {
|
55 | aptRequirements = aptRequirements.concat(
|
56 | this.systemPackageLookup.lookupSystemPackage(
|
57 | requirement.name, this.pythonMajorVersion, 'deb', sysVersion
|
58 | )
|
59 | )
|
60 | })
|
61 |
|
62 | let dedupedRequirements: Array<string> = []
|
63 | aptRequirements.map(aptRequirement => {
|
64 | if (!dedupedRequirements.includes(aptRequirement)) {
|
65 | dedupedRequirements.push(aptRequirement)
|
66 | }
|
67 | })
|
68 | return [`python${this.pythonVersionSuffix()}`, `python${this.pythonVersionSuffix()}-pip`].concat(
|
69 | dedupedRequirements
|
70 | )
|
71 | }
|
72 |
|
73 | |
74 |
|
75 |
|
76 | generateRequirementsContent (): string {
|
77 | if (!this.package.softwareRequirements) {
|
78 | return ''
|
79 | }
|
80 |
|
81 | return this.filterPackages('Python').map(
|
82 | requirement => `${requirement.name}${requirement.version}`
|
83 | ).join('\n')
|
84 | }
|
85 |
|
86 | |
87 |
|
88 |
|
89 | stencilaInstall (sysVersion: string): string | undefined {
|
90 | return `pip${this.pythonVersionSuffix()} install --no-cache-dir https://github.com/stencila/py/archive/91a05a139ac120a89fc001d9d267989f062ad374.zip`
|
91 | }
|
92 |
|
93 | |
94 |
|
95 |
|
96 |
|
97 | installFiles (sysVersion: string): Array<[string, string]> {
|
98 | let requirementsContent = this.generateRequirementsContent()
|
99 |
|
100 | if (requirementsContent !== '') {
|
101 | this.write(GENERATED_REQUIREMENTS_FILE, requirementsContent)
|
102 | return [[GENERATED_REQUIREMENTS_FILE, 'requirements.txt']]
|
103 | }
|
104 |
|
105 | if (this.exists('requirements.txt')) {
|
106 | return [['requirements.txt', 'requirements.txt']]
|
107 | }
|
108 |
|
109 | return []
|
110 | }
|
111 |
|
112 | |
113 |
|
114 |
|
115 | installCommand (sysVersion: string): string | undefined {
|
116 | return `pip${this.pythonVersionSuffix()} install --requirement requirements.txt`
|
117 | }
|
118 |
|
119 | |
120 |
|
121 |
|
122 |
|
123 |
|
124 | projectFiles (): Array<[string, string]> {
|
125 | const pyFiles = this.glob('**/*.py')
|
126 | return pyFiles.map(file => [file, file]) as Array<[string, string]>
|
127 | }
|
128 |
|
129 | |
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 | runCommand (): string | undefined {
|
136 | const pyFiles = this.glob('**/*.py')
|
137 | if (pyFiles.length === 0) return
|
138 | let script
|
139 | if (pyFiles.includes('main.py')) script = 'main.py'
|
140 | else if (pyFiles.includes('cmd.py')) script = 'cmd.py'
|
141 | else script = pyFiles[0]
|
142 | return `python${this.pythonVersionSuffix()} ${script}`
|
143 | }
|
144 |
|
145 | }
|