pyinfra 3.0b1__py2.py3-none-any.whl → 3.0b2__py2.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 (104) hide show
  1. pyinfra/api/arguments.py +9 -3
  2. pyinfra/api/arguments_typed.py +8 -5
  3. pyinfra/api/command.py +5 -3
  4. pyinfra/api/config.py +115 -13
  5. pyinfra/api/connectors.py +5 -2
  6. pyinfra/api/facts.py +33 -32
  7. pyinfra/api/host.py +5 -5
  8. pyinfra/api/inventory.py +4 -0
  9. pyinfra/api/operation.py +22 -14
  10. pyinfra/api/util.py +24 -16
  11. pyinfra/connectors/base.py +3 -6
  12. pyinfra/connectors/docker.py +2 -9
  13. pyinfra/connectors/local.py +2 -2
  14. pyinfra/connectors/ssh.py +2 -2
  15. pyinfra/connectors/util.py +6 -7
  16. pyinfra/connectors/vagrant.py +5 -5
  17. pyinfra/context.py +1 -0
  18. pyinfra/facts/apk.py +2 -0
  19. pyinfra/facts/apt.py +2 -0
  20. pyinfra/facts/brew.py +2 -0
  21. pyinfra/facts/bsdinit.py +2 -0
  22. pyinfra/facts/cargo.py +2 -0
  23. pyinfra/facts/choco.py +2 -0
  24. pyinfra/facts/deb.py +7 -2
  25. pyinfra/facts/dnf.py +2 -0
  26. pyinfra/facts/docker.py +2 -0
  27. pyinfra/facts/files.py +2 -0
  28. pyinfra/facts/gem.py +2 -0
  29. pyinfra/facts/gpg.py +2 -0
  30. pyinfra/facts/hardware.py +30 -22
  31. pyinfra/facts/launchd.py +2 -0
  32. pyinfra/facts/lxd.py +2 -0
  33. pyinfra/facts/mysql.py +12 -6
  34. pyinfra/facts/npm.py +1 -0
  35. pyinfra/facts/openrc.py +2 -0
  36. pyinfra/facts/pacman.py +6 -2
  37. pyinfra/facts/pip.py +2 -0
  38. pyinfra/facts/pkg.py +2 -0
  39. pyinfra/facts/pkgin.py +2 -0
  40. pyinfra/facts/postgres.py +6 -6
  41. pyinfra/facts/postgresql.py +2 -0
  42. pyinfra/facts/rpm.py +12 -9
  43. pyinfra/facts/server.py +10 -13
  44. pyinfra/facts/snap.py +2 -0
  45. pyinfra/facts/systemd.py +2 -0
  46. pyinfra/facts/upstart.py +2 -0
  47. pyinfra/facts/util/packaging.py +3 -2
  48. pyinfra/facts/vzctl.py +2 -0
  49. pyinfra/facts/xbps.py +2 -0
  50. pyinfra/facts/yum.py +2 -0
  51. pyinfra/facts/zypper.py +2 -0
  52. pyinfra/operations/apk.py +3 -1
  53. pyinfra/operations/apt.py +16 -18
  54. pyinfra/operations/brew.py +10 -8
  55. pyinfra/operations/bsdinit.py +5 -3
  56. pyinfra/operations/cargo.py +3 -1
  57. pyinfra/operations/choco.py +3 -1
  58. pyinfra/operations/dnf.py +15 -19
  59. pyinfra/operations/files.py +81 -66
  60. pyinfra/operations/gem.py +3 -1
  61. pyinfra/operations/git.py +18 -16
  62. pyinfra/operations/iptables.py +27 -25
  63. pyinfra/operations/launchd.py +5 -6
  64. pyinfra/operations/lxd.py +7 -4
  65. pyinfra/operations/mysql.py +57 -53
  66. pyinfra/operations/npm.py +8 -1
  67. pyinfra/operations/openrc.py +5 -3
  68. pyinfra/operations/pacman.py +4 -5
  69. pyinfra/operations/pip.py +11 -9
  70. pyinfra/operations/pkg.py +3 -1
  71. pyinfra/operations/pkgin.py +3 -1
  72. pyinfra/operations/postgres.py +39 -37
  73. pyinfra/operations/postgresql.py +2 -0
  74. pyinfra/operations/puppet.py +3 -1
  75. pyinfra/operations/python.py +7 -3
  76. pyinfra/operations/selinux.py +42 -16
  77. pyinfra/operations/server.py +48 -43
  78. pyinfra/operations/snap.py +3 -1
  79. pyinfra/operations/ssh.py +12 -10
  80. pyinfra/operations/systemd.py +8 -6
  81. pyinfra/operations/sysvinit.py +6 -4
  82. pyinfra/operations/upstart.py +5 -3
  83. pyinfra/operations/util/files.py +24 -16
  84. pyinfra/operations/util/packaging.py +53 -37
  85. pyinfra/operations/util/service.py +18 -13
  86. pyinfra/operations/vzctl.py +12 -10
  87. pyinfra/operations/xbps.py +3 -1
  88. pyinfra/operations/yum.py +14 -18
  89. pyinfra/operations/zypper.py +8 -9
  90. pyinfra/version.py +5 -2
  91. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/METADATA +28 -26
  92. pyinfra-3.0b2.dist-info/RECORD +163 -0
  93. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/WHEEL +1 -1
  94. pyinfra_cli/exceptions.py +0 -5
  95. pyinfra_cli/inventory.py +38 -19
  96. pyinfra_cli/prints.py +15 -11
  97. pyinfra_cli/util.py +3 -1
  98. tests/test_api/test_api_operations.py +1 -1
  99. tests/test_connectors/test_ssh.py +66 -13
  100. tests/test_connectors/test_vagrant.py +3 -3
  101. pyinfra-3.0b1.dist-info/RECORD +0 -163
  102. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/LICENSE.md +0 -0
  103. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/entry_points.txt +0 -0
  104. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,163 @@
1
+ pyinfra/__init__.py,sha256=7ZcKHGWk7_nYxsYrbFBB_vJr-J-Ddbc56ZS4sk5ArVw,535
2
+ pyinfra/__main__.py,sha256=aVd00glLz5CMJGXgt1XxbOvC2HluqaowoTOjxgIpBaA,47
3
+ pyinfra/context.py,sha256=S6DvGjjTEjM4u2m9oIAmAaV7kXIJzVwYf725P1muIuY,3395
4
+ pyinfra/local.py,sha256=0bpIRCyDKM6i_jA1i8Ej2qr_iWIF9cUYWutXNdLj8po,2751
5
+ pyinfra/progress.py,sha256=X3hXZ4Flh_L9FE4ZEWxWoG0R4dA5UPd1FCO-Exd5Xtc,4193
6
+ pyinfra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ pyinfra/version.py,sha256=LZf50PHDzEZv65w0G-iMICoQ9US0U5LWHAOEmNtkF3I,216
8
+ pyinfra/api/__init__.py,sha256=suGbKKM-qCduuXFYBEcyswlTqozewtYpdLRhK63PVn0,942
9
+ pyinfra/api/arguments.py,sha256=8BhuJiljFJzaCi9lM8HoEBB9mcnCBilv4Zwdx_349g8,9941
10
+ pyinfra/api/arguments_typed.py,sha256=WQKr0wDtlgJGq-Vkv_oPAz7f-LxjqQv3wJCdvVrePWk,2331
11
+ pyinfra/api/command.py,sha256=SyUlxvhYlXpgFpg0jua8bzQ2KPtVYQXHcvD6AUL2SCI,7226
12
+ pyinfra/api/config.py,sha256=wS6Pi4T4DxNkzO4llNY-ghLxyI5VBJ26uGvgMPZxIKY,9043
13
+ pyinfra/api/connect.py,sha256=Z9wusMLR_jBkKKk5D4AUOj8LHl3H5MsNO5FxAeR4jac,1416
14
+ pyinfra/api/connectors.py,sha256=nie7JuLxMSC6gqPjmjuCisQ11R-eAQDtMMWF6YbSQ48,659
15
+ pyinfra/api/deploy.py,sha256=xo4F7URUf3xzIChRHZn4zwqs_WTjLjZNC9i9eQjAFk8,2756
16
+ pyinfra/api/exceptions.py,sha256=cCbUp1qN1QO0d9aAvOAbRgYpLi0vUI5j7ZqSjcD1_P8,1861
17
+ pyinfra/api/facts.py,sha256=L_Wsrdq-u0zR69klnXWZ_2j9H7m3Oto53X0bQf670X8,10574
18
+ pyinfra/api/host.py,sha256=3lRhlZDRKvCNvpziaTglExy2Ep1wd4YdmGDNY4emAdA,13466
19
+ pyinfra/api/inventory.py,sha256=nPITdNEJ7q71adIqS_OKHsMjD7amUuHEuTl6xzgh1Gk,7734
20
+ pyinfra/api/operation.py,sha256=pB0LpjUqbMLGtoDnsckNw0FRoeo1BopL0fnXVDM1JyU,15112
21
+ pyinfra/api/operations.py,sha256=jvz9ISfwmQnAQVUKLnbrRdD9QHIAAfypo9l5b3fYG1w,10894
22
+ pyinfra/api/state.py,sha256=3dXRjeZJXnzLcbP9E4aogkRPwIg3_kK1h4Tf4FVZock,12622
23
+ pyinfra/api/util.py,sha256=vesFOxExETb-B-oAhWpJJrmALTubg3fkFqi0gYd0pJs,12265
24
+ pyinfra/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ pyinfra/connectors/base.py,sha256=2fASiV-MvpXgcZAFLM_PUwYx5ax6EHai44ri_oEKeSE,3732
26
+ pyinfra/connectors/chroot.py,sha256=Xd72I8T58KIwKOoc0LXCw91AoEIaiHfRLDcDVTHGJ0o,5931
27
+ pyinfra/connectors/docker.py,sha256=2UNHhXS4hpLo7I19ixDeSd7JR8SNo43VgqsaUIZQZJ4,8741
28
+ pyinfra/connectors/dockerssh.py,sha256=VWHY--jqs3yf-RuPUZXav4vLeON9SzoVC9CUyOJo1rg,8919
29
+ pyinfra/connectors/local.py,sha256=vYOBQS_5rf-dVaPeG4dJlLwBHqkxAzLjj3aDEgbAsx8,6900
30
+ pyinfra/connectors/ssh.py,sha256=ESCZwehJ0Ve6gkjbqGTJrNEGZlu3ItjKLMkmCWq-Z3Y,20989
31
+ pyinfra/connectors/ssh_util.py,sha256=CN_5AdTA3RpiWCnXTrRBjez1NsN59hITDzQmXIkZvoE,3683
32
+ pyinfra/connectors/terraform.py,sha256=G7lK168Fz0jNFetc_7_bPT-RnoaRDksJat0R26fqkUk,3617
33
+ pyinfra/connectors/util.py,sha256=0bvoMsGMD-Tbfaer8NUhWJjBnaNKdmE83PDg48BYjcU,11374
34
+ pyinfra/connectors/vagrant.py,sha256=oEeRglzRmemRXW3vilsp_Xg9qnZMRprRJO9fd_C-f5M,4759
35
+ pyinfra/connectors/sshuserclient/__init__.py,sha256=Qc4RO2wknSWIiNTwOeQ0y2TeiuKHmyWDW2Dz4MOo9CE,44
36
+ pyinfra/connectors/sshuserclient/client.py,sha256=7YSd3QckZuPDRnKzy2FfG3J8zp7CY-jny8tbWwxvKro,9720
37
+ pyinfra/connectors/sshuserclient/config.py,sha256=UMwkvTgAIS7__re6Wz_pwH6EU4kO1-uMQ5zuFakH0v4,2721
38
+ pyinfra/facts/__init__.py,sha256=myTXSOZmAqmU88Fyifn035h9Lr6Gj2mlka_jDcXyKGw,347
39
+ pyinfra/facts/apk.py,sha256=zihlHc6BbBUNQRL3v6wVFUHypfIL7wC6CPLrp4yynHo,518
40
+ pyinfra/facts/apt.py,sha256=8BJX79dBM9t3ceOhP_B5-I008HEJAUj_ijKDVvSxbFo,2035
41
+ pyinfra/facts/brew.py,sha256=aG77URXfNYT50ZpeHyyByiiX08GR6Oz6L0M3UMf9ztI,2302
42
+ pyinfra/facts/bsdinit.py,sha256=KyX4gc8cXKNn3O_NAlKWvEDKvMCnkTWJQg61oTV9ZN0,526
43
+ pyinfra/facts/cargo.py,sha256=mHtT2Yxoqx_g0akDq6jkHFN5VWNHQu70vKvNLZ10-b8,567
44
+ pyinfra/facts/choco.py,sha256=Tf7_DuQY0eZ4SIxV0rlyulrBCg7A0qyPbtTcHgkVP_0,739
45
+ pyinfra/facts/deb.py,sha256=dy5PKdQqy1oLdCUd6iTxCa6yG8agsaxZrPVsjvlDi74,1756
46
+ pyinfra/facts/dnf.py,sha256=7YNicP8EbRvWJQKU0OcwcW3bnIxx9GJ1Fy4qdCFnI0Y,898
47
+ pyinfra/facts/docker.py,sha256=uaY2ui98t3p0a6F6DQq5FiA6y8pOCwsrkFK4JTRlj3Y,1714
48
+ pyinfra/facts/files.py,sha256=ki9-NQnYyt1VzuqKwEOYpX1nz5gJ_ph-ruq-4DS1VLg,11511
49
+ pyinfra/facts/gem.py,sha256=U1oF32LeiBo3ruaFm6hfF3XwNmgyhqamFUAeGn4cD3k,509
50
+ pyinfra/facts/git.py,sha256=rk4NS2SQJiosI6eY2eCy_p9kOP4O8UARRjFi16ObE2w,1294
51
+ pyinfra/facts/gpg.py,sha256=T5yVc_X9BLrDc77Yjk69x9SnP0qRWnKYEpi4JU__pKo,3765
52
+ pyinfra/facts/hardware.py,sha256=je1KjLfr4t-QZxTYei-V3Xqpll4TjbNeQxlHUvADg-c,11877
53
+ pyinfra/facts/iptables.py,sha256=sUkywfHZUXnMZF_KshAnyJufrJvZ9fBYnERSRbwOCRE,3374
54
+ pyinfra/facts/launchd.py,sha256=xjkszKmi9XNkovp7J33WTV19XfQbc5xGJkIBbFRTRhE,704
55
+ pyinfra/facts/lxd.py,sha256=ymBb_SdHbfAlx_tQyRPVa1ij_e68ZDODg1id1E0V8Rg,373
56
+ pyinfra/facts/mysql.py,sha256=0tpNks5be_mBWzIxuEqOyQ9MTYD9rRjeC3Oc_MQ2nns,6038
57
+ pyinfra/facts/npm.py,sha256=l_61BmbAWrO9RlYKUzLUcgicJ4RCMZHD70alrngC7-M,709
58
+ pyinfra/facts/openrc.py,sha256=NitG8BkwUCBrn-3SqM3FDiP4r6tAQTAWuHXTm1-3WGM,1386
59
+ pyinfra/facts/pacman.py,sha256=lU8IQYpQI3tzxRvKZHJD8giM_n17D5abzxIPasbII-A,1070
60
+ pyinfra/facts/pip.py,sha256=ORyrVxu_-8eIr0uSCkI6x4MH-sorDEavml4aozcdrOA,738
61
+ pyinfra/facts/pkg.py,sha256=2N-NlY_f3eQaW3dxCGKaKvu_ymC5_EF0-KASeul0EJc,488
62
+ pyinfra/facts/pkgin.py,sha256=Q1q7m4CCs_na92dDdQIjTuQnJ3axYv5qUdxnAy7e_XY,517
63
+ pyinfra/facts/postgres.py,sha256=M7ppmVvUXy8HSNPqrc8zLPyt8JamAyGs2IO2ocbzSZ8,4187
64
+ pyinfra/facts/postgresql.py,sha256=4nusMVvGhtku86KX4O4vjSxh_MamxZy_kmTQvvy0GhE,223
65
+ pyinfra/facts/rpm.py,sha256=v9OCfTlTSqs4UQWDwnt2tVJkqHOmHZvj7Cd1g4mZ3WI,2091
66
+ pyinfra/facts/selinux.py,sha256=N0zbJrAtBeRBtxZFUHbYTLQ2L4mRV7_Oj3Cj3OA1Npw,4272
67
+ pyinfra/facts/server.py,sha256=ocUPIIveHWfe4K4-7mt7Je7TswWbKmjdu1xAF2VxaD8,19798
68
+ pyinfra/facts/snap.py,sha256=MnZDllRZ1JKLw0SKRFQ1tI6Wi05gvipQPo7m4gpL4fI,1946
69
+ pyinfra/facts/systemd.py,sha256=7uYJyP9yryq9PZT0lRH597HHQFExxebz8og2OrRQUc8,3963
70
+ pyinfra/facts/sysvinit.py,sha256=PS7yMOrVxclywKjF3BIXmxTBgn2_vpSTQrDeOly_j8Q,1490
71
+ pyinfra/facts/upstart.py,sha256=4OSQ257KmYvWWboeXiqKGbhvOmLCMCwwOBgDXKCq1XE,579
72
+ pyinfra/facts/vzctl.py,sha256=LoWXJdFVg7bWcY-aGvSk-teFaAjUjKzQHnR-VuaomZ8,627
73
+ pyinfra/facts/xbps.py,sha256=k7G0L_IgOWIQUs-UswVgs3WzqdjokSCzq0TKT3Tvok0,517
74
+ pyinfra/facts/yum.py,sha256=5nhp7iXLFyEM7MSrBqierSQpTzqyBOwMB-e658Fe838,863
75
+ pyinfra/facts/zypper.py,sha256=hCgm37xwVqgrsG6h2FMNnzW17UH64y8qZbDOVrLglIY,802
76
+ pyinfra/facts/util/__init__.py,sha256=f7HKu8z9_yFC899ajJ3RFiyivioaZeGfOI6nf9GviCs,521
77
+ pyinfra/facts/util/databases.py,sha256=EphGQApzRBXI2nG1FL9h8bozY-o4SgdQgpv9YcnCkxs,730
78
+ pyinfra/facts/util/packaging.py,sha256=4RzjDYb3HrRWZuuPlEfYHgbftLH4r1FOccN5QyIGkrk,1181
79
+ pyinfra/facts/util/win_files.py,sha256=S_IQ5kJD6ZgkEcVHajgh7BIMolLV-1q1ghIcwAS-E1Q,2561
80
+ pyinfra/operations/__init__.py,sha256=SOcW337KXIzD_LH-iJJfq14BQcCs5JzwswJ0PIzDgF4,357
81
+ pyinfra/operations/apk.py,sha256=_0vOjbSiGx6EWv9rvTmQdGnRZQ_NA_Dyd3QW1cTzFgI,2111
82
+ pyinfra/operations/apt.py,sha256=TGNO-ovc24v0T5pBzweB68Z3Hd_130sauGsmNzcXyJI,13663
83
+ pyinfra/operations/brew.py,sha256=aghLE4qyuhhRbt6fgSPV6_5fyWgTohA77Dc0gol19UU,5155
84
+ pyinfra/operations/bsdinit.py,sha256=okQUQDr2H8Z-cAdfdbPJiuGujsHLuV5gpuMZ1UlICEM,1648
85
+ pyinfra/operations/cargo.py,sha256=mXWd6pb0IR6kzJMmPHwXZN-VJ-B_y8AdOFlrRzDQOZI,1104
86
+ pyinfra/operations/choco.py,sha256=8nG0wc1tZEA0L0HTIjgR00IDiONARokyzHyKj-R3xmo,1515
87
+ pyinfra/operations/dnf.py,sha256=3154Rer6dejVB1AK-CqyJhpMVn_djaSDJrVMs62GNcE,5599
88
+ pyinfra/operations/files.py,sha256=9O_HKgmVD_z74jtSivY4pKBPrCDKKHDSy0jAB9QERHU,53639
89
+ pyinfra/operations/gem.py,sha256=2C85sOwIRMHGvmPg4uAlUVf6MokhiA7LLPqzdJRHsBg,1132
90
+ pyinfra/operations/git.py,sha256=b26tQF_4hykTy0FtxiuCkqPk9i8JdZaz-RBhH4X96yw,11789
91
+ pyinfra/operations/iptables.py,sha256=brYa4kMhZKFTu24BNds_1b6sOaG94EfqWEoWrScx-Ck,9341
92
+ pyinfra/operations/launchd.py,sha256=6HWvqoQ74idV_NStOEmFXwu0dmTv7YDvFtsK8An2Lu4,1177
93
+ pyinfra/operations/lxd.py,sha256=bKm9gsgZaruKYSL7OYFMiou-wGP4BzwIMWzjW4AZYrk,1742
94
+ pyinfra/operations/mysql.py,sha256=QcYvEQDlPESzDDoJ-HFwJFzN7ftsbsP892LMRZrmaLQ,19873
95
+ pyinfra/operations/npm.py,sha256=bUmfQsClZ2YcHiihiC7k5widIXIi6lbfx_32iyaAKfo,1499
96
+ pyinfra/operations/openrc.py,sha256=GXFoCHEEKeyQyRvrZcNYx8og4fmgmtzTVAViBzt84TE,1580
97
+ pyinfra/operations/pacman.py,sha256=QMjmsBiiw362nhZY0rEDVQL5A32MG3u7GcmX4q4PzfI,1702
98
+ pyinfra/operations/pip.py,sha256=7PpQvZHnwBGZ60V5b0XKNR4tHLW0MXJo6_6UX7HBtGY,5856
99
+ pyinfra/operations/pkg.py,sha256=rORQBbKeb-6gS0LYu0a0VdiWcDZoovcUONCaf6KMdeQ,2298
100
+ pyinfra/operations/pkgin.py,sha256=zhUyGzKjnUfGoyHbMoYMbeeMzcsiOUpBz1zIzppigJ0,1992
101
+ pyinfra/operations/postgres.py,sha256=LRoedDevQqiM5eX5Lmzb5mr_E9Od0ROVC0j18ZqaR0w,9661
102
+ pyinfra/operations/postgresql.py,sha256=agZjL2W4yxigk9ThIC0V_3wvmcWVdX308aJO24WkN6g,833
103
+ pyinfra/operations/puppet.py,sha256=eDe8D9jQbHYQ4_r4-dmEZfMASKQvj36BR8z_h8aDfw8,861
104
+ pyinfra/operations/python.py,sha256=u569cdPrPesrmzU09nwIPA3bk6TZ-Qv2QP0lJLcO_bw,2021
105
+ pyinfra/operations/selinux.py,sha256=khqWJsr9MOTyZmxP9P4dQ_7KUNlAfo5fx3Nv7kWm49w,5961
106
+ pyinfra/operations/server.py,sha256=TUJ_E61ar1sOYUykX35mYUuwtJRqOpiDZ22HYDP6Vys,36315
107
+ pyinfra/operations/snap.py,sha256=a-QtNE4Dlsavqq425TUIwpEJu4oGw8UlLRkdTFyT1F8,3049
108
+ pyinfra/operations/ssh.py,sha256=wocoaYDlOhhItItAVQCEfnVowTtkg3AP0hQ3mnpUnl0,5634
109
+ pyinfra/operations/systemd.py,sha256=89bq9VMpQ-qnupTa6U8OsBFFoDWUNwWvrLP_LN8uaxE,3944
110
+ pyinfra/operations/sysvinit.py,sha256=WzzthkmWL46MNNY6LsBZ90e37yPj0w2QyUtEAlGBwqY,4078
111
+ pyinfra/operations/upstart.py,sha256=pHb9RGnVhT14A_y6OezfOH-lmniKpiyJqpeoOJl0beE,1978
112
+ pyinfra/operations/vzctl.py,sha256=2u2CDkuDjzHBRQ54HfyfLpLrsbT8U7_05EEjbbhKUiU,3110
113
+ pyinfra/operations/xbps.py,sha256=ru3_srMBUyUXGzAsPo7WwoomfM0AeDglFv8CDqB33B0,1508
114
+ pyinfra/operations/yum.py,sha256=Ig7AzQy1C7I8XM37lWbw0nI5lzFGMoX30P8FV8-V5uA,5600
115
+ pyinfra/operations/zypper.py,sha256=z1CWv2uwWBlCLIhHna7U5DojVoKZYoUYpezJ_FM_xK8,5555
116
+ pyinfra/operations/util/__init__.py,sha256=ZAHjeCXtLo0TIOSfZ9h0Sh5IXXRCspfHs3RR1l8tQCE,366
117
+ pyinfra/operations/util/files.py,sha256=Zcet3ydNVbdT9jss0BDm6RJFyR_s6XTr0isDR60Zubw,3622
118
+ pyinfra/operations/util/packaging.py,sha256=xFtOlEX46ms7g3gDvOOInRVR1RVfgsmhLzFzsJAL_eU,9381
119
+ pyinfra/operations/util/service.py,sha256=RQjnByy-x_KdOSjOLweS12x8pOXpLkTPLlaHsntpYQE,1230
120
+ pyinfra_cli/__init__.py,sha256=G0X7tNdqT45uWuK3aHIKxMdDeCgJ7zHo6vbxoG6zy_8,284
121
+ pyinfra_cli/__main__.py,sha256=8tjq8HUll8P8naFw7pGlygwSz7u9je_MQ-0pqcDlENY,881
122
+ pyinfra_cli/commands.py,sha256=J-mCJYvDebJ8M7o3HreB2zToa871-xO6_KjVhPLeHho,1832
123
+ pyinfra_cli/exceptions.py,sha256=iptx9Zj1od7VgSbOyXs7P8tD4zAZ_fwrQFKPlpPrfS0,4806
124
+ pyinfra_cli/inventory.py,sha256=lggXV9blVqNDT2lgVkq9FQWqYBPOakoLYLbuuVQ8upE,10179
125
+ pyinfra_cli/log.py,sha256=7WEGtmf3ncF1BtXL2icUjyxeRKy-7XrCcQ2Hg4GWX5Y,2201
126
+ pyinfra_cli/main.py,sha256=MsBn0RCD5ce4GY-dDBe6vLXT0LanDrrQZpJOTIYZPBs,19715
127
+ pyinfra_cli/prints.py,sha256=za6V-yjXf-LViBW73qWcyfsajCUnf0NCG-7K0ugOA0k,9170
128
+ pyinfra_cli/util.py,sha256=f3iGIPxlUiQJ5LmUGYbEz0QrySQAKmf9xov9WvHXbrk,6364
129
+ pyinfra_cli/virtualenv.py,sha256=6j9W54JkQLN02SrZZIVwszp0GxlaaDEUWFZjBDHIWNA,2466
130
+ tests/test_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
+ tests/test_api/test_api.py,sha256=Ig2ebkNACYbHcC4_zRkxS9vj5ZEogoPqGx30ErIKChg,2413
132
+ tests/test_api/test_api_arguments.py,sha256=5k7w0_x5cnABEFOk0LQBCt5gU9iTN9lo2XS6MlJTnhQ,1961
133
+ tests/test_api/test_api_command.py,sha256=OW0ESMyS5vo38u17DHeCrSIaIkW9gMU5PSkXL7mRrq0,3204
134
+ tests/test_api/test_api_config.py,sha256=bf0mDrUie3On6zGC_hJBpv-wvSf3LHBIBzUDvkopEt0,708
135
+ tests/test_api/test_api_deploys.py,sha256=h_zbI6CK4K8SdzEr3LEAMPxOf9hnQBdi_suqiNPqHHQ,4200
136
+ tests/test_api/test_api_facts.py,sha256=fUPadZbZ5xaKSF-kmLj7XGwsNiBmfj7Av0gl8fE01Qc,10687
137
+ tests/test_api/test_api_host.py,sha256=U_VW2vTl35vR8EdyIGMKr4y0ydsDLbvHSjZDa99CyNE,1119
138
+ tests/test_api/test_api_inventory.py,sha256=VLbV0MXdRLOPvTXJF156ne6rAx1cBlFfgq_1S79s4tw,2013
139
+ tests/test_api/test_api_operations.py,sha256=GUfnuHK2NoTAGdOT4AbytT9R8i3ZZIvGP7KBfoYcYUQ,20134
140
+ tests/test_api/test_api_util.py,sha256=uHv4oLpoy1_tzOoqFA1zpdvC74SvjitZbxQwp0dmjTs,1716
141
+ tests/test_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
+ tests/test_cli/test_cli.py,sha256=nZQH0zK1SOgIr5VxBuuHH68hyzG4lhwyw_Z7EhjPtf4,6045
143
+ tests/test_cli/test_cli_deploy.py,sha256=KBnnDsiD21h7t1S2JXpEDpiMxh0AFqwxaEl0z78IE9E,4858
144
+ tests/test_cli/test_cli_exceptions.py,sha256=02sjC6rMptuqchgcdjdsVNQbSQYW6HwGutSy6Q6sMs4,3088
145
+ tests/test_cli/test_cli_util.py,sha256=-Ehnj0cO-EkF-6KLxcPPcFeuAUMTz-fKITrxhuiYhV4,2562
146
+ tests/test_cli/test_context_objects.py,sha256=JiUTwQP7yvcqA47Kq9jtdsB_Z8nxGMZN46d9pR--FYA,2130
147
+ tests/test_cli/util.py,sha256=kp_-XsGnTyDgG6IHWorYzl5VD_WLe77dKOH007TDOUE,338
148
+ tests/test_connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
+ tests/test_connectors/test_chroot.py,sha256=QK7YgFPXzHh8y363-tmHvzZ0Ok5PVJWFTDAvwt91eac,5907
150
+ tests/test_connectors/test_docker.py,sha256=0EjkfhCHpLCfL4X-AIdMNw5ASaseY0tbRAn7T_TAkMQ,6566
151
+ tests/test_connectors/test_dockerssh.py,sha256=MaC9IK1OZDiqoIsuLOZBJnPDglsMoPDoL19LQtXsyCE,9303
152
+ tests/test_connectors/test_local.py,sha256=N_FkejDZKu7XLnKeApqfBARYMyxf-hRXCQJrXLHvwRg,7442
153
+ tests/test_connectors/test_ssh.py,sha256=zYL0FbRXzqkYJslhmVeUgSkcHtozhmvZfRcaqDrYKvI,40386
154
+ tests/test_connectors/test_sshuserclient.py,sha256=2PQNLPhNL6lBACc6tQuXmPoog-9L6AdDQNrA-rEw1_8,5734
155
+ tests/test_connectors/test_terraform.py,sha256=Z5MhgDeRDFumu-GlbjMD0ZRkecwBIPP8C8ZVg-mq7C8,3743
156
+ tests/test_connectors/test_util.py,sha256=hQir0WyjH0LEF6xvIyHNyqdI5pkJX6qUR9287MgO2bY,4647
157
+ tests/test_connectors/test_vagrant.py,sha256=27qRB7ftjEPaj4ejBNZ-rR4Ou1AD1VyVcf2XjwZPG3M,3640
158
+ pyinfra-3.0b2.dist-info/LICENSE.md,sha256=gwC95tUll0gwB32tHNkTAasN7Sb6vjWzXa305NwClbI,1076
159
+ pyinfra-3.0b2.dist-info/METADATA,sha256=lISn-ii_LETvqwvTJMl5HZ4oa1jNndtp6M-Q1Q8TSzk,8322
160
+ pyinfra-3.0b2.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
161
+ pyinfra-3.0b2.dist-info/entry_points.txt,sha256=BraEFyquy05M8ch33HZXOHoH_m2BTqejL3xX3NrpzOM,471
162
+ pyinfra-3.0b2.dist-info/top_level.txt,sha256=2K6D1mK35JTSEBgOfEPV-N-uA2SDErxGiE0J-HUMMVI,26
163
+ pyinfra-3.0b2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.3)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
pyinfra_cli/exceptions.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import abc
2
2
  import sys
3
3
  from inspect import getframeinfo
4
- from os import path
5
4
  from traceback import format_exception, format_tb, walk_tb
6
5
  from types import TracebackType
7
6
 
@@ -24,10 +23,6 @@ def get_frame_line_from_tb(tb: TracebackType):
24
23
  info = getframeinfo(frame)
25
24
  if info.filename.startswith(PYINFRA_INSTALL_DIR):
26
25
  continue
27
- if info.filename.startswith("/"):
28
- continue
29
- if not path.exists(info.filename):
30
- continue
31
26
  return info
32
27
 
33
28
 
pyinfra_cli/inventory.py CHANGED
@@ -1,4 +1,3 @@
1
- import re
2
1
  import socket
3
2
  from collections import defaultdict
4
3
  from os import listdir, path
@@ -81,32 +80,52 @@ def _get_any_tuple_first(item: Union[T, Tuple[T, Any]]) -> T:
81
80
  return item[0] if isinstance(item, tuple) else item
82
81
 
83
82
 
83
+ def _resolves_to_host(maybe_host: str) -> bool:
84
+ """Check if a string resolves to a valid IP address."""
85
+ try:
86
+ # Use getaddrinfo to support IPv6 hosts
87
+ socket.getaddrinfo(maybe_host, port=None)
88
+ return True
89
+ except socket.gaierror:
90
+ return False
91
+
92
+
84
93
  def make_inventory(
85
94
  inventory: str,
86
95
  override_data=None,
87
96
  cwd: Optional[str] = None,
88
97
  group_data_directories=None,
89
98
  ):
90
- inventory_func = None
91
-
92
- # (Un)fortunately the CLI is pretty flexible for inventory inputs; we support a single hostname,
93
- # a Python module.function import or a Python file path. All of these are kind of similar, and
94
- # we want error handling to be a good user experience.
95
- # Thus, we'll check for everything but also drop a warning to the console if the inventory looks
96
- # like either an import or hostname but neither works.
97
- if re.match("[a-zA-Z0-9\\._]+[\\.:][a-zA-Z0-9_]+", inventory):
98
- # First, try loading the inventory as if it's a Python import function
99
+ # (Un)fortunately the CLI is pretty flexible for inventory inputs; we support inventory files, a
100
+ # single hostname, list of hosts, connectors, and python module.function or module:function
101
+ # imports.
102
+ #
103
+ # We check first for an inventory file, a list of hosts or anything with a connector, because
104
+ # (1) an inventory file is a common use case and (2) no other option can have a comma or an @
105
+ # symbol in them.
106
+ is_path_or_host_list_or_connector = (
107
+ path.exists(inventory) or "," in inventory or "@" in inventory
108
+ )
109
+ if not is_path_or_host_list_or_connector:
110
+ # Next, try loading the inventory from a python function. This happens before checking for a
111
+ # single-host inventory, so that your command does not stop working because somebody
112
+ # registered the domain `my.module.name`.
99
113
  inventory_func = try_import_module_attribute(inventory, raise_for_none=False)
100
- if inventory_func is None:
101
- try:
102
- socket.gethostbyname(inventory)
103
- except socket.gaierror:
104
- logger.warning(f"{inventory} is neither a valid Python import or hostname.")
105
-
106
- if inventory_func is None:
107
- # If not an import, load as if from the filesystem *or* comma separated list, which also
108
- # loads any all.py group data files (imported functions do not load group data).
114
+
115
+ # If the inventory does not refer to a module, we finally check if it refers to a reachable
116
+ # host
117
+ if inventory_func is None and _resolves_to_host(inventory):
118
+ is_path_or_host_list_or_connector = True
119
+
120
+ if is_path_or_host_list_or_connector:
121
+ # The inventory is either an inventory file or a (list of) hosts
109
122
  return make_inventory_from_files(inventory, override_data, cwd, group_data_directories)
123
+ elif inventory_func is None:
124
+ logger.warn(
125
+ f"{inventory} is neither an inventory file, a (list of) hosts or connectors "
126
+ "nor refers to a python module"
127
+ )
128
+ return Inventory.empty()
110
129
  else:
111
130
  return make_inventory_from_func(inventory_func, override_data)
112
131
 
pyinfra_cli/prints.py CHANGED
@@ -237,17 +237,21 @@ def print_meta(state: "State"):
237
237
  logger.info,
238
238
  [
239
239
  pretty_op_name(state.op_meta[op_hash]),
240
- "-"
241
- if len(hosts_in_op) == 0
242
- else "{0} ({1})".format(
243
- len(hosts_in_op),
244
- truncate(", ".join(sorted(hosts_in_op)), 48),
240
+ (
241
+ "-"
242
+ if len(hosts_in_op) == 0
243
+ else "{0} ({1})".format(
244
+ len(hosts_in_op),
245
+ truncate(", ".join(sorted(hosts_in_op)), 48),
246
+ )
245
247
  ),
246
- "-"
247
- if len(hosts_maybe_in_op) == 0
248
- else "{0} ({1})".format(
249
- len(hosts_maybe_in_op),
250
- truncate(", ".join(sorted(hosts_maybe_in_op)), 48),
248
+ (
249
+ "-"
250
+ if len(hosts_maybe_in_op) == 0
251
+ else "{0} ({1})".format(
252
+ len(hosts_maybe_in_op),
253
+ truncate(", ".join(sorted(hosts_maybe_in_op)), 48),
254
+ )
251
255
  ),
252
256
  ],
253
257
  )
@@ -273,7 +277,7 @@ def print_results(state: "State"):
273
277
  hosts_in_op += 1
274
278
 
275
279
  op_meta = state.ops[host][op_hash].operation_meta
276
- if op_meta.did_succeed():
280
+ if op_meta.did_succeed(_raise_if_not_complete=False):
277
281
  if op_meta._did_change():
278
282
  hosts_in_op_success.append(host.name)
279
283
  else:
pyinfra_cli/util.py CHANGED
@@ -154,9 +154,11 @@ def try_import_module_attribute(path, prefix=None, raise_for_none=True):
154
154
  if ":" in path:
155
155
  # Allow a.module.name:function syntax
156
156
  mod_path, attr_name = path.rsplit(":", 1)
157
- else:
157
+ elif "." in path:
158
158
  # And also a.module.name.function
159
159
  mod_path, attr_name = path.rsplit(".", 1)
160
+ else:
161
+ return None
160
162
 
161
163
  possible_modules = [mod_path]
162
164
  if prefix:
@@ -390,7 +390,7 @@ class TestOperationsApi(PatchSSHTestCase):
390
390
  state = State(inventory, Config())
391
391
  connect_all(state)
392
392
 
393
- with patch("pyinfra.connectors.ssh.find_executable", lambda x: None):
393
+ with patch("pyinfra.connectors.ssh.which", lambda x: None):
394
394
  with self.assertRaises(OperationError) as context:
395
395
  add_op(state, files.rsync, "src", "dest")
396
396
 
@@ -500,6 +500,57 @@ class TestSSHConnector(TestCase):
500
500
  get_pty=False,
501
501
  )
502
502
 
503
+ @patch("pyinfra.connectors.util.getpass")
504
+ @patch("pyinfra.connectors.ssh.SSHClient")
505
+ def test_run_shell_command_sudo_password_automatic_prompt_with_special_chars_in_password(
506
+ self,
507
+ fake_ssh_client,
508
+ fake_getpass,
509
+ ):
510
+ fake_ssh = MagicMock()
511
+ first_fake_stdout = MagicMock()
512
+ second_fake_stdout = MagicMock()
513
+ third_fake_stdout = MagicMock()
514
+
515
+ first_fake_stdout.__iter__.return_value = ["sudo: a password is required\r"]
516
+ second_fake_stdout.__iter__.return_value = ["/tmp/pyinfra-sudo-askpass-XXXXXXXXXXXX"]
517
+
518
+ fake_ssh.exec_command.side_effect = [
519
+ (MagicMock(), first_fake_stdout, MagicMock()), # command w/o sudo password
520
+ (MagicMock(), second_fake_stdout, MagicMock()), # SUDO_ASKPASS_COMMAND
521
+ (MagicMock(), third_fake_stdout, MagicMock()), # command with sudo pw
522
+ ]
523
+
524
+ fake_ssh_client.return_value = fake_ssh
525
+ fake_getpass.return_value = "p@ss'word';"
526
+
527
+ inventory = make_inventory(hosts=("somehost",))
528
+ State(inventory, Config())
529
+ host = inventory.get_host("somehost")
530
+ host.connect()
531
+
532
+ command = "echo Šablony"
533
+ first_fake_stdout.channel.recv_exit_status.return_value = 1
534
+ second_fake_stdout.channel.recv_exit_status.return_value = 0
535
+ third_fake_stdout.channel.recv_exit_status.return_value = 0
536
+
537
+ out = host.run_shell_command(command, _sudo=True, print_output=True)
538
+ assert len(out) == 2
539
+
540
+ status, output = out
541
+ assert status is True
542
+
543
+ fake_ssh.exec_command.assert_any_call(("sudo -H -n sh -c 'echo Šablony'"), get_pty=False)
544
+
545
+ fake_ssh.exec_command.assert_called_with(
546
+ (
547
+ "env SUDO_ASKPASS=/tmp/pyinfra-sudo-askpass-XXXXXXXXXXXX "
548
+ """PYINFRA_SUDO_PASSWORD='p@ss'"'"'word'"'"';' """
549
+ "sudo -H -A -k sh -c 'echo Šablony'"
550
+ ),
551
+ get_pty=False,
552
+ )
553
+
503
554
  # SSH file put/get tests
504
555
  #
505
556
 
@@ -1003,7 +1054,7 @@ class TestSSHConnector(TestCase):
1003
1054
  )
1004
1055
 
1005
1056
  @patch("pyinfra.connectors.ssh.SSHClient")
1006
- @patch("time.sleep")
1057
+ @patch("pyinfra.connectors.ssh.sleep")
1007
1058
  def test_ssh_connect_fail_retry(self, fake_sleep, fake_ssh_client):
1008
1059
  for exception_class in (
1009
1060
  SSHException,
@@ -1011,6 +1062,9 @@ class TestSSHConnector(TestCase):
1011
1062
  socket_error,
1012
1063
  EOFError,
1013
1064
  ):
1065
+ fake_sleep.reset_mock()
1066
+ fake_ssh_client.reset_mock()
1067
+
1014
1068
  inventory = make_inventory(
1015
1069
  hosts=("unresposivehost",), override_data={"ssh_connect_retries": 1}
1016
1070
  )
@@ -1019,17 +1073,16 @@ class TestSSHConnector(TestCase):
1019
1073
  unresposivehost = inventory.get_host("unresposivehost")
1020
1074
  assert unresposivehost.data.ssh_connect_retries == 1
1021
1075
 
1022
- fake_ssh = MagicMock()
1023
- fake_ssh.connect.side_effect = exception_class()
1024
- fake_ssh_client.return_value = fake_ssh
1076
+ fake_ssh_client().connect.side_effect = exception_class()
1025
1077
 
1026
1078
  with self.assertRaises(ConnectError):
1027
1079
  unresposivehost.connect(show_errors=False, raise_exceptions=True)
1028
- assert fake_sleep.called_once()
1029
- assert fake_ssh_client.connect.called_twice()
1080
+
1081
+ fake_sleep.assert_called_once()
1082
+ assert fake_ssh_client().connect.call_count == 2
1030
1083
 
1031
1084
  @patch("pyinfra.connectors.ssh.SSHClient")
1032
- @patch("time.sleep")
1085
+ @patch("pyinfra.connectors.ssh.sleep")
1033
1086
  def test_ssh_connect_fail_success(self, fake_sleep, fake_ssh_client):
1034
1087
  for exception_class in (
1035
1088
  SSHException,
@@ -1037,6 +1090,9 @@ class TestSSHConnector(TestCase):
1037
1090
  socket_error,
1038
1091
  EOFError,
1039
1092
  ):
1093
+ fake_sleep.reset_mock()
1094
+ fake_ssh_client.reset_mock()
1095
+
1040
1096
  inventory = make_inventory(
1041
1097
  hosts=("unresposivehost",), override_data={"ssh_connect_retries": 1}
1042
1098
  )
@@ -1045,11 +1101,8 @@ class TestSSHConnector(TestCase):
1045
1101
  unresposivehost = inventory.get_host("unresposivehost")
1046
1102
  assert unresposivehost.data.ssh_connect_retries == 1
1047
1103
 
1048
- connection = MagicMock()
1049
- fake_ssh = MagicMock()
1050
- fake_ssh.connect.side_effect = [exception_class(), connection]
1051
- fake_ssh_client.return_value = fake_ssh
1104
+ fake_ssh_client().connect.side_effect = [exception_class(), MagicMock()]
1052
1105
 
1053
1106
  unresposivehost.connect(show_errors=False, raise_exceptions=True)
1054
- assert fake_sleep.called_once()
1055
- assert fake_ssh_client.connect.called_twice()
1107
+ fake_sleep.assert_called_once()
1108
+ assert fake_ssh_client().connect.call_count == 2
@@ -75,7 +75,7 @@ class TestVagrantConnector(TestCase):
75
75
  (
76
76
  "@vagrant/ubuntu16",
77
77
  {
78
- "ssh_port": "2222",
78
+ "ssh_port": 2222,
79
79
  "ssh_user": "vagrant",
80
80
  "ssh_hostname": "127.0.0.1",
81
81
  "ssh_key": "path/to/key",
@@ -85,7 +85,7 @@ class TestVagrantConnector(TestCase):
85
85
  (
86
86
  "@vagrant/centos7",
87
87
  {
88
- "ssh_port": "2200",
88
+ "ssh_port": 2200,
89
89
  "ssh_user": "vagrant",
90
90
  "ssh_hostname": "127.0.0.1",
91
91
  "ssh_key": "path/to/key",
@@ -109,7 +109,7 @@ class TestVagrantConnector(TestCase):
109
109
  (
110
110
  "@vagrant/ubuntu16",
111
111
  {
112
- "ssh_port": "2222",
112
+ "ssh_port": 2222,
113
113
  "ssh_user": "vagrant",
114
114
  "ssh_hostname": "127.0.0.1",
115
115
  "ssh_key": "path/to/key",