pyinfra 0.11.dev3__py3-none-any.whl → 3.6__py3-none-any.whl

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.
Files changed (204) hide show
  1. pyinfra/__init__.py +9 -12
  2. pyinfra/__main__.py +4 -0
  3. pyinfra/api/__init__.py +19 -3
  4. pyinfra/api/arguments.py +413 -0
  5. pyinfra/api/arguments_typed.py +79 -0
  6. pyinfra/api/command.py +274 -0
  7. pyinfra/api/config.py +222 -28
  8. pyinfra/api/connect.py +33 -13
  9. pyinfra/api/connectors.py +27 -0
  10. pyinfra/api/deploy.py +65 -66
  11. pyinfra/api/exceptions.py +73 -18
  12. pyinfra/api/facts.py +267 -200
  13. pyinfra/api/host.py +416 -50
  14. pyinfra/api/inventory.py +121 -160
  15. pyinfra/api/metadata.py +69 -0
  16. pyinfra/api/operation.py +432 -262
  17. pyinfra/api/operations.py +273 -260
  18. pyinfra/api/state.py +302 -248
  19. pyinfra/api/util.py +309 -369
  20. pyinfra/connectors/base.py +173 -0
  21. pyinfra/connectors/chroot.py +212 -0
  22. pyinfra/connectors/docker.py +405 -0
  23. pyinfra/connectors/dockerssh.py +297 -0
  24. pyinfra/connectors/local.py +238 -0
  25. pyinfra/connectors/scp/__init__.py +1 -0
  26. pyinfra/connectors/scp/client.py +204 -0
  27. pyinfra/connectors/ssh.py +727 -0
  28. pyinfra/connectors/ssh_util.py +114 -0
  29. pyinfra/connectors/sshuserclient/client.py +309 -0
  30. pyinfra/connectors/sshuserclient/config.py +102 -0
  31. pyinfra/connectors/terraform.py +135 -0
  32. pyinfra/connectors/util.py +417 -0
  33. pyinfra/connectors/vagrant.py +183 -0
  34. pyinfra/context.py +145 -0
  35. pyinfra/facts/__init__.py +7 -6
  36. pyinfra/facts/apk.py +22 -7
  37. pyinfra/facts/apt.py +117 -60
  38. pyinfra/facts/brew.py +100 -15
  39. pyinfra/facts/bsdinit.py +23 -0
  40. pyinfra/facts/cargo.py +37 -0
  41. pyinfra/facts/choco.py +47 -0
  42. pyinfra/facts/crontab.py +195 -0
  43. pyinfra/facts/deb.py +94 -0
  44. pyinfra/facts/dnf.py +48 -0
  45. pyinfra/facts/docker.py +96 -23
  46. pyinfra/facts/efibootmgr.py +113 -0
  47. pyinfra/facts/files.py +629 -58
  48. pyinfra/facts/flatpak.py +77 -0
  49. pyinfra/facts/freebsd.py +70 -0
  50. pyinfra/facts/gem.py +19 -6
  51. pyinfra/facts/git.py +59 -14
  52. pyinfra/facts/gpg.py +150 -0
  53. pyinfra/facts/hardware.py +313 -167
  54. pyinfra/facts/iptables.py +72 -62
  55. pyinfra/facts/launchd.py +44 -0
  56. pyinfra/facts/lxd.py +17 -4
  57. pyinfra/facts/mysql.py +122 -86
  58. pyinfra/facts/npm.py +17 -9
  59. pyinfra/facts/openrc.py +71 -0
  60. pyinfra/facts/opkg.py +246 -0
  61. pyinfra/facts/pacman.py +50 -7
  62. pyinfra/facts/pip.py +24 -7
  63. pyinfra/facts/pipx.py +82 -0
  64. pyinfra/facts/pkg.py +15 -6
  65. pyinfra/facts/pkgin.py +35 -0
  66. pyinfra/facts/podman.py +54 -0
  67. pyinfra/facts/postgres.py +178 -0
  68. pyinfra/facts/postgresql.py +6 -147
  69. pyinfra/facts/rpm.py +105 -0
  70. pyinfra/facts/runit.py +77 -0
  71. pyinfra/facts/selinux.py +161 -0
  72. pyinfra/facts/server.py +762 -285
  73. pyinfra/facts/snap.py +88 -0
  74. pyinfra/facts/systemd.py +139 -0
  75. pyinfra/facts/sysvinit.py +59 -0
  76. pyinfra/facts/upstart.py +35 -0
  77. pyinfra/facts/util/__init__.py +17 -0
  78. pyinfra/facts/util/databases.py +4 -6
  79. pyinfra/facts/util/packaging.py +37 -6
  80. pyinfra/facts/util/units.py +30 -0
  81. pyinfra/facts/util/win_files.py +99 -0
  82. pyinfra/facts/vzctl.py +20 -13
  83. pyinfra/facts/xbps.py +35 -0
  84. pyinfra/facts/yum.py +34 -40
  85. pyinfra/facts/zfs.py +77 -0
  86. pyinfra/facts/zypper.py +42 -0
  87. pyinfra/local.py +45 -83
  88. pyinfra/operations/__init__.py +12 -0
  89. pyinfra/operations/apk.py +99 -0
  90. pyinfra/operations/apt.py +496 -0
  91. pyinfra/operations/brew.py +232 -0
  92. pyinfra/operations/bsdinit.py +59 -0
  93. pyinfra/operations/cargo.py +45 -0
  94. pyinfra/operations/choco.py +61 -0
  95. pyinfra/operations/crontab.py +194 -0
  96. pyinfra/operations/dnf.py +213 -0
  97. pyinfra/operations/docker.py +492 -0
  98. pyinfra/operations/files.py +2014 -0
  99. pyinfra/operations/flatpak.py +95 -0
  100. pyinfra/operations/freebsd/__init__.py +12 -0
  101. pyinfra/operations/freebsd/freebsd_update.py +70 -0
  102. pyinfra/operations/freebsd/pkg.py +219 -0
  103. pyinfra/operations/freebsd/service.py +116 -0
  104. pyinfra/operations/freebsd/sysrc.py +92 -0
  105. pyinfra/operations/gem.py +48 -0
  106. pyinfra/operations/git.py +420 -0
  107. pyinfra/operations/iptables.py +312 -0
  108. pyinfra/operations/launchd.py +45 -0
  109. pyinfra/operations/lxd.py +69 -0
  110. pyinfra/operations/mysql.py +610 -0
  111. pyinfra/operations/npm.py +57 -0
  112. pyinfra/operations/openrc.py +63 -0
  113. pyinfra/operations/opkg.py +89 -0
  114. pyinfra/operations/pacman.py +82 -0
  115. pyinfra/operations/pip.py +206 -0
  116. pyinfra/operations/pipx.py +103 -0
  117. pyinfra/operations/pkg.py +71 -0
  118. pyinfra/operations/pkgin.py +92 -0
  119. pyinfra/operations/postgres.py +437 -0
  120. pyinfra/operations/postgresql.py +30 -0
  121. pyinfra/operations/puppet.py +41 -0
  122. pyinfra/operations/python.py +73 -0
  123. pyinfra/operations/runit.py +184 -0
  124. pyinfra/operations/selinux.py +190 -0
  125. pyinfra/operations/server.py +1100 -0
  126. pyinfra/operations/snap.py +118 -0
  127. pyinfra/operations/ssh.py +217 -0
  128. pyinfra/operations/systemd.py +150 -0
  129. pyinfra/operations/sysvinit.py +142 -0
  130. pyinfra/operations/upstart.py +68 -0
  131. pyinfra/operations/util/__init__.py +12 -0
  132. pyinfra/operations/util/docker.py +407 -0
  133. pyinfra/operations/util/files.py +247 -0
  134. pyinfra/operations/util/packaging.py +338 -0
  135. pyinfra/operations/util/service.py +46 -0
  136. pyinfra/operations/vzctl.py +137 -0
  137. pyinfra/operations/xbps.py +78 -0
  138. pyinfra/operations/yum.py +213 -0
  139. pyinfra/operations/zfs.py +176 -0
  140. pyinfra/operations/zypper.py +193 -0
  141. pyinfra/progress.py +44 -32
  142. pyinfra/py.typed +0 -0
  143. pyinfra/version.py +9 -1
  144. pyinfra-3.6.dist-info/METADATA +142 -0
  145. pyinfra-3.6.dist-info/RECORD +160 -0
  146. {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info}/WHEEL +1 -2
  147. pyinfra-3.6.dist-info/entry_points.txt +12 -0
  148. {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info/licenses}/LICENSE.md +1 -1
  149. pyinfra_cli/__init__.py +1 -0
  150. pyinfra_cli/cli.py +793 -0
  151. pyinfra_cli/commands.py +66 -0
  152. pyinfra_cli/exceptions.py +155 -65
  153. pyinfra_cli/inventory.py +233 -89
  154. pyinfra_cli/log.py +39 -43
  155. pyinfra_cli/main.py +26 -495
  156. pyinfra_cli/prints.py +215 -156
  157. pyinfra_cli/util.py +172 -105
  158. pyinfra_cli/virtualenv.py +25 -20
  159. pyinfra/api/connectors/__init__.py +0 -21
  160. pyinfra/api/connectors/ansible.py +0 -99
  161. pyinfra/api/connectors/docker.py +0 -178
  162. pyinfra/api/connectors/local.py +0 -169
  163. pyinfra/api/connectors/ssh.py +0 -402
  164. pyinfra/api/connectors/sshuserclient/client.py +0 -105
  165. pyinfra/api/connectors/sshuserclient/config.py +0 -90
  166. pyinfra/api/connectors/util.py +0 -63
  167. pyinfra/api/connectors/vagrant.py +0 -155
  168. pyinfra/facts/init.py +0 -176
  169. pyinfra/facts/util/files.py +0 -102
  170. pyinfra/hook.py +0 -41
  171. pyinfra/modules/__init__.py +0 -11
  172. pyinfra/modules/apk.py +0 -64
  173. pyinfra/modules/apt.py +0 -272
  174. pyinfra/modules/brew.py +0 -122
  175. pyinfra/modules/files.py +0 -711
  176. pyinfra/modules/gem.py +0 -30
  177. pyinfra/modules/git.py +0 -115
  178. pyinfra/modules/init.py +0 -344
  179. pyinfra/modules/iptables.py +0 -271
  180. pyinfra/modules/lxd.py +0 -45
  181. pyinfra/modules/mysql.py +0 -347
  182. pyinfra/modules/npm.py +0 -47
  183. pyinfra/modules/pacman.py +0 -60
  184. pyinfra/modules/pip.py +0 -99
  185. pyinfra/modules/pkg.py +0 -43
  186. pyinfra/modules/postgresql.py +0 -245
  187. pyinfra/modules/puppet.py +0 -20
  188. pyinfra/modules/python.py +0 -37
  189. pyinfra/modules/server.py +0 -524
  190. pyinfra/modules/ssh.py +0 -150
  191. pyinfra/modules/util/files.py +0 -52
  192. pyinfra/modules/util/packaging.py +0 -118
  193. pyinfra/modules/vzctl.py +0 -133
  194. pyinfra/modules/yum.py +0 -171
  195. pyinfra/pseudo_modules.py +0 -64
  196. pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
  197. pyinfra-0.11.dev3.dist-info/METADATA +0 -135
  198. pyinfra-0.11.dev3.dist-info/RECORD +0 -95
  199. pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
  200. pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
  201. pyinfra_cli/__main__.py +0 -40
  202. pyinfra_cli/config.py +0 -92
  203. /pyinfra/{modules/util → connectors}/__init__.py +0 -0
  204. /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+
5
+ from typing_extensions import override
6
+
7
+ from pyinfra.api import FactBase
8
+
9
+
10
+ class FlatpakBaseFact(FactBase):
11
+ abstract = True
12
+
13
+ @override
14
+ def requires_command(self, *args, **kwargs) -> str:
15
+ return "flatpak"
16
+
17
+
18
+ class FlatpakPackage(FlatpakBaseFact):
19
+ """
20
+ Returns information for an installed flatpak package
21
+
22
+ .. code:: python
23
+
24
+ {
25
+ "id": "org.signal.Signal",
26
+ "ref": "app/org.signal.Signal/x86_64/stable",
27
+ "version": "7.12.0"
28
+ }
29
+ """
30
+
31
+ default = dict
32
+ _regexes = {
33
+ "id": "^[ ]+ID:[ ]+(.*)$",
34
+ "ref": r"^[ ]+Ref:[ ]+(.*)$",
35
+ "version": r"^[ ]+Version:[ ]+([\w\d.-]+).*$",
36
+ }
37
+
38
+ @override
39
+ def command(self, package):
40
+ return f"flatpak info {package}"
41
+
42
+ @override
43
+ def process(self, output):
44
+ data = {}
45
+ for line in output:
46
+ for regex_name, regex in self._regexes.items():
47
+ matches = re.match(regex, line)
48
+ if matches:
49
+ data[regex_name] = matches.group(1)
50
+
51
+ return data
52
+
53
+
54
+ class FlatpakPackages(FlatpakBaseFact):
55
+ """
56
+ Returns a list of installed flatpak packages:
57
+
58
+ .. code:: python
59
+
60
+ [
61
+ "org.gnome.Platform",
62
+ "org.kde.Platform",
63
+ "org.kde.Sdk",
64
+ "org.libreoffice.LibreOffice",
65
+ "org.videolan.VLC"
66
+ ]
67
+ """
68
+
69
+ default = list
70
+
71
+ @override
72
+ def command(self):
73
+ return "flatpak list --columns=application"
74
+
75
+ @override
76
+ def process(self, output):
77
+ return [flatpak for flatpak in output[1:]]
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ from typing_extensions import Optional, override
4
+
5
+ from pyinfra.api import FactBase
6
+ from pyinfra.api.command import QuoteString, StringCommand, make_formatted_string_command
7
+
8
+
9
+ class ServiceScript(FactBase):
10
+ @override
11
+ def command(self, srvname: str, jail: Optional[str] = None) -> StringCommand:
12
+ if jail is None:
13
+ jail = ""
14
+
15
+ return make_formatted_string_command(
16
+ (
17
+ "for service in `service -j {0} -l`; do "
18
+ 'if [ {1} = \\"$service\\" ]; '
19
+ 'then echo \\"$service\\"; '
20
+ "fi; "
21
+ "done"
22
+ ),
23
+ QuoteString(jail),
24
+ QuoteString(srvname),
25
+ )
26
+
27
+
28
+ class ServiceStatus(FactBase):
29
+ @override
30
+ def command(self, srvname: str, jail: Optional[str] = None) -> StringCommand:
31
+ if jail is None:
32
+ jail = ""
33
+
34
+ return make_formatted_string_command(
35
+ ("service -j {0} {1} status > /dev/null 2>&1; if [ $? -eq 0 ]; then echo running; fi"),
36
+ QuoteString(jail),
37
+ QuoteString(srvname),
38
+ )
39
+
40
+
41
+ class Sysrc(FactBase):
42
+ @override
43
+ def command(self, parameter: str, jail: Optional[str] = None) -> StringCommand:
44
+ if jail is None:
45
+ command = make_formatted_string_command(
46
+ ("sysrc -in -- {0} || true"), QuoteString(parameter)
47
+ )
48
+ else:
49
+ command = make_formatted_string_command(
50
+ ("sysrc -j {0} -in -- {1} || true"), QuoteString(jail), QuoteString(parameter)
51
+ )
52
+
53
+ return command
54
+
55
+
56
+ class PkgPackage(FactBase):
57
+ @override
58
+ def command(self, package: str, jail: Optional[str] = None) -> StringCommand:
59
+ if jail is None:
60
+ command = make_formatted_string_command(
61
+ ("pkg info -E -- {0} 2> /dev/null || true"), QuoteString(package)
62
+ )
63
+ else:
64
+ command = make_formatted_string_command(
65
+ ("pkg -j {0} info -E -- {1} 2> /dev/null || true"),
66
+ QuoteString(jail),
67
+ QuoteString(package),
68
+ )
69
+
70
+ return command
pyinfra/facts/gem.py CHANGED
@@ -1,22 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ from typing_extensions import override
4
+
1
5
  from pyinfra.api import FactBase
2
6
 
3
7
  from .util.packaging import parse_packages
4
8
 
5
- GEM_REGEX = r'^([a-zA-Z0-9\-\+\_]+)\s\(([0-9\.]+)\)$'
9
+ GEM_REGEX = r"^([a-zA-Z0-9\-\+\_]+)\s\(([0-9\.]+)\)$"
6
10
 
7
11
 
8
12
  class GemPackages(FactBase):
9
- '''
13
+ """
10
14
  Returns a dict of installed gem packages:
11
15
 
12
16
  .. code:: python
13
17
 
14
- 'package_name': ['version'],
15
- ...
16
- '''
18
+ {
19
+ 'package_name': ['version'],
20
+ }
21
+ """
22
+
23
+ @override
24
+ def command(self) -> str:
25
+ return "gem list --local"
26
+
27
+ @override
28
+ def requires_command(self) -> str:
29
+ return "gem"
17
30
 
18
- command = 'gem list --local'
19
31
  default = dict
20
32
 
33
+ @override
21
34
  def process(self, output):
22
35
  return parse_packages(GEM_REGEX, output)
pyinfra/facts/git.py CHANGED
@@ -1,26 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+
5
+ from typing_extensions import override
6
+
1
7
  from pyinfra.api.facts import FactBase
2
8
 
3
9
 
4
- class GitBranch(FactBase):
5
- @staticmethod
6
- def command(repo):
7
- return 'cd {0} && git rev-parse --abbrev-ref HEAD'.format(repo)
10
+ class GitFactBase(FactBase):
11
+ @override
12
+ def requires_command(self, *args, **kwargs) -> str:
13
+ return "git"
14
+
15
+
16
+ class GitBranch(GitFactBase):
17
+ @override
18
+ def command(self, repo) -> str:
19
+ return "! test -d {0} || (cd {0} && git describe --all)".format(repo)
20
+
21
+ @override
22
+ def process(self, output):
23
+ return re.sub(r"(heads|tags)/", r"", "\n".join(output))
24
+
8
25
 
26
+ class GitTag(GitFactBase):
27
+ @override
28
+ def command(self, repo) -> str:
29
+ return "! test -d {0} || (cd {0} && git tag)".format(repo)
9
30
 
10
- class GitConfig(FactBase):
11
- @staticmethod
12
- def command(repo=None):
31
+ @override
32
+ def process(self, output):
33
+ return output
34
+
35
+
36
+ class GitConfig(GitFactBase):
37
+ default = dict
38
+
39
+ @override
40
+ def command(self, repo=None, system=False) -> str:
13
41
  if repo is None:
14
- return 'git config --global -l'
42
+ level = "--system" if system else "--global"
43
+ return f"git config {level} -l || true"
15
44
 
16
- return 'cd {0} && git config --local -l'.format(repo)
45
+ return "! test -d {0} || (cd {0} && git config --local -l)".format(repo)
17
46
 
18
- @staticmethod
19
- def process(output):
20
- items = {}
47
+ @override
48
+ def process(self, output):
49
+ items: dict[str, list[str]] = {}
21
50
 
22
51
  for line in output:
23
- key, value = line.split('=', 1)
24
- items[key] = value
52
+ key, value = line.split("=", 1)
53
+ items.setdefault(key, []).append(value)
25
54
 
26
55
  return items
56
+
57
+
58
+ class GitTrackingBranch(GitFactBase):
59
+ @override
60
+ def command(self, repo) -> str:
61
+ return r"! test -d {0} || (cd {0} && git status --branch --porcelain)".format(repo)
62
+
63
+ @override
64
+ def process(self, output):
65
+ if not output:
66
+ return None
67
+
68
+ m = re.search(r"\.{3}(\S+)\b", list(output)[0])
69
+ if m:
70
+ return m.group(1)
71
+ return None
pyinfra/facts/gpg.py ADDED
@@ -0,0 +1,150 @@
1
+ from __future__ import annotations
2
+
3
+ from urllib.parse import urlparse
4
+
5
+ from typing_extensions import override
6
+
7
+ from pyinfra.api import FactBase
8
+
9
+
10
+ class GpgFactBase(FactBase):
11
+ abstract = True
12
+
13
+ @override
14
+ def requires_command(self, *args, **kwargs) -> str:
15
+ return "gpg"
16
+
17
+ key_record_type = "pub"
18
+ subkey_record_type = "sub"
19
+
20
+ @override
21
+ def process(self, output):
22
+ # For details on the field values see:
23
+ # https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS
24
+ keys = []
25
+
26
+ current_key = None
27
+ current_subkey = None
28
+
29
+ for line in output:
30
+ if not line:
31
+ continue
32
+
33
+ bits = line.split(":")
34
+
35
+ if bits[0] in (self.key_record_type, self.subkey_record_type):
36
+ key_details = {
37
+ "validity": bits[1],
38
+ "length": int(bits[2]),
39
+ "id": bits[4],
40
+ }
41
+
42
+ if bits[0] == self.key_record_type:
43
+ key_details["subkeys"] = []
44
+
45
+ if current_key:
46
+ if current_subkey:
47
+ current_key["subkeys"].append(current_subkey)
48
+
49
+ keys.append(current_key)
50
+
51
+ current_key = key_details
52
+ current_subkey = None
53
+ elif current_key:
54
+ current_subkey = key_details
55
+
56
+ elif current_subkey or current_key:
57
+ target = current_subkey or current_key
58
+ assert target is not None
59
+ if bits[0] == "fpr":
60
+ target["fingerprint"] = bits[9] # fingerprint = field 10
61
+ elif bits[0] == "uid":
62
+ target["uid_hash"] = bits[7]
63
+ target["uid"] = bits[9]
64
+
65
+ if current_key:
66
+ if current_subkey:
67
+ current_key["subkeys"].append(current_subkey)
68
+
69
+ keys.append(current_key)
70
+
71
+ # Return as a dictionary of keyID -> details
72
+ keys_by_id = {}
73
+ for key in keys:
74
+ if "subkeys" in key:
75
+ key["subkeys"] = {subkey.pop("id"): subkey for subkey in key["subkeys"]}
76
+ keys_by_id[key.pop("id")] = key
77
+
78
+ return keys_by_id
79
+
80
+
81
+ class GpgKey(GpgFactBase):
82
+ """
83
+ Returns information on one or more GPG keys found in a file or URL.
84
+
85
+ .. code:: python
86
+
87
+ {
88
+ "KEY-ID": {
89
+ "length": 4096,
90
+ "uid": "Oxygem <hello@oxygem.com>"
91
+ },
92
+ }
93
+ """
94
+
95
+ @override
96
+ def command(self, src):
97
+ if urlparse(src).scheme:
98
+ return ("(wget -O - {0} || curl -sSLf {0}) | gpg --with-colons").format(src)
99
+
100
+ return "gpg --with-colons {0}".format(src)
101
+
102
+
103
+ class GpgKeys(GpgFactBase):
104
+ """
105
+ Returns information on all public keys in a keychain.
106
+
107
+ .. code:: python
108
+
109
+ {
110
+ "KEY-ID": {
111
+ "length": 4096,
112
+ "uid": "Oxygem <hello@oxygem.com>"
113
+ },
114
+ }
115
+ """
116
+
117
+ @override
118
+ def command(self, keyring=None):
119
+ if not keyring:
120
+ return "gpg --list-keys --with-colons"
121
+
122
+ return ("gpg --list-keys --with-colons --keyring {0} --no-default-keyring").format(keyring)
123
+
124
+
125
+ class GpgSecretKeys(GpgFactBase):
126
+ """
127
+ Returns information on all secret keys in a keychain.
128
+
129
+ .. code:: python
130
+
131
+ {
132
+ "KEY-ID": {
133
+ "length": 4096,
134
+ "fingerprint": "ABC",
135
+ "uid": "Oxygem <hello@oxygem.com>"
136
+ },
137
+ }
138
+ """
139
+
140
+ key_record_type = "sec"
141
+ subkey_record_type = "ssb"
142
+
143
+ @override
144
+ def command(self, keyring=None):
145
+ if not keyring:
146
+ return "gpg --list-secret-keys --with-colons"
147
+
148
+ return ("gpg --list-secret-keys --with-colons --keyring {0} --no-default-keyring").format(
149
+ keyring,
150
+ )