Merge branch 'main' into bmw/esbuild
This commit is contained in:
Коммит
ada839ed3d
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -1,3 +1,23 @@
|
|||
## 1.27.0 - 16 October 2023
|
||||
### Added
|
||||
- Enhanced registries functionality: [#869](https://github.com/microsoft/vscode-docker/issues/869)
|
||||
- Allows third party providers to contribute to the registries view.
|
||||
- Added GitHub Container Registry support.
|
||||
- GitLab Container Registry support will be moved to a separate extension. We will provide a link to install once it's published.
|
||||
|
||||
### Fixed
|
||||
- Resolved issues with opening .NET web apps in browsers built with .NET SDK containers. [#4006](https://github.com/microsoft/vscode-docker/issues/4006)
|
||||
- Fixed several Dockerfile language server issues. [#4056](https://github.com/microsoft/vscode-docker/issues/4056), [#4054](https://github.com/microsoft/vscode-docker/issues/4054), [#4051](https://github.com/microsoft/vscode-docker/issues/4051), [#4012](https://github.com/microsoft/vscode-docker/issues/4012)
|
||||
|
||||
## 1.26.1 - 13 September 2023
|
||||
### Added
|
||||
- Updated .NET Dockerfile scaffolding to utilize the latest .NET 8 image names. [#4015](https://github.com/microsoft/vscode-docker/issues/4015)
|
||||
- Added support for multiple .dockerignore file naming conventions specific to language modes. [#4059](https://github.com/microsoft/vscode-docker/issues/4059)
|
||||
- Integrated the container client package. [#3982](https://github.com/microsoft/vscode-docker/pull/3982)
|
||||
|
||||
### Fixed
|
||||
- Enhanced debugging experience on arm64 machines. [#4040](https://github.com/microsoft/vscode-docker/issues/4040)
|
||||
|
||||
## 1.26.0 - 10 July 2023
|
||||
### Added
|
||||
* Added support for debugging .NET projects with .NET SDK container build. [#3808](https://github.com/microsoft/vscode-docker/issues/3808)
|
||||
|
|
|
@ -1563,74 +1563,6 @@ END OF TERMS AND CONDITIONS
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
typescript 1.0.0 - Apache-2.0
|
||||
</summary>
|
||||
<p><a href="http://typescriptlang.org/">http://typescriptlang.org/</a></p>
|
||||
<ul><li>Copyright (c) Microsoft Corporation.</li>
|
||||
<li>Copyright (c) 2010-2011 Dojo Foundation.</li></ul>
|
||||
<pre>
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -1698,78 +1630,6 @@ If the Work includes a "NOTICE" text file as part of its distribution,
|
|||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
typescript 5.1.3 - Apache-2.0
|
||||
</summary>
|
||||
<p><a href="https://www.typescriptlang.org/">https://www.typescriptlang.org/</a></p>
|
||||
<ul><li>(c) by W3C</li>
|
||||
<li>Copyright (c) 2018 WHATWG</li>
|
||||
<li>Copyright (c) Microsoft Corporation</li>
|
||||
<li>Copyright (c) 1991-2017 Unicode, Inc.</li>
|
||||
<li>Copyright (c) 2018 The Khronos Group Inc.</li>
|
||||
<li>Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers</li></ul>
|
||||
<pre>
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
</pre>
|
||||
|
@ -2734,49 +2594,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
diff 1.0.0 - BSD-3-Clause
|
||||
</summary>
|
||||
|
||||
<ul><li>Copyright (c) 2009-2011, Kevin Decker kpdecker@gmail.com</li>
|
||||
<li>Copyright (c) 2009-2011, Kevin Decker <kpdecker@gmail.com></li></ul>
|
||||
<pre>
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2009-2011, Kevin Decker <kpdecker@gmail.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of Kevin Decker nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -4068,26 +3885,6 @@ PERFORMANCE OF THIS SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
ini 1.0.0 - ISC
|
||||
</summary>
|
||||
|
||||
|
||||
<pre>
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
Copyright (c) 1995-2003 by Internet Software Consortium
|
||||
|
||||
Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -4115,46 +3912,6 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
javascript 1.0.0 - ISC
|
||||
</summary>
|
||||
<p><a href="https://github.com/npm/deprecate-holder#readme">https://github.com/npm/deprecate-holder#readme</a></p>
|
||||
|
||||
<pre>
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
Copyright (c) 1995-2003 by Internet Software Consortium
|
||||
|
||||
Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
julia 1.0.0 - ISC
|
||||
</summary>
|
||||
<p><a href="https://github.com/npm/deprecate-holder#readme">https://github.com/npm/deprecate-holder#readme</a></p>
|
||||
|
||||
<pre>
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
Copyright (c) 1995-2003 by Internet Software Consortium
|
||||
|
||||
Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -4482,7 +4239,7 @@ License, as follows:
|
|||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
semver 5.7.1 - ISC
|
||||
semver 5.7.2 - ISC
|
||||
</summary>
|
||||
<p><a href="https://github.com/npm/node-semver#readme">https://github.com/npm/node-semver#readme</a></p>
|
||||
<ul><li>Copyright Isaac Z.</li>
|
||||
|
@ -4511,7 +4268,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
semver 7.5.0 - ISC
|
||||
semver 7.5.2 - ISC
|
||||
</summary>
|
||||
<p><a href="https://github.com/npm/node-semver#readme">https://github.com/npm/node-semver#readme</a></p>
|
||||
<ul><li>Copyright Isaac Z. Schlueter</li>
|
||||
|
@ -4669,31 +4426,6 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
yaml 1.0.0 - ISC
|
||||
</summary>
|
||||
<p><a href="https://eemeli.org/yaml/">https://eemeli.org/yaml/</a></p>
|
||||
<ul><li>Copyright 2018 Eemeli Aro <eemeli@gmail.com></li></ul>
|
||||
<pre>
|
||||
Copyright 2018 Eemeli Aro <eemeli@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -4746,6 +4478,41 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
@aashutoshrathi/word-wrap 1.2.6 - MIT
|
||||
</summary>
|
||||
<p><a href="https://github.com/aashutoshrathi/word-wrap">https://github.com/aashutoshrathi/word-wrap</a></p>
|
||||
<ul><li>Copyright (c) 2014-2016, Jon Schlinkert</li>
|
||||
<li>Copyright (c) 2014-2023, Jon Schlinkert</li>
|
||||
<li>Copyright (c) 2017, Jon Schlinkert (https://github.com/jonschlinkert)</li></ul>
|
||||
<pre>
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2016, Jon Schlinkert
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -8538,39 +8305,6 @@ THE SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
coffeescript 1.0.0 - MIT
|
||||
</summary>
|
||||
|
||||
<ul><li>Copyright (c) 2010 Jeremy Ashkenas</li></ul>
|
||||
<pre>
|
||||
Copyright (c) 2010 Jeremy Ashkenas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -8989,26 +8723,6 @@ THE SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
css 1.0.0 - MIT
|
||||
</summary>
|
||||
|
||||
<ul><li>Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca></li></ul>
|
||||
<pre>
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -9271,39 +8985,6 @@ furnished to do so, subject to the following conditions:
|
|||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
docker 1.0.0 - MIT
|
||||
</summary>
|
||||
<p><a href="http://jbt.github.com/docker">http://jbt.github.com/docker</a></p>
|
||||
<ul><li>Copyright (c) 2015 James Taylor</li></ul>
|
||||
<pre>
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 James Taylor
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
@ -10311,27 +9992,6 @@ SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
github 0.0.1 - MIT
|
||||
</summary>
|
||||
<p><a href="http://github.com/ajaxorg/node-github.git">http://github.com/ajaxorg/node-github.git</a></p>
|
||||
<ul><li>Copyright 2010 Ajax.org B.V.</li>
|
||||
<li>Copyright (c) 2010 ajax.org B.V</li></ul>
|
||||
<pre>
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -10395,26 +10055,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRES
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
go 1.0.0 - MIT
|
||||
</summary>
|
||||
|
||||
|
||||
<pre>
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -10447,84 +10087,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||
SOFTWARE.
|
||||
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
grunt 1.0.0 - MIT
|
||||
</summary>
|
||||
<p><a href="http://gruntjs.com/">http://gruntjs.com/</a></p>
|
||||
<ul><li>Copyright jQuery Foundation and other contributors, https://jquery.org</li></ul>
|
||||
<pre>
|
||||
Copyright jQuery Foundation and other contributors, https://jquery.org/
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals. For exact contribution history, see the revision history
|
||||
available at https://github.com/gruntjs/grunt .
|
||||
|
||||
The following license applies to all parts of this software except as
|
||||
documented below:
|
||||
|
||||
====
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
All files located in the node_modules directory are externally maintained
|
||||
libraries used by this software which have their own licenses; we recommend
|
||||
you read them, as their terms may differ from the terms above.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
gulp 1.0.0 - MIT
|
||||
</summary>
|
||||
<p><a href="http://github.com/wearefractal/gulp">http://github.com/wearefractal/gulp</a></p>
|
||||
<ul><li>Copyright (c) 2013 Fractal <contact@wearefractal.com></li></ul>
|
||||
<pre>
|
||||
Copyright (c) 2013 Fractal <contact@wearefractal.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
|
@ -10723,28 +10285,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
html 1.0.0 - MIT
|
||||
</summary>
|
||||
<p><a href="https://github.com/maxogden/commonjs-html-prettyprinter">https://github.com/maxogden/commonjs-html-prettyprinter</a></p>
|
||||
<ul><li>Copyright (c) 2014-2015 Max Ogden and contributors</li>
|
||||
<li>Copyright (c) 2007-2013 Einar Lielmanis and contributors.</li></ul>
|
||||
<pre>
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2015 Max Ogden and contributors
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -11060,26 +10600,6 @@ SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
ipynb 1.0.0 - MIT
|
||||
</summary>
|
||||
<p><a href="https://github.com/finnp/ipynb">https://github.com/finnp/ipynb</a></p>
|
||||
|
||||
<pre>
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -12139,26 +11659,6 @@ terms above.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
log 1.0.0 - MIT
|
||||
</summary>
|
||||
|
||||
<ul><li>Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca></li></ul>
|
||||
<pre>
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -12943,7 +12443,7 @@ SOFTWARE.
|
|||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
optionator 0.9.1 - MIT
|
||||
optionator 0.9.3 - MIT
|
||||
</summary>
|
||||
<p><a href="https://github.com/gkz/optionator">https://github.com/gkz/optionator</a></p>
|
||||
<ul><li>Copyright (c) George Zahariev</li></ul>
|
||||
|
@ -14598,41 +14098,6 @@ SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
swift 1.0.0 - MIT
|
||||
</summary>
|
||||
<p><a href="http://github.com/131/swift">http://github.com/131/swift</a></p>
|
||||
<ul><li>Copyright (c) 2018 - Francois Leurent</li></ul>
|
||||
<pre>
|
||||
Copyright (c) 2018 - Francois Leurent
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of OVH and or its trademarks
|
||||
shall not be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Software without prior written authorization from OVH.
|
||||
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -15331,26 +14796,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRES
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
vscode-json-languageserver 1.3.4 - MIT
|
||||
</summary>
|
||||
|
||||
<ul><li>Copyright (c) Microsoft Corporation.</li></ul>
|
||||
<pre>
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
@ -15924,40 +15369,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
xml 1.0.0 - MIT
|
||||
</summary>
|
||||
<p><a href="http://github.com/dylang/node-xml">http://github.com/dylang/node-xml</a></p>
|
||||
<ul><li>Copyright (c) 2011 Dylan Greene <dylang@gmail.com></li>
|
||||
<li>Copyright (c) 2011-2014 Dylan Greene <dylang@gmail.com></li></ul>
|
||||
<pre>
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 Dylan Greene <dylang@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details>
|
||||
<summary>
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
{
|
||||
"name": "vscode-docker",
|
||||
"version": "1.26.0",
|
||||
"version": "1.27.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vscode-docker",
|
||||
"version": "1.26.0",
|
||||
"version": "1.27.0",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"dependencies": {
|
||||
"@azure/arm-authorization": "^9.0.0",
|
||||
"@azure/arm-containerregistry": "^10.1.0",
|
||||
"@azure/storage-blob": "^12.14.0",
|
||||
"@microsoft/compose-language-service": "^0.2.0",
|
||||
"@microsoft/vscode-azext-azureappservice": "^1.0.2",
|
||||
"@microsoft/vscode-azext-azureutils": "^1.1.5",
|
||||
"@microsoft/vscode-azext-utils": "^1.2.2",
|
||||
"@microsoft/vscode-azext-azureappservice": "~2.0",
|
||||
"@microsoft/vscode-azext-azureauth": "^1.1.2",
|
||||
"@microsoft/vscode-azext-azureutils": "^2.0.0",
|
||||
"@microsoft/vscode-azext-utils": "^2.1.1",
|
||||
"@microsoft/vscode-container-client": "^0.1.0",
|
||||
"@microsoft/vscode-docker-registries": "^0.1.3",
|
||||
"dayjs": "^1.11.7",
|
||||
"dockerfile-language-server-nodejs": "^0.10.2",
|
||||
"dockerfile-language-server-nodejs": "^0.11.0",
|
||||
"fs-extra": "^11.1.1",
|
||||
"gradle-to-js": "^2.0.1",
|
||||
"handlebars": "^4.7.7",
|
||||
"node-fetch": "^2.6.9",
|
||||
"semver": "^7.5.2",
|
||||
"tar": "^6.1.13",
|
||||
"tree-kill": "^1.2.2",
|
||||
"vscode-languageclient": "^8.1.0",
|
||||
"vscode-tas-client": "^0.1.63",
|
||||
"xml2js": "^0.5.0"
|
||||
|
@ -257,6 +259,23 @@
|
|||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/arm-subscriptions": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/arm-subscriptions/-/arm-subscriptions-5.1.0.tgz",
|
||||
"integrity": "sha512-6BeOF2eQWNLq22ch7xP9RxYnPjtGev54OUCGggKOWoOvmesK7jUZbIyLk8JeXDT21PEl7iyYnxw78gxJ7zBxQw==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-client": "^1.6.1",
|
||||
"@azure/core-lro": "^2.2.0",
|
||||
"@azure/core-paging": "^1.2.0",
|
||||
"@azure/core-rest-pipeline": "^1.8.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-auth": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz",
|
||||
|
@ -403,8 +422,7 @@
|
|||
"node_modules/@azure/ms-rest-azure-env": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz",
|
||||
"integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==",
|
||||
"peer": true
|
||||
"integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw=="
|
||||
},
|
||||
"node_modules/@azure/storage-blob": {
|
||||
"version": "12.14.0",
|
||||
|
@ -1030,9 +1048,9 @@
|
|||
"integrity": "sha512-n1VPsljTSkthsAFYdiWfC+DKzK2WwcRp83Y1YAqdX552BstvsDjft9YXppjUzp11BPsapDoO1LDgrDB0XVsfNQ=="
|
||||
},
|
||||
"node_modules/@microsoft/vscode-azext-azureappservice": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappservice/-/vscode-azext-azureappservice-1.0.2.tgz",
|
||||
"integrity": "sha512-YaKqYIkeX0kH8KgUsUOUrr7RA9ghtFnZXcS8RfSIs6/HmssN3pYdKEjlq4Yq3U5oOkX8Cq5xlujHoCiUaUsh7Q==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappservice/-/vscode-azext-azureappservice-2.0.0.tgz",
|
||||
"integrity": "sha512-evtnwjKZk6wBGXJQy3sNEEFdGztQAT09HeuyU4qpFwWRBIoPE1wg0TO7S7psc+N5W8sFiWBy3h15mOlU6daocA==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.4",
|
||||
"@azure/arm-appinsights": "^5.0.0-beta.4",
|
||||
|
@ -1043,8 +1061,8 @@
|
|||
"@azure/core-client": "^1.7.2",
|
||||
"@azure/core-rest-pipeline": "^1.10.3",
|
||||
"@azure/storage-blob": "^12.3.0",
|
||||
"@microsoft/vscode-azext-azureutils": "^1.1.5",
|
||||
"@microsoft/vscode-azext-utils": "^1.2.2",
|
||||
"@microsoft/vscode-azext-azureutils": "^2.0.0",
|
||||
"@microsoft/vscode-azext-utils": "^2.0.0",
|
||||
"dayjs": "^1.11.2",
|
||||
"fs-extra": "^10.0.0",
|
||||
"globby": "^11.0.2",
|
||||
|
@ -1056,7 +1074,7 @@
|
|||
},
|
||||
"peerDependencies": {
|
||||
"@azure/ms-rest-azure-env": "^2.0.0",
|
||||
"@microsoft/vscode-azext-azureappsettings": "^0.1.0"
|
||||
"@microsoft/vscode-azext-azureappsettings": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/vscode-azext-azureappservice/node_modules/fs-extra": {
|
||||
|
@ -1073,18 +1091,27 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@microsoft/vscode-azext-azureappsettings": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappsettings/-/vscode-azext-azureappsettings-0.1.0.tgz",
|
||||
"integrity": "sha512-oxq3tYgb9yt/Vxh8larmd3XTRW0FEaIfhtzEpZyb0YcqFaTEhY299J9oogiu78+dGDztgR3y8g0AhDHBpEmCiQ==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureappsettings/-/vscode-azext-azureappsettings-0.2.0.tgz",
|
||||
"integrity": "sha512-fHv+m+dOluuYgPCQ7Mt8HoDgguWy8zHWofP3T6uxkuDF8VAJbjl9LFYHwV0frVcK4Qgxcj95QDjw5AMSUMHtqw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@microsoft/vscode-azext-utils": "^1.2.1"
|
||||
"@microsoft/vscode-azext-utils": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/vscode-azext-azureauth": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureauth/-/vscode-azext-azureauth-1.1.2.tgz",
|
||||
"integrity": "sha512-cacmiEv1GiofOKaQzgRqXrDqPoFc3HAGiaer+ENNrdeW6elks0o5Z0oXkTIauS26yeYQUUaooB6DezvQU6LC+Q==",
|
||||
"dependencies": {
|
||||
"@azure/arm-subscriptions": "^5.1.0",
|
||||
"@azure/ms-rest-azure-env": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/vscode-azext-azureutils": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-1.1.5.tgz",
|
||||
"integrity": "sha512-iG89BMp57ydHHl3NbW+T9vn/zksDOoYxgebAZmoF6fZzrIJn2VVmzWGllBsfBa1vEx/qDrvdfT6juSY0UtLe0w==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-2.0.2.tgz",
|
||||
"integrity": "sha512-r+7NqedkvfFazztO7kxT1AU/B/UfiGhTDlRtFHx+W5bhp+yJw0eOtX8VPJXXSXoOaq2dzuGBwxAQ0bDD1lNPcQ==",
|
||||
"dependencies": {
|
||||
"@azure/arm-resources": "^5.0.0",
|
||||
"@azure/arm-resources-profile-2020-09-01-hybrid": "^2.0.0",
|
||||
|
@ -1094,7 +1121,7 @@
|
|||
"@azure/core-client": "^1.6.0",
|
||||
"@azure/core-rest-pipeline": "^1.9.0",
|
||||
"@azure/logger": "^1.0.4",
|
||||
"@microsoft/vscode-azext-utils": "^1.2.2",
|
||||
"@microsoft/vscode-azext-utils": "^2.0.0",
|
||||
"semver": "^7.3.7",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
|
@ -1111,9 +1138,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@microsoft/vscode-azext-utils": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-1.2.2.tgz",
|
||||
"integrity": "sha512-mOTcJF8IMsz+Xn8QTUP1AC3K5tPl/3f17L2xGTTtLeV/HJ2sTh/3712NFuN58tnOwdISdazId4tHwaqUta8HEA==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-2.1.1.tgz",
|
||||
"integrity": "sha512-MUrBET1YzS0QmpMY9ZcRjZe9/U0vmGtYI9hRTMB7NYBtutUF19+Y7W6k6G7Odlnn3MjRIrc8ZMmumvsVqlxhPg==",
|
||||
"dependencies": {
|
||||
"@microsoft/vscode-azureresources-api": "^2.0.4",
|
||||
"@vscode/extension-telemetry": "^0.6.2",
|
||||
|
@ -1142,6 +1169,24 @@
|
|||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-azureresources-api/-/vscode-azureresources-api-2.0.4.tgz",
|
||||
"integrity": "sha512-LridV1h2rCydrBzEpwy+pUIUx61GpZNwrK04G7LdlhoxHrzuM/WAoy8jXaSC/FSKSsXD1QXuE6u/YofEfsuKeg=="
|
||||
},
|
||||
"node_modules/@microsoft/vscode-container-client": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-container-client/-/vscode-container-client-0.1.0.tgz",
|
||||
"integrity": "sha512-qA9xMZWH6JvhovJLlbxgyPRgtEj8cA7ktJtJPykJbycC+F/vwt1j2/GyWhrgwlkTlmmM1aGOnF9nSD84DGhABw==",
|
||||
"dependencies": {
|
||||
"dayjs": "^1.11.2",
|
||||
"tree-kill": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/vscode-docker-registries": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/vscode-docker-registries/-/vscode-docker-registries-0.1.3.tgz",
|
||||
"integrity": "sha512-3ORzbV3Ea764Nh3QuyGsqUTPTCk6T45KXBc+j7MUirJ39lUZAAeiXwAC85UHT40xPURhgQdqHdbhDz3kZ1Vw7g==",
|
||||
"dependencies": {
|
||||
"dayjs": "^1.11.7",
|
||||
"node-fetch": "^2.6.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
@ -2734,25 +2779,26 @@
|
|||
"integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="
|
||||
},
|
||||
"node_modules/dockerfile-ast": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-ast/-/dockerfile-ast-0.5.0.tgz",
|
||||
"integrity": "sha512-YsRrWww6mKRS1HK32gbherPlgfvwS593ZeDegb5glNCBJgByICAYZCP5F+njY6TSB0eiPdFgCU9RkuO516mLFQ==",
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-ast/-/dockerfile-ast-0.6.1.tgz",
|
||||
"integrity": "sha512-m3rH2qHHU2pSTCppXgJT+1KLxhvkdROOxVPof5Yz4IPGSw6K+x0B0/RFdYgXN5zsIUTlbOSRyfDCv3/uVhnNmg==",
|
||||
"dependencies": {
|
||||
"vscode-languageserver-textdocument": "^1.0.1",
|
||||
"vscode-languageserver-types": "^3.17.0-next.3"
|
||||
"vscode-languageserver-textdocument": "^1.0.8",
|
||||
"vscode-languageserver-types": "^3.17.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/dockerfile-language-server-nodejs": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-language-server-nodejs/-/dockerfile-language-server-nodejs-0.10.2.tgz",
|
||||
"integrity": "sha512-vLbaeYv4h3XEzrZ9JOhP6bD1eLzbzGzFFF03F3Ofd6kh9PU2aGBS/LVjd/w1omCyNV2LHviFX0ZGHINmWsZYyw==",
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-language-server-nodejs/-/dockerfile-language-server-nodejs-0.11.0.tgz",
|
||||
"integrity": "sha512-kv97EVYcKXh4SiteaVX8LDSwpcdAOIJM/3Wm6rWxTH4gLbozocDekoU5YpX1X2kKOI4L5gvzFIhzgxqPhFnRzg==",
|
||||
"dependencies": {
|
||||
"dockerfile-language-service": "0.10.2",
|
||||
"dockerfile-utils": "0.11.0",
|
||||
"vscode-languageserver": "^8.0.0-next.2"
|
||||
"dockerfile-language-service": "0.11.0",
|
||||
"dockerfile-utils": "0.15.0",
|
||||
"vscode-languageserver": "~8.0.0",
|
||||
"vscode-languageserver-textdocument": "~1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"docker-langserver": "bin/docker-langserver"
|
||||
|
@ -2761,27 +2807,61 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/dockerfile-language-service": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-language-service/-/dockerfile-language-service-0.10.2.tgz",
|
||||
"integrity": "sha512-W561U9gj5Eol55j/hanLRPVarXDq+WXPai1lG5f1fW7/kYElsmWJZoRd585SQBahvC9VlJfFAs6IpzZlvN41Hg==",
|
||||
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-jsonrpc": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
|
||||
"integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-languageserver": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz",
|
||||
"integrity": "sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==",
|
||||
"dependencies": {
|
||||
"dockerfile-ast": "0.5.0",
|
||||
"dockerfile-utils": "0.11.0",
|
||||
"vscode-languageserver-types": "3.17.0-next.3"
|
||||
"vscode-languageserver-protocol": "3.17.2"
|
||||
},
|
||||
"bin": {
|
||||
"installServerIntoExtension": "bin/installServerIntoExtension"
|
||||
}
|
||||
},
|
||||
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-languageserver-protocol": {
|
||||
"version": "3.17.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz",
|
||||
"integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==",
|
||||
"dependencies": {
|
||||
"vscode-jsonrpc": "8.0.2",
|
||||
"vscode-languageserver-types": "3.17.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dockerfile-language-server-nodejs/node_modules/vscode-languageserver-types": {
|
||||
"version": "3.17.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
|
||||
"integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
|
||||
},
|
||||
"node_modules/dockerfile-language-service": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-language-service/-/dockerfile-language-service-0.11.0.tgz",
|
||||
"integrity": "sha512-Y0TtqZNnI3EC5g/zCZitNV191oZoYCva2r6lt0T1k+W5VX1kjz0vwKbkgBIpk2Rzh4fQlYFJALALtvd/kw5ixA==",
|
||||
"dependencies": {
|
||||
"dockerfile-ast": "0.6.1",
|
||||
"dockerfile-utils": "0.15.0",
|
||||
"vscode-languageserver-textdocument": "1.0.8",
|
||||
"vscode-languageserver-types": "3.17.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/dockerfile-utils": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-utils/-/dockerfile-utils-0.11.0.tgz",
|
||||
"integrity": "sha512-b7uGmYAeneg/zP63vfUrkIWw4frvtviXe7QGV0Vw58kJwyEYmrKxjm+N+NbBgk6mwq5FEIDT5rx08pBpjstpEw==",
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/dockerfile-utils/-/dockerfile-utils-0.15.0.tgz",
|
||||
"integrity": "sha512-hV2OExB797C3/GlOloywmMZzu3MPmzMziGuCaPWh/m9qHgTyfN4+EI3b6xhHDXy78PU0GqwvHnZVX7wfpqOCkg==",
|
||||
"dependencies": {
|
||||
"dockerfile-ast": "0.5.0",
|
||||
"vscode-languageserver-textdocument": "^1.0.1",
|
||||
"vscode-languageserver-types": "^3.17.0-next.3"
|
||||
"dockerfile-ast": "0.6.1",
|
||||
"vscode-languageserver-textdocument": "^1.0.8",
|
||||
"vscode-languageserver-types": "^3.17.3"
|
||||
},
|
||||
"bin": {
|
||||
"dockerfile-utils": "bin/dockerfile-utils"
|
||||
|
@ -3509,9 +3589,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/get-func-name": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
|
||||
"integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
|
||||
"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
|
@ -4747,9 +4827,9 @@
|
|||
"optional": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
|
||||
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
|
@ -6300,20 +6380,15 @@
|
|||
"vscode-languageserver-types": "3.17.3"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-protocol/node_modules/vscode-languageserver-types": {
|
||||
"version": "3.17.3",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
|
||||
"integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
|
||||
},
|
||||
"node_modules/vscode-languageserver-textdocument": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz",
|
||||
"integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q=="
|
||||
},
|
||||
"node_modules/vscode-languageserver-types": {
|
||||
"version": "3.17.0-next.3",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.3.tgz",
|
||||
"integrity": "sha512-VQcXnhKYxUW6OiRMhG++SzmZYMJwusXknJGd+FfdOnS1yHAo734OHyR0e2eEHDlv0/oWc8RZPgx/VKSKyondVg=="
|
||||
"version": "3.17.3",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
|
||||
"integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
|
||||
},
|
||||
"node_modules/vscode-tas-client": {
|
||||
"version": "0.1.63",
|
||||
|
|
138
package.json
138
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vscode-docker",
|
||||
"version": "1.26.0",
|
||||
"version": "1.27.0",
|
||||
"publisher": "ms-azuretools",
|
||||
"displayName": "Docker",
|
||||
"description": "Makes it easy to create, manage, and debug containerized applications.",
|
||||
|
@ -122,10 +122,6 @@
|
|||
"command": "vscode-docker.registries.azure.buildImage",
|
||||
"when": "isWorkspaceTrusted"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.runFileAsTask",
|
||||
"when": "isWorkspaceTrusted"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.help.openWalkthrough",
|
||||
"when": "never"
|
||||
|
@ -145,19 +141,18 @@
|
|||
{
|
||||
"command": "vscode-docker.containers.group.remove",
|
||||
"when": "never"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.activateRegistryProviders",
|
||||
"when": "never"
|
||||
}
|
||||
],
|
||||
"editor/context": [
|
||||
{
|
||||
"when": "isWorkspaceTrusted && editorLangId == dockerfile && isAzureAccountInstalled",
|
||||
"when": "isWorkspaceTrusted && editorLangId == dockerfile",
|
||||
"command": "vscode-docker.registries.azure.buildImage",
|
||||
"group": "docker"
|
||||
},
|
||||
{
|
||||
"when": "isWorkspaceTrusted && editorLangId == yaml && isAzureAccountInstalled",
|
||||
"command": "vscode-docker.registries.azure.runFileAsTask",
|
||||
"group": "docker"
|
||||
},
|
||||
{
|
||||
"when": "isWorkspaceTrusted && editorLangId == dockercompose",
|
||||
"command": "vscode-docker.compose.down",
|
||||
|
@ -186,15 +181,10 @@
|
|||
],
|
||||
"explorer/context": [
|
||||
{
|
||||
"when": "isWorkspaceTrusted && resourceFilename =~ /dockerfile/i && isAzureAccountInstalled",
|
||||
"when": "isWorkspaceTrusted && resourceFilename =~ /dockerfile/i",
|
||||
"command": "vscode-docker.registries.azure.buildImage",
|
||||
"group": "docker"
|
||||
},
|
||||
{
|
||||
"when": "isWorkspaceTrusted && resourceLangId == yaml && isAzureAccountInstalled",
|
||||
"command": "vscode-docker.registries.azure.runFileAsTask",
|
||||
"group": "docker"
|
||||
},
|
||||
{
|
||||
"when": "isWorkspaceTrusted && resourceLangId == dockercompose",
|
||||
"command": "vscode-docker.compose.down",
|
||||
|
@ -464,11 +454,6 @@
|
|||
"when": "view == dockerRegistries && viewItem == azure;DockerV2;RegistryProvider;",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.viewTaskLogs",
|
||||
"when": "view == dockerRegistries && viewItem == azureTaskRun",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.networks.inspect",
|
||||
"when": "view == dockerNetworks && viewItem =~ /network$/i",
|
||||
|
@ -481,102 +466,92 @@
|
|||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.createRegistry",
|
||||
"when": "view == dockerRegistries && viewItem == azureextensionui.azureSubscription",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azuresubscription/i",
|
||||
"group": "regs_1_general@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.deleteRegistry",
|
||||
"when": "view == dockerRegistries && viewItem == azure;DockerV2;Registry;",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azure;.*commonregistry/i",
|
||||
"group": "regs_reg_2_destructive@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.pullRepository",
|
||||
"when": "view == dockerRegistries && viewItem =~ /Repository;/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commonrepository/",
|
||||
"group": "regs_repo_1_general@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.deleteRepository",
|
||||
"when": "view == dockerRegistries && viewItem == azure;DockerV2;Repository;",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azure;.*commonrepository/i",
|
||||
"group": "regs_repo_2_destructive@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.pullImage",
|
||||
"when": "view == dockerRegistries && viewItem =~ /Tag;/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
|
||||
"group": "regs_tag_1_general@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.copyRemoteFullTag",
|
||||
"when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2);Tag;/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
|
||||
"group": "regs_tag_1_general@2"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.copyImageDigest",
|
||||
"when": "view == dockerRegistries && viewItem =~ /DockerV2;Tag;/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commontag/i && !(viewItem =~ /commontag;.*dockerhub/i)",
|
||||
"group": "regs_tag_1_general@3"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.deployImageToAzure",
|
||||
"when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2);Tag;/ && isAzureAccountInstalled",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
|
||||
"group": "regs_tag_1_general@4"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.deployImageToAca",
|
||||
"when": "view == dockerRegistries && viewItem =~ /(DockerV2|DockerHubV2|GitLabV4);Tag;/ && isAzureAccountInstalled",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commontag/i",
|
||||
"group": "regs_tag_1_general@6"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.untagImage",
|
||||
"when": "view == dockerRegistries && viewItem == azure;DockerV2;Tag;",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azure;.*commontag/i",
|
||||
"group": "regs_tag_2_destructive@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.deleteImage",
|
||||
"when": "view == dockerRegistries && viewItem =~ /DockerV2;Tag;/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commontag/i && !(viewItem =~ /commontag;.*(dockerhub|github)/i)",
|
||||
"group": "regs_tag_2_destructive@2"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.runTask",
|
||||
"when": "view == dockerRegistries && viewItem == azureTask",
|
||||
"group": "regs_task_1_general@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.copyImageDigest",
|
||||
"when": "view == dockerRegistries && viewItem == azureTaskRun",
|
||||
"group": "regs_taskRun_1_general@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.viewTaskLogs",
|
||||
"when": "view == dockerRegistries && viewItem == azureTaskRun",
|
||||
"group": "regs_taskRun_1_general@2"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.disconnectRegistry",
|
||||
"when": "view == dockerRegistries && viewItem =~ /RegistryProvider;/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commonregistryroot/i && !(viewItem =~ /commonregistryroot;.*generic/i)",
|
||||
"group": "regs_yyy_destructive@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.disconnectRegistry",
|
||||
"when": "view == dockerRegistries && viewItem == invalidRegistryProvider",
|
||||
"command": "vscode-docker.registries.genericV2.removeTrackedRegistry",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commonregistry;.*generic/i",
|
||||
"group": "regs_yyy_destructive@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.genericV2.addTrackedRegistry",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commonregistryroot;.*generic/i",
|
||||
"group": "regs_yyy_destructive@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.openInPortal",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azure(Subscription|;DockerV2;Registry;)/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azuresubscription|azure;.*(commonregistry|commonrepository)/i",
|
||||
"group": "regs_zzz_common@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.dockerHub.openInBrowser",
|
||||
"when": "view == dockerRegistries && viewItem =~ /dockerHub;DockerHubV2;(Tag|Repository|Registry);/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /(commonregistry|commonrepository|commontag);.*dockerhub/i",
|
||||
"group": "regs_zzz_common@1"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.viewProperties",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azure(TaskRun|;DockerV2;Registry;)/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azure;.*commonregistry/i",
|
||||
"group": "regs_zzz_common@2"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.reconnectRegistry",
|
||||
"when": "view == dockerRegistries && viewItem == registryConnectError",
|
||||
"when": "view == dockerRegistries && viewItem =~ /registryConnectError/i",
|
||||
"group": "regs_zzz_common@8"
|
||||
},
|
||||
{
|
||||
|
@ -586,12 +561,7 @@
|
|||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.refresh",
|
||||
"when": "view == dockerRegistries && viewItem =~ /.*;.*;(Repository|Registry|RegistryProvider);/",
|
||||
"group": "regs_zzz_common@9"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.refresh",
|
||||
"when": "view == dockerRegistries && viewItem =~ /azure(Subscription|Tasks|Task|RunsWithoutTask)$/",
|
||||
"when": "view == dockerRegistries && viewItem =~ /commonregistry|commonregistryroot|commonrepository/",
|
||||
"group": "regs_zzz_common@9"
|
||||
},
|
||||
{
|
||||
|
@ -1558,6 +1528,9 @@
|
|||
"id": "ignore",
|
||||
"filenames": [
|
||||
".dockerignore"
|
||||
],
|
||||
"filenamePatterns": [
|
||||
"*.dockerignore"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -2598,16 +2571,6 @@
|
|||
"title": "%vscode-docker.commands.registries.azure.openInPortal%",
|
||||
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.runFileAsTask",
|
||||
"title": "%vscode-docker.commands.registries.azure.runFileAsTask%",
|
||||
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.runTask",
|
||||
"title": "%vscode-docker.commands.registries.azure.runTask%",
|
||||
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.selectSubscriptions",
|
||||
"title": "%vscode-docker.commands.registries.azure.selectSubscriptions%",
|
||||
|
@ -2623,12 +2586,6 @@
|
|||
"title": "%vscode-docker.commands.registries.azure.viewProperties%",
|
||||
"category": "%vscode-docker.commands.category.azureContainerRegistry%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.azure.viewTaskLogs",
|
||||
"title": "%vscode-docker.commands.registries.azure.viewLogs%",
|
||||
"category": "%vscode-docker.commands.category.azureContainerRegistry%",
|
||||
"icon": "$(output)"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.connectRegistry",
|
||||
"title": "%vscode-docker.commands.registries.connect%",
|
||||
|
@ -2665,6 +2622,16 @@
|
|||
"title": "%vscode-docker.commands.registries.disconnectRegistry%",
|
||||
"category": "%vscode-docker.commands.category.dockerRegistries%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.genericV2.removeTrackedRegistry",
|
||||
"title": "%vscode-docker.commands.registries.genericV2.removeTrackedRegistry%",
|
||||
"category": "%vscode-docker.commands.category.dockerRegistries%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.genericV2.addTrackedRegistry",
|
||||
"title": "%vscode-docker.commands.registries.genericV2.addTrackedRegistry%",
|
||||
"category": "%vscode-docker.commands.category.dockerRegistries%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.registries.dockerHub.openInBrowser",
|
||||
"title": "%vscode-docker.commands.registries.dockerHub.openInBrowser%",
|
||||
|
@ -2784,6 +2751,11 @@
|
|||
"title": "%vscode-docker.commands.contexts.help%",
|
||||
"category": "%vscode-docker.commands.category.contexts%",
|
||||
"icon": "$(question)"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.activateRegistryProviders",
|
||||
"title": "%vscode-docker.commands.activateRegistryProviders%",
|
||||
"category": "%vscode-docker.commands.category.docker%"
|
||||
}
|
||||
],
|
||||
"views": {
|
||||
|
@ -3024,18 +2996,20 @@
|
|||
"@azure/arm-containerregistry": "^10.1.0",
|
||||
"@azure/storage-blob": "^12.14.0",
|
||||
"@microsoft/compose-language-service": "^0.2.0",
|
||||
"@microsoft/vscode-azext-azureappservice": "^1.0.2",
|
||||
"@microsoft/vscode-azext-azureutils": "^1.1.5",
|
||||
"@microsoft/vscode-azext-utils": "^1.2.2",
|
||||
"@microsoft/vscode-azext-azureappservice": "~2.0",
|
||||
"@microsoft/vscode-azext-azureauth": "^1.1.2",
|
||||
"@microsoft/vscode-azext-azureutils": "^2.0.0",
|
||||
"@microsoft/vscode-azext-utils": "^2.1.1",
|
||||
"@microsoft/vscode-container-client": "^0.1.0",
|
||||
"@microsoft/vscode-docker-registries": "^0.1.3",
|
||||
"dayjs": "^1.11.7",
|
||||
"dockerfile-language-server-nodejs": "^0.10.2",
|
||||
"dockerfile-language-server-nodejs": "^0.11.0",
|
||||
"fs-extra": "^11.1.1",
|
||||
"gradle-to-js": "^2.0.1",
|
||||
"handlebars": "^4.7.7",
|
||||
"node-fetch": "^2.6.9",
|
||||
"semver": "^7.5.2",
|
||||
"tar": "^6.1.13",
|
||||
"tree-kill": "^1.2.2",
|
||||
"vscode-languageclient": "^8.1.0",
|
||||
"vscode-tas-client": "^0.1.63",
|
||||
"xml2js": "^0.5.0"
|
||||
|
|
|
@ -262,12 +262,9 @@
|
|||
"vscode-docker.commands.registries.azure.deleteRegistry": "Delete Registry...",
|
||||
"vscode-docker.commands.registries.azure.deleteRepository": "Delete Repository...",
|
||||
"vscode-docker.commands.registries.azure.openInPortal": "Open in Portal",
|
||||
"vscode-docker.commands.registries.azure.runFileAsTask": "Run as Task in Azure...",
|
||||
"vscode-docker.commands.registries.azure.runTask": "Run Task",
|
||||
"vscode-docker.commands.registries.azure.selectSubscriptions": "Select Subscriptions...",
|
||||
"vscode-docker.commands.registries.azure.untagImage": "Untag Image...",
|
||||
"vscode-docker.commands.registries.azure.viewProperties": "View Properties",
|
||||
"vscode-docker.commands.registries.azure.viewLogs": "View Logs",
|
||||
"vscode-docker.commands.registries.connect": "Connect Registry...",
|
||||
"vscode-docker.commands.registries.reconnectRegistry": "Re-enter credentials",
|
||||
"vscode-docker.commands.registries.copyImageDigest": "Copy Image Digest",
|
||||
|
@ -276,6 +273,8 @@
|
|||
"vscode-docker.commands.registries.deployImageToAzure": "Deploy Image to Azure App Service...",
|
||||
"vscode-docker.commands.registries.deployImageToAca": "Deploy Image to Azure Container Apps...",
|
||||
"vscode-docker.commands.registries.disconnectRegistry": "Disconnect",
|
||||
"vscode-docker.commands.registries.genericV2.removeTrackedRegistry": "Disconnect from Generic Docker Registry",
|
||||
"vscode-docker.commands.registries.genericV2.addTrackedRegistry": "Connect to Generic Docker Registry...",
|
||||
"vscode-docker.commands.registries.dockerHub.openInBrowser": "Open in Browser",
|
||||
"vscode-docker.commands.registries.help": "Registries Help",
|
||||
"vscode-docker.commands.registries.logInToDockerCli": "Log In to Docker CLI",
|
||||
|
@ -294,6 +293,7 @@
|
|||
"vscode-docker.commands.contexts.configureExplorer": "Configure Explorer...",
|
||||
"vscode-docker.commands.contexts.refresh": "Refresh",
|
||||
"vscode-docker.commands.contexts.help": "Docker Context Help",
|
||||
"vscode-docker.commands.activateRegistryProviders": "Activate Registry Providers...",
|
||||
"vscode-docker.commands.category.docker": "Docker",
|
||||
"vscode-docker.commands.category.dockerContainers": "Docker Containers",
|
||||
"vscode-docker.commands.category.dockerImages": "Docker Images",
|
||||
|
|
|
@ -23,7 +23,11 @@ USER appuser
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{#if (eq netCorePlatformOS 'Windows')}}
|
||||
FROM {{ netCoreSdkBaseImage }} AS build
|
||||
{{else}}
|
||||
FROM --platform=$BUILDPLATFORM {{ netCoreSdkBaseImage }} AS build
|
||||
{{/if}}
|
||||
ARG configuration=Release
|
||||
WORKDIR /src
|
||||
COPY ["{{ workspaceRelative . artifact }}", "{{ dirname (workspaceRelative . artifact) }}/"]
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DockerExtensionApi as DockerExtensionRegistryApi, RegistryDataProvider, RegistryItem } from '@microsoft/vscode-docker-registries';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from './extensionVariables';
|
||||
|
||||
export class DockerExtensionApi implements MementoExplorerExport {
|
||||
export class DockerExtensionApi implements MementoExplorerExport, DockerExtensionRegistryApi {
|
||||
readonly #extensionMementos: ExtensionMementos | undefined;
|
||||
|
||||
public constructor(ctx: vscode.ExtensionContext) {
|
||||
|
@ -18,6 +20,12 @@ export class DockerExtensionApi implements MementoExplorerExport {
|
|||
}
|
||||
}
|
||||
|
||||
public registerRegistryDataProvider<T extends RegistryItem>(id: string, registryDataProvider: RegistryDataProvider<T>): vscode.Disposable {
|
||||
const disposable = ext.registriesTree.registerProvider(registryDataProvider);
|
||||
void ext.registriesTree.refresh();
|
||||
return disposable;
|
||||
}
|
||||
|
||||
public get memento(): ExtensionMementos | undefined {
|
||||
return this.#extensionMementos;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { ContainerOS, VoidCommandResponse } from '@microsoft/vscode-container-client';
|
||||
import { l10n } from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { ContainerOS, VoidCommandResponse } from '../../runtimes/docker';
|
||||
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
|
||||
import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem';
|
||||
import { getDockerOSType } from '../../utils/osUtils';
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { PortBinding } from '../../runtimes/docker';
|
||||
import { IActionContext, IAzureQuickPickItem, TelemetryProperties } from '@microsoft/vscode-azext-utils';
|
||||
import { PortBinding } from '@microsoft/vscode-container-client';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { ContainerTreeItem } from "../../tree/containers/ContainerTreeItem";
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { CommonOrchestratorCommandOptions, IContainerOrchestratorClient, LogsCommandOptions, VoidCommandResponse } from '@microsoft/vscode-container-client';
|
||||
import * as path from 'path';
|
||||
import { l10n } from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { CommonOrchestratorCommandOptions, IContainerOrchestratorClient, LogsCommandOptions, VoidCommandResponse } from '../../runtimes/docker';
|
||||
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
|
||||
import { ContainerGroupTreeItem } from '../../tree/containers/ContainerGroupTreeItem';
|
||||
import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem';
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, NoResourceFoundError } from '@microsoft/vscode-azext-utils';
|
||||
import { parseDockerLikeImageName } from '@microsoft/vscode-container-client';
|
||||
import { CommonRegistry } from '@microsoft/vscode-docker-registries';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
|
||||
import { ImageTreeItem } from '../../tree/images/ImageTreeItem';
|
||||
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
|
||||
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
|
||||
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { registryExperience } from '../../utils/registryExperience';
|
||||
import { addImageTaggingTelemetry, tagImage } from './tagImage';
|
||||
|
||||
export async function pushImage(context: IActionContext, node: ImageTreeItem | undefined): Promise<void> {
|
||||
|
@ -21,7 +23,7 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
|
|||
});
|
||||
}
|
||||
|
||||
let connectedRegistry: RegistryTreeItemBase | undefined;
|
||||
let connectedRegistry: UnifiedRegistryItem<CommonRegistry> | undefined;
|
||||
|
||||
if (!node.fullTag.includes('/')) {
|
||||
// The registry to push to is indeterminate--could be Docker Hub, or could need tagging.
|
||||
|
@ -30,7 +32,7 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
|
|||
// If the prompt setting is true, we'll ask; if not we'll assume Docker Hub.
|
||||
if (prompt) {
|
||||
try {
|
||||
connectedRegistry = await ext.registriesTree.showTreeItemPicker<RegistryTreeItemBase>(registryExpectedContextValues.all.registry, context);
|
||||
connectedRegistry = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: [/commonregistry/i] } });
|
||||
} catch (error) {
|
||||
if (error instanceof NoResourceFoundError) {
|
||||
// Do nothing, move on without a selected registry
|
||||
|
@ -41,25 +43,30 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
|
|||
}
|
||||
} else {
|
||||
// Try to find a connected Docker Hub registry (primarily for login credentials)
|
||||
connectedRegistry = await tryGetDockerHubRegistry(context);
|
||||
connectedRegistry = await registryExperience<CommonRegistry>(
|
||||
context,
|
||||
{
|
||||
registryFilter: { include: [ext.dockerHubRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: /commonregistry/i },
|
||||
skipIfOne: true
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// The registry to push to is determinate. If there's a connected registry in the tree view, we'll try to find it, to perform login ahead of time.
|
||||
// Registry path is everything up to the last slash.
|
||||
const baseImagePath = node.fullTag.substring(0, node.fullTag.lastIndexOf('/'));
|
||||
|
||||
const progressOptions: vscode.ProgressOptions = {
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: vscode.l10n.t('Fetching login credentials...'),
|
||||
};
|
||||
|
||||
connectedRegistry = await vscode.window.withProgress(progressOptions, async () => await tryGetConnectedRegistryForPath(context, baseImagePath));
|
||||
connectedRegistry = await vscode.window.withProgress(progressOptions, async () => await tryGetConnectedRegistryForPath(context, node.parent.label));
|
||||
}
|
||||
|
||||
// Give the user a chance to modify the tag however they want
|
||||
const finalTag = await tagImage(context, node, connectedRegistry);
|
||||
|
||||
if (connectedRegistry && finalTag.startsWith(connectedRegistry.baseImagePath)) {
|
||||
const baseImagePath = connectedRegistry.wrappedItem.baseUrl.authority;
|
||||
if (connectedRegistry && finalTag.startsWith(baseImagePath)) {
|
||||
// If a registry was found/chosen and is still the same as the final tag's registry, try logging in
|
||||
await vscode.commands.executeCommand('vscode-docker.registries.logInToDockerCli', connectedRegistry);
|
||||
}
|
||||
|
@ -78,12 +85,15 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u
|
|||
);
|
||||
}
|
||||
|
||||
async function tryGetConnectedRegistryForPath(context: IActionContext, baseImagePath: string): Promise<RegistryTreeItemBase | undefined> {
|
||||
const allRegistries = await ext.registriesRoot.getAllConnectedRegistries(context);
|
||||
return allRegistries.find(r => r.baseImagePath === baseImagePath);
|
||||
}
|
||||
async function tryGetConnectedRegistryForPath(context: IActionContext, baseImagePath: string): Promise<UnifiedRegistryItem<CommonRegistry> | undefined> {
|
||||
const baseImageNameInfo = parseDockerLikeImageName(baseImagePath);
|
||||
const allRegistries = await ext.registriesTree.getConnectedRegistries(baseImageNameInfo.registry);
|
||||
|
||||
async function tryGetDockerHubRegistry(context: IActionContext): Promise<RegistryTreeItemBase | undefined> {
|
||||
const allRegistries = await ext.registriesRoot.getAllConnectedRegistries(context);
|
||||
return allRegistries.find(r => r.contextValue.match(registryExpectedContextValues.dockerHub.registry));
|
||||
let matchedRegistry = allRegistries.find((registry) => registry.wrappedItem.baseUrl.authority === baseImageNameInfo.registry);
|
||||
|
||||
if (!matchedRegistry) {
|
||||
matchedRegistry = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: [/commonregistry/i] } });
|
||||
}
|
||||
|
||||
return matchedRegistry;
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { RunContainerBindMount } from '@microsoft/vscode-container-client';
|
||||
import * as fse from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { l10n } from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { RunContainerBindMount } from '../../runtimes/docker';
|
||||
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
|
||||
import { getDockerOSType } from '../../utils/osUtils';
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, TelemetryProperties } from '@microsoft/vscode-azext-utils';
|
||||
import { CommonRegistry, isRegistry } from '@microsoft/vscode-docker-registries';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { ImageTreeItem } from '../../tree/images/ImageTreeItem';
|
||||
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
|
||||
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getBaseImagePathFromRegistry } from '../../tree/registries/registryTreeUtils';
|
||||
|
||||
export async function tagImage(context: IActionContext, node?: ImageTreeItem, registry?: RegistryTreeItemBase): Promise<string> {
|
||||
export async function tagImage(context: IActionContext, node?: ImageTreeItem, registry?: UnifiedRegistryItem<CommonRegistry>): Promise<string> {
|
||||
if (!node) {
|
||||
await ext.imagesTree.refresh(context);
|
||||
node = await ext.imagesTree.showTreeItemPicker<ImageTreeItem>(ImageTreeItem.contextValue, {
|
||||
|
@ -19,7 +21,8 @@ export async function tagImage(context: IActionContext, node?: ImageTreeItem, re
|
|||
}
|
||||
|
||||
addImageTaggingTelemetry(context, node.fullTag, '.before');
|
||||
const newTaggedName: string = await getTagFromUserInput(context, node.fullTag, registry?.baseImagePath);
|
||||
const baseImagePath = isRegistry(registry?.wrappedItem) ? getBaseImagePathFromRegistry(registry.wrappedItem) : undefined;
|
||||
const newTaggedName: string = await getTagFromUserInput(context, node.fullTag, baseImagePath);
|
||||
addImageTaggingTelemetry(context, newTaggedName, '.after');
|
||||
|
||||
await ext.runWithDefaults(client =>
|
||||
|
|
|
@ -58,17 +58,16 @@ import { deployImageToAca } from "./registries/azure/deployImageToAca";
|
|||
import { deployImageToAzure } from "./registries/azure/deployImageToAzure";
|
||||
import { openInAzurePortal } from "./registries/azure/openInAzurePortal";
|
||||
import { buildImageInAzure } from "./registries/azure/tasks/buildImageInAzure";
|
||||
import { runAzureTask } from "./registries/azure/tasks/runAzureTask";
|
||||
import { runFileAsAzureTask } from "./registries/azure/tasks/runFileAsAzureTask";
|
||||
import { viewAzureTaskLogs } from "./registries/azure/tasks/viewAzureTaskLogs";
|
||||
import { untagAzureImage } from "./registries/azure/untagAzureImage";
|
||||
import { viewAzureProperties } from "./registries/azure/viewAzureProperties";
|
||||
import { connectRegistry } from "./registries/connectRegistry";
|
||||
import { copyRemoteFullTag } from './registries/copyRemoteFullTag';
|
||||
import { copyRemoteFullTag } from "./registries/copyRemoteFullTag";
|
||||
import { copyRemoteImageDigest } from "./registries/copyRemoteImageDigest";
|
||||
import { deleteRemoteImage } from "./registries/deleteRemoteImage";
|
||||
import { disconnectRegistry } from "./registries/disconnectRegistry";
|
||||
import { openDockerHubInBrowser } from "./registries/dockerHub/openDockerHubInBrowser";
|
||||
import { addTrackedGenericV2Registry } from "./registries/genericV2/addTrackedGenericV2Registry";
|
||||
import { removeTrackedGenericV2Registry } from "./registries/genericV2/removeTrackedGenericV2Registry";
|
||||
import { logInToDockerCli } from "./registries/logInToDockerCli";
|
||||
import { logOutOfDockerCli } from "./registries/logOutOfDockerCli";
|
||||
import { pullImageFromRepository, pullRepository } from "./registries/pullImages";
|
||||
|
@ -180,6 +179,9 @@ export function registerCommands(): void {
|
|||
registerWorkspaceCommand('vscode-docker.registries.pullRepository', pullRepository);
|
||||
registerCommand('vscode-docker.registries.reconnectRegistry', reconnectRegistry);
|
||||
|
||||
registerCommand('vscode-docker.registries.genericV2.removeTrackedRegistry', removeTrackedGenericV2Registry);
|
||||
registerCommand('vscode-docker.registries.genericV2.addTrackedRegistry', addTrackedGenericV2Registry);
|
||||
|
||||
registerCommand('vscode-docker.registries.dockerHub.openInBrowser', openDockerHubInBrowser);
|
||||
|
||||
registerWorkspaceCommand('vscode-docker.registries.azure.buildImage', buildImageInAzure);
|
||||
|
@ -187,12 +189,9 @@ export function registerCommands(): void {
|
|||
registerCommand('vscode-docker.registries.azure.deleteRegistry', deleteAzureRegistry);
|
||||
registerCommand('vscode-docker.registries.azure.deleteRepository', deleteAzureRepository);
|
||||
registerCommand('vscode-docker.registries.azure.openInPortal', openInAzurePortal);
|
||||
registerCommand('vscode-docker.registries.azure.runTask', runAzureTask);
|
||||
registerWorkspaceCommand('vscode-docker.registries.azure.runFileAsTask', runFileAsAzureTask);
|
||||
registerCommand('vscode-docker.registries.azure.selectSubscriptions', () => commands.executeCommand("azure-account.selectSubscriptions"));
|
||||
registerCommand('vscode-docker.registries.azure.untagImage', untagAzureImage);
|
||||
registerCommand('vscode-docker.registries.azure.viewProperties', viewAzureProperties);
|
||||
registerCommand('vscode-docker.registries.azure.viewTaskLogs', viewAzureTaskLogs);
|
||||
|
||||
registerCommand('vscode-docker.volumes.configureExplorer', configureVolumesExplorer);
|
||||
registerCommand('vscode-docker.volumes.inspect', inspectVolume);
|
||||
|
@ -208,4 +207,10 @@ export function registerCommands(): void {
|
|||
registerCommand('vscode-docker.openDockerDownloadPage', openDockerDownloadPage);
|
||||
registerCommand('vscode-docker.help', help);
|
||||
registerCommand('vscode-docker.help.openWalkthrough', () => commands.executeCommand('workbench.action.openWalkthrough', 'ms-azuretools.vscode-docker#dockerStart'));
|
||||
|
||||
registerCommand('vscode-docker.activateRegistryProviders', (context: IActionContext) => {
|
||||
// Do nothing, but registry provider extensions can use this command as an activation event
|
||||
context.telemetry.suppressAll = true;
|
||||
context.errorHandling.suppressDisplay = true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,17 +5,19 @@
|
|||
|
||||
import type { IAppServiceWizardContext } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
|
||||
import { AzureWizardExecuteStep } from "@microsoft/vscode-azext-utils";
|
||||
import { CommonTag } from "@microsoft/vscode-docker-registries";
|
||||
import { randomUUID } from "crypto";
|
||||
import { l10n, Progress } from "vscode";
|
||||
import { Progress, l10n } from "vscode";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
|
||||
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
|
||||
import { AzureRegistry, isAzureTag } from "../../../tree/registries/Azure/AzureRegistryDataProvider";
|
||||
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { getFullImageNameFromRegistryTagItem, getResourceGroupFromAzureRegistryItem } from "../../../tree/registries/registryTreeUtils";
|
||||
import { getArmAuth, getArmContainerRegistry, getAzExtAppService, getAzExtAzureUtils } from "../../../utils/lazyPackages";
|
||||
|
||||
export class DockerAssignAcrPullRoleStep extends AzureWizardExecuteStep<IAppServiceWizardContext> {
|
||||
public priority: number = 141; // execute after DockerSiteCreateStep
|
||||
|
||||
public constructor(private readonly tagTreeItem: RemoteTagTreeItem) {
|
||||
public constructor(private readonly tagTreeItem: UnifiedRegistryItem<CommonTag>) {
|
||||
super();
|
||||
}
|
||||
|
||||
|
@ -33,14 +35,14 @@ export class DockerAssignAcrPullRoleStep extends AzureWizardExecuteStep<IAppServ
|
|||
const appSvcClient = await vscAzureAppService.createWebSiteClient(context);
|
||||
|
||||
// If we're in `execute`, then `shouldExecute` passed and `this.tagTreeItem.parent.parent` is guaranteed to be an AzureRegistryTreeItem
|
||||
const registryTreeItem: AzureRegistryTreeItem = this.tagTreeItem.parent.parent as unknown as AzureRegistryTreeItem;
|
||||
const registryTreeItem: UnifiedRegistryItem<AzureRegistry> = this.tagTreeItem.parent.parent as unknown as UnifiedRegistryItem<AzureRegistry>;
|
||||
|
||||
// 1. Get the registry resource. We will need the ID.
|
||||
const registry = await crmClient.registries.get(registryTreeItem.resourceGroup, registryTreeItem.registryName);
|
||||
const registry = await crmClient.registries.get(getResourceGroupFromAzureRegistryItem(registryTreeItem.wrappedItem), registryTreeItem.wrappedItem.label);
|
||||
|
||||
if (!(registry?.id)) {
|
||||
throw new Error(
|
||||
l10n.t('Unable to get details from Container Registry {0}', registryTreeItem.baseUrl)
|
||||
l10n.t('Unable to get details from Container Registry {0}', registryTreeItem.wrappedItem.label)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -78,12 +80,12 @@ export class DockerAssignAcrPullRoleStep extends AzureWizardExecuteStep<IAppServ
|
|||
);
|
||||
}
|
||||
|
||||
config.linuxFxVersion = `DOCKER|${this.tagTreeItem.fullTag}`;
|
||||
const fullTag = getFullImageNameFromRegistryTagItem(this.tagTreeItem.wrappedItem);
|
||||
config.linuxFxVersion = `DOCKER|${fullTag}`;
|
||||
await appSvcClient.webApps.updateConfiguration(context.site.resourceGroup, context.site.name, config);
|
||||
}
|
||||
|
||||
public shouldExecute(context: IAppServiceWizardContext): boolean {
|
||||
return !!(context.site) && !!(this.tagTreeItem?.parent?.parent) && this.tagTreeItem.parent.parent instanceof AzureRegistryTreeItem
|
||||
&& !context.customLocation;
|
||||
return !!(context.site) && isAzureTag(this.tagTreeItem.wrappedItem) && !context.customLocation;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,22 +7,19 @@ import type { NameValuePair, Site, SiteConfig, WebSiteManagementClient } from '@
|
|||
import type { CustomLocation } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
|
||||
import type { AzExtLocation } from '@microsoft/vscode-azext-azureutils'; // These are only dev-time imports so don't need to be lazy
|
||||
import { AzureWizardExecuteStep, nonNullProp, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
|
||||
import { l10n, Progress } from "vscode";
|
||||
import { CommonRegistry, CommonTag } from '@microsoft/vscode-docker-registries';
|
||||
import { Progress, l10n } from "vscode";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
|
||||
import { DockerHubNamespaceTreeItem } from '../../../tree/registries/dockerHub/DockerHubNamespaceTreeItem';
|
||||
import { DockerV2RegistryTreeItemBase } from '../../../tree/registries/dockerV2/DockerV2RegistryTreeItemBase';
|
||||
import { GenericDockerV2RegistryTreeItem } from '../../../tree/registries/dockerV2/GenericDockerV2RegistryTreeItem';
|
||||
import { getRegistryPassword } from '../../../tree/registries/registryPasswords';
|
||||
import { RegistryTreeItemBase } from '../../../tree/registries/RegistryTreeItemBase';
|
||||
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
|
||||
import { AzureRegistryDataProvider, isAzureRegistry } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getFullImageNameFromRegistryTagItem } from '../../../tree/registries/registryTreeUtils';
|
||||
import { getAzExtAppService, getAzExtAzureUtils } from '../../../utils/lazyPackages';
|
||||
import { IAppServiceContainerWizardContext } from './deployImageToAzure';
|
||||
|
||||
export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceContainerWizardContext> {
|
||||
public priority: number = 140;
|
||||
|
||||
public constructor(private readonly node: RemoteTagTreeItem) {
|
||||
public constructor(private readonly tagItem: UnifiedRegistryItem<CommonTag>) {
|
||||
super();
|
||||
}
|
||||
|
||||
|
@ -49,7 +46,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
|
|||
if (context.customLocation) {
|
||||
// deploying to Azure Arc
|
||||
siteEnvelope.kind = 'app,linux,kubernetes,container';
|
||||
await this.addCustomLocationProperties(siteEnvelope, context.customLocation);
|
||||
this.addCustomLocationProperties(siteEnvelope, context.customLocation);
|
||||
} else {
|
||||
siteEnvelope.identity = {
|
||||
type: 'SystemAssigned'
|
||||
|
@ -60,7 +57,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
|
|||
}
|
||||
|
||||
private async getNewSiteConfig(context: IAppServiceContainerWizardContext): Promise<SiteConfig> {
|
||||
const registryTI: RegistryTreeItemBase = this.node.parent.parent;
|
||||
const registryTI: UnifiedRegistryItem<CommonRegistry> = this.tagItem.parent.parent as unknown as UnifiedRegistryItem<CommonRegistry>;
|
||||
|
||||
let username: string | undefined;
|
||||
let password: string | undefined;
|
||||
|
@ -69,7 +66,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
|
|||
|
||||
// Scenarios:
|
||||
// ACR -> App Service, NOT Arc App Service. Use managed service identity.
|
||||
if (registryTI instanceof AzureRegistryTreeItem && !context.customLocation) {
|
||||
if (isAzureRegistry(registryTI.wrappedItem) && !context.customLocation) {
|
||||
appSettings.push({ name: 'DOCKER_ENABLE_CI', value: 'true' });
|
||||
|
||||
// Don't need an image, username, or password--just create an empty web app to assign permissions and then configure with an image
|
||||
|
@ -80,36 +77,29 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
|
|||
};
|
||||
}
|
||||
// ACR -> Arc App Service. Use regular auth. Same as any V2 registry but different way of getting auth.
|
||||
else if (registryTI instanceof AzureRegistryTreeItem && context.customLocation) {
|
||||
const cred = await registryTI.tryGetAdminCredentials(context);
|
||||
else if (isAzureRegistry(registryTI.wrappedItem) && context.customLocation) {
|
||||
const cred = await (registryTI.provider as unknown as AzureRegistryDataProvider).tryGetAdminCredentials(registryTI.wrappedItem);
|
||||
if (!cred?.username || !cred?.passwords?.[0]?.value) {
|
||||
throw new Error(l10n.t('Azure App service deployment on Azure Arc only supports running images from Azure Container Registries with admin enabled'));
|
||||
}
|
||||
|
||||
username = cred.username;
|
||||
password = cred.passwords[0].value;
|
||||
registryUrl = registryTI.baseUrl;
|
||||
registryUrl = registryTI.wrappedItem.baseUrl.toString();
|
||||
}
|
||||
// Docker Hub -> App Service *OR* Arc App Service
|
||||
else if (registryTI instanceof DockerHubNamespaceTreeItem) {
|
||||
username = registryTI.parent.username;
|
||||
password = await registryTI.parent.getPassword();
|
||||
registryUrl = 'https://index.docker.io';
|
||||
}
|
||||
// Generic registry -> App Service *OR* Arc App Service
|
||||
else if (registryTI instanceof DockerV2RegistryTreeItemBase) {
|
||||
if (registryTI instanceof GenericDockerV2RegistryTreeItem) {
|
||||
username = registryTI.cachedProvider.username;
|
||||
password = await getRegistryPassword(registryTI.cachedProvider);
|
||||
} else {
|
||||
throw new RangeError(l10n.t('Unrecognized node type "{0}"', registryTI.constructor.name));
|
||||
// Other registries -> App Service *OR* Arc App Service
|
||||
else {
|
||||
if (!registryTI.provider.getLoginInformation) {
|
||||
throw new Error(l10n.t('This registry does not support deploying to Azure App Service'));
|
||||
}
|
||||
const loginInformation = await registryTI.provider.getLoginInformation(registryTI.wrappedItem);
|
||||
|
||||
registryUrl = registryTI.baseUrl;
|
||||
} else {
|
||||
throw new RangeError(l10n.t('Unrecognized node type "{0}"', registryTI.constructor.name));
|
||||
registryUrl = (registryTI.wrappedItem as CommonRegistry).baseUrl.toString();
|
||||
username = loginInformation.username;
|
||||
password = loginInformation.secret;
|
||||
}
|
||||
|
||||
|
||||
if (username && password) {
|
||||
appSettings.push({ name: "DOCKER_REGISTRY_SERVER_USERNAME", value: username });
|
||||
appSettings.push({ name: "DOCKER_REGISTRY_SERVER_PASSWORD", value: password });
|
||||
|
@ -123,7 +113,7 @@ export class DockerSiteCreateStep extends AzureWizardExecuteStep<IAppServiceCont
|
|||
appSettings.push({ name: "WEBSITES_PORT", value: context.webSitesPort.toString() });
|
||||
}
|
||||
|
||||
const linuxFxVersion = `DOCKER|${this.node.fullTag}`;
|
||||
const linuxFxVersion = `DOCKER|${getFullImageNameFromRegistryTagItem(this.tagItem.wrappedItem)}`;
|
||||
|
||||
return {
|
||||
linuxFxVersion,
|
||||
|
|
|
@ -7,21 +7,20 @@ import type { Site } from '@azure/arm-appservice'; // These are only dev-time im
|
|||
import type { Webhook, WebhookCreateParameters } from '@azure/arm-containerregistry'; // These are only dev-time imports so don't need to be lazy
|
||||
import type { IAppServiceWizardContext } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
|
||||
import { AzureWizardExecuteStep, nonNullProp } from "@microsoft/vscode-azext-utils";
|
||||
import { CommonRepository, CommonTag, isDockerHubRepository } from '@microsoft/vscode-docker-registries';
|
||||
import * as vscode from "vscode";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
|
||||
import { AzureRepositoryTreeItem } from '../../../tree/registries/azure/AzureRepositoryTreeItem';
|
||||
import { DockerHubRepositoryTreeItem } from '../../../tree/registries/dockerHub/DockerHubRepositoryTreeItem';
|
||||
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
|
||||
import { AzureRegistry, isAzureRepository } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getResourceGroupFromAzureRegistryItem } from '../../../tree/registries/registryTreeUtils';
|
||||
import { cryptoUtils } from '../../../utils/cryptoUtils';
|
||||
import { getArmContainerRegistry, getAzExtAppService, getAzExtAzureUtils } from "../../../utils/lazyPackages";
|
||||
|
||||
export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceWizardContext> {
|
||||
public priority: number = 142; // execute after DockerAssignAcrPullRoleStep
|
||||
private _treeItem: RemoteTagTreeItem;
|
||||
public constructor(treeItem: RemoteTagTreeItem) {
|
||||
|
||||
public constructor(private readonly tagItem: UnifiedRegistryItem<CommonTag>) {
|
||||
super();
|
||||
this._treeItem = treeItem;
|
||||
}
|
||||
|
||||
public async execute(context: IAppServiceWizardContext, progress: vscode.Progress<{
|
||||
|
@ -34,17 +33,20 @@ export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceW
|
|||
const parsedSite = new vscAzureAppService.ParsedSite(site, context);
|
||||
const siteClient = await parsedSite.createClient(context);
|
||||
const appUri: string = (await siteClient.getWebAppPublishCredential()).scmUri;
|
||||
if (this._treeItem.parent instanceof AzureRepositoryTreeItem) {
|
||||
|
||||
if (isAzureRepository(this.tagItem.parent.wrappedItem)) {
|
||||
const creatingNewWebhook: string = vscode.l10n.t('Creating webhook for web app "{0}"...', context.newSiteName);
|
||||
ext.outputChannel.info(creatingNewWebhook);
|
||||
progress.report({ message: creatingNewWebhook });
|
||||
const webhook = await this.createWebhookForApp(context, this._treeItem, context.site, appUri);
|
||||
const webhook = await this.createWebhookForApp(context, context.site, appUri);
|
||||
ext.outputChannel.info(vscode.l10n.t('Created webhook "{0}" with scope "{1}", id: "{2}" and location: "{3}"', webhook.name, webhook.scope, webhook.id, webhook.location));
|
||||
} else if (this._treeItem.parent instanceof DockerHubRepositoryTreeItem) {
|
||||
} else if (isDockerHubRepository(this.tagItem.parent.wrappedItem)) {
|
||||
const registryName = this.tagItem.parent.parent.wrappedItem.label;
|
||||
const repoName = (this.tagItem.parent as unknown as CommonRepository).wrappedItem.label;
|
||||
// point to dockerhub to create a webhook
|
||||
// http://cloud.docker.com/repository/docker/<registryName>/<repoName>/webHooks
|
||||
const dockerhubPrompt: string = vscode.l10n.t('Copy & Open');
|
||||
const dockerhubUri: string = `https://cloud.docker.com/repository/docker/${this._treeItem.parent.parent.namespace}/${this._treeItem.parent.repoName}/webHooks`;
|
||||
const dockerhubUri: string = `https://cloud.docker.com/repository/docker/${registryName}/${repoName}/webHooks`;
|
||||
|
||||
// NOTE: The response to the information message is not awaited but handled independently of the wizard steps.
|
||||
// VS Code will hide such messages in the notifications pane after a period of time; awaiting them risks
|
||||
|
@ -64,10 +66,10 @@ export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceW
|
|||
}
|
||||
|
||||
public shouldExecute(context: IAppServiceWizardContext): boolean {
|
||||
return !!context.site && (this._treeItem.parent instanceof AzureRepositoryTreeItem || this._treeItem.parent instanceof DockerHubRepositoryTreeItem);
|
||||
return !!context.site && (isAzureRepository(this.tagItem.parent.wrappedItem) || isDockerHubRepository(this.tagItem.parent.wrappedItem));
|
||||
}
|
||||
|
||||
private async createWebhookForApp(context: IAppServiceWizardContext, node: RemoteTagTreeItem, site: Site, appUri: string): Promise<Webhook | undefined> {
|
||||
private async createWebhookForApp(context: IAppServiceWizardContext, site: Site, appUri: string): Promise<Webhook | undefined> {
|
||||
const maxLength: number = 50;
|
||||
const numRandomChars: number = 6;
|
||||
|
||||
|
@ -80,17 +82,18 @@ export class DockerWebhookCreateStep extends AzureWizardExecuteStep<IAppServiceW
|
|||
webhookName += cryptoUtils.getRandomHexString(numRandomChars);
|
||||
|
||||
// variables derived from the container registry
|
||||
const registryTreeItem: AzureRegistryTreeItem = (<AzureRepositoryTreeItem>node.parent).parent;
|
||||
const registryTreeItem: UnifiedRegistryItem<AzureRegistry> = this.tagItem.parent.parent as unknown as UnifiedRegistryItem<AzureRegistry>;
|
||||
const armContainerRegistry = await getArmContainerRegistry();
|
||||
const azExtAzureUtils = await getAzExtAzureUtils();
|
||||
const crmClient = azExtAzureUtils.createAzureClient(context, armContainerRegistry.ContainerRegistryManagementClient);
|
||||
const webhookCreateParameters: WebhookCreateParameters = {
|
||||
location: registryTreeItem.registryLocation,
|
||||
location: registryTreeItem.wrappedItem.registryProperties.location,
|
||||
serviceUri: appUri,
|
||||
scope: `${node.parent.repoName}:${node.tag}`,
|
||||
scope: `${this.tagItem.parent.wrappedItem.label}:${this.tagItem.wrappedItem.label}`,
|
||||
actions: ["push"],
|
||||
status: 'enabled'
|
||||
};
|
||||
return await crmClient.webhooks.beginCreateAndWait(registryTreeItem.resourceGroup, registryTreeItem.registryName, webhookName, webhookCreateParameters);
|
||||
const resourceGroup = getResourceGroupFromAzureRegistryItem(registryTreeItem.wrappedItem);
|
||||
return await crmClient.webhooks.beginCreateAndWait(resourceGroup, registryTreeItem.wrappedItem.label, webhookName, webhookCreateParameters);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,17 +3,61 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { AzureWizard, IActionContext, createSubscriptionContext, nonNullProp } from '@microsoft/vscode-azext-utils';
|
||||
import { l10n, window } from 'vscode';
|
||||
import { ext } from '../../../extensionVariables';
|
||||
import type { SubscriptionTreeItem } from '../../../tree/registries/azure/SubscriptionTreeItem'; // These are only dev-time imports so don't need to be lazy
|
||||
import { getAzSubTreeItem } from '../../../utils/lazyPackages';
|
||||
import { AzureSubscriptionRegistryItem } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { AzureRegistryCreateStep } from '../../../tree/registries/Azure/createWizard/AzureRegistryCreateStep';
|
||||
import { AzureRegistryNameStep } from '../../../tree/registries/Azure/createWizard/AzureRegistryNameStep';
|
||||
import { AzureRegistrySkuStep } from '../../../tree/registries/Azure/createWizard/AzureRegistrySkuStep';
|
||||
import { IAzureRegistryWizardContext } from '../../../tree/registries/Azure/createWizard/IAzureRegistryWizardContext';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getAzExtAzureUtils } from '../../../utils/lazyPackages';
|
||||
import { registryExperience } from '../../../utils/registryExperience';
|
||||
|
||||
export async function createAzureRegistry(context: IActionContext, node?: SubscriptionTreeItem): Promise<void> {
|
||||
const azSubTreeItem = await getAzSubTreeItem();
|
||||
export async function createAzureRegistry(context: IActionContext, node?: UnifiedRegistryItem<AzureSubscriptionRegistryItem>): Promise<void> {
|
||||
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<SubscriptionTreeItem>(azSubTreeItem.SubscriptionTreeItem.contextValue, context);
|
||||
node = await registryExperience<AzureSubscriptionRegistryItem>(context,
|
||||
{
|
||||
contextValueFilter: { include: /azuresubscription/i },
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
await node.createChild(context);
|
||||
const registryItem = node.wrappedItem;
|
||||
|
||||
const subscriptionContext = createSubscriptionContext(registryItem.subscription);
|
||||
const wizardContext: IAzureRegistryWizardContext = {
|
||||
...context,
|
||||
...subscriptionContext,
|
||||
azureSubscription: registryItem.subscription,
|
||||
};
|
||||
const azExtAzureUtils = await getAzExtAzureUtils();
|
||||
|
||||
const promptSteps = [
|
||||
new AzureRegistryNameStep(),
|
||||
new AzureRegistrySkuStep(),
|
||||
new azExtAzureUtils.ResourceGroupListStep(),
|
||||
];
|
||||
azExtAzureUtils.LocationListStep.addStep(wizardContext, promptSteps);
|
||||
|
||||
const wizard = new AzureWizard(
|
||||
wizardContext,
|
||||
{
|
||||
promptSteps,
|
||||
executeSteps: [
|
||||
new AzureRegistryCreateStep()
|
||||
],
|
||||
title: l10n.t('Create new Azure Container Registry')
|
||||
}
|
||||
);
|
||||
|
||||
await wizard.prompt();
|
||||
const newRegistryName: string = nonNullProp(wizardContext, 'newRegistryName');
|
||||
await wizard.execute();
|
||||
|
||||
void window.showInformationMessage(`Successfully created registry "${newRegistryName}".`);
|
||||
void ext.registriesTree.refresh();
|
||||
}
|
||||
|
|
|
@ -4,26 +4,35 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { l10n, ProgressLocation, window } from 'vscode';
|
||||
import { ProgressLocation, l10n, window } from 'vscode';
|
||||
import { ext } from '../../../extensionVariables';
|
||||
import type { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
|
||||
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
|
||||
import { AzureRegistry, AzureRegistryDataProvider } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { registryExperience } from '../../../utils/registryExperience';
|
||||
|
||||
export async function deleteAzureRegistry(context: IActionContext, node?: AzureRegistryTreeItem): Promise<void> {
|
||||
export async function deleteAzureRegistry(context: IActionContext, node?: UnifiedRegistryItem<AzureRegistry>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, { ...context, suppressCreatePick: true });
|
||||
node = await registryExperience<AzureRegistry>(context, {
|
||||
contextValueFilter: { include: /commonregistry/i },
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] }
|
||||
});
|
||||
}
|
||||
|
||||
const confirmDelete: string = l10n.t('Are you sure you want to delete registry "{0}" and its associated images?', node.registryName);
|
||||
const registryName = node.wrappedItem.label;
|
||||
|
||||
const confirmDelete: string = l10n.t('Are you sure you want to delete registry "{0}" and its associated images?', registryName);
|
||||
// no need to check result - cancel will throw a UserCancelledError
|
||||
await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);
|
||||
|
||||
const deleting = l10n.t('Deleting registry "{0}"...', node.registryName);
|
||||
const deleting = l10n.t('Deleting registry "{0}"...', registryName);
|
||||
await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
|
||||
await node.deleteTreeItem(context);
|
||||
const azureRegistryDataProvider = node.provider as unknown as AzureRegistryDataProvider;
|
||||
await azureRegistryDataProvider.deleteRegistry(node.wrappedItem);
|
||||
});
|
||||
|
||||
const message = l10n.t('Successfully deleted registry "{0}".', node.registryName);
|
||||
void ext.registriesTree.refresh();
|
||||
|
||||
const message = l10n.t('Successfully deleted registry "{0}".', registryName);
|
||||
// don't wait
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
window.showInformationMessage(message);
|
||||
|
|
|
@ -4,27 +4,32 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { l10n, ProgressLocation, window } from 'vscode';
|
||||
import { ProgressLocation, l10n, window } from 'vscode';
|
||||
import { ext } from '../../../extensionVariables';
|
||||
import type { AzureRepositoryTreeItem } from '../../../tree/registries/azure/AzureRepositoryTreeItem';
|
||||
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
|
||||
import { AzureRegistryDataProvider, AzureRepository } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { registryExperience } from '../../../utils/registryExperience';
|
||||
|
||||
export async function deleteAzureRepository(context: IActionContext, node?: AzureRepositoryTreeItem): Promise<void> {
|
||||
export async function deleteAzureRepository(context: IActionContext, node?: UnifiedRegistryItem<AzureRepository>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<AzureRepositoryTreeItem>(registryExpectedContextValues.azure.repository, { ...context, suppressCreatePick: true });
|
||||
node = await registryExperience<AzureRepository>(context, {
|
||||
contextValueFilter: { include: /commonrepository/i },
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] }
|
||||
});
|
||||
}
|
||||
|
||||
const confirmDelete = l10n.t('Are you sure you want to delete repository "{0}" and its associated images?', node.repoName);
|
||||
const confirmDelete = l10n.t('Are you sure you want to delete repository "{0}" and its associated images?', node.wrappedItem.label);
|
||||
// no need to check result - cancel will throw a UserCancelledError
|
||||
await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);
|
||||
|
||||
const deleting = l10n.t('Deleting repository "{0}"...', node.repoName);
|
||||
const deleting = l10n.t('Deleting repository "{0}"...', node.wrappedItem.label);
|
||||
await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
|
||||
await node.deleteTreeItem(context);
|
||||
const azureDataProvider = node.provider as unknown as AzureRegistryDataProvider;
|
||||
await azureDataProvider.deleteRepository(node.wrappedItem);
|
||||
});
|
||||
|
||||
const deleteSucceeded = l10n.t('Successfully deleted repository "{0}".', node.repoName);
|
||||
// don't wait
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
window.showInformationMessage(deleteSucceeded);
|
||||
void ext.registriesTree.refresh();
|
||||
|
||||
const deleteSucceeded = l10n.t('Successfully deleted repository "{0}".', node.wrappedItem.label);
|
||||
void window.showInformationMessage(deleteSucceeded);
|
||||
}
|
||||
|
|
|
@ -4,16 +4,15 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, nonNullProp, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import { parseDockerLikeImageName } from '@microsoft/vscode-container-client';
|
||||
import { CommonRegistry, CommonTag, isDockerHubRegistry, LoginInformation } from '@microsoft/vscode-docker-registries';
|
||||
import * as semver from 'semver';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../../extensionVariables';
|
||||
import { parseDockerLikeImageName } from '../../../runtimes/docker/clients/DockerClientBase/parseDockerLikeImageName';
|
||||
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
|
||||
import { DockerHubNamespaceTreeItem } from '../../../tree/registries/dockerHub/DockerHubNamespaceTreeItem';
|
||||
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
|
||||
import { RegistryTreeItemBase } from '../../../tree/registries/RegistryTreeItemBase';
|
||||
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
|
||||
import { isAzureRegistry } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { getFullImageNameFromRegistryTagItem } from '../../../tree/registries/registryTreeUtils';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { installExtension } from '../../../utils/installExtension';
|
||||
import { registryExperience } from '../../../utils/registryExperience';
|
||||
import { addImageTaggingTelemetry } from '../../images/tagImage';
|
||||
|
||||
const acaExtensionId = 'ms-azuretools.vscode-azurecontainerapps';
|
||||
|
@ -27,7 +26,7 @@ interface DeployImageToAcaOptionsContract {
|
|||
secret?: string;
|
||||
}
|
||||
|
||||
export async function deployImageToAca(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
|
||||
export async function deployImageToAca(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
|
||||
// Assert installation of the ACA extension
|
||||
if (!isAcaExtensionInstalled()) {
|
||||
// This will always throw a `UserCancelledError` but with the appropriate step name
|
||||
|
@ -36,34 +35,35 @@ export async function deployImageToAca(context: IActionContext, node?: RemoteTag
|
|||
}
|
||||
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>([registryExpectedContextValues.dockerHub.tag, registryExpectedContextValues.dockerV2.tag], context);
|
||||
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: /commontag/i } });
|
||||
}
|
||||
|
||||
const commandOptions: Partial<DeployImageToAcaOptionsContract> = {
|
||||
image: node.fullTag,
|
||||
image: getFullImageNameFromRegistryTagItem(node.wrappedItem),
|
||||
};
|
||||
|
||||
addImageTaggingTelemetry(context, commandOptions.image, '');
|
||||
|
||||
const registry: RegistryTreeItemBase = node.parent.parent;
|
||||
if (registry instanceof AzureRegistryTreeItem) {
|
||||
const registry: UnifiedRegistryItem<CommonRegistry> = node.parent.parent as unknown as UnifiedRegistryItem<CommonRegistry>;
|
||||
|
||||
if (isAzureRegistry(registry.wrappedItem)) {
|
||||
// No additional work to do; ACA can handle this on its own
|
||||
} else {
|
||||
const { auth } = await registry.getDockerCliCredentials() as { auth?: { username?: string, password?: string } };
|
||||
const logInInfo: LoginInformation = await registry.provider.getLoginInformation(registry.wrappedItem);
|
||||
|
||||
if (!auth?.username || !auth?.password) {
|
||||
throw new Error(vscode.l10n.t('No credentials found for registry "{0}".', registry.label));
|
||||
if (!logInInfo?.username || !logInInfo?.secret) {
|
||||
throw new Error(vscode.l10n.t('No credentials found for registry "{0}".', registry.wrappedItem.label));
|
||||
}
|
||||
|
||||
if (registry instanceof DockerHubNamespaceTreeItem) {
|
||||
if (isDockerHubRegistry(registry.wrappedItem)) {
|
||||
// Ensure Docker Hub images are prefixed with 'docker.io/...'
|
||||
if (!/^docker\.io\//i.test(commandOptions.image)) {
|
||||
commandOptions.image = 'docker.io/' + commandOptions.image;
|
||||
}
|
||||
}
|
||||
|
||||
commandOptions.username = auth.username;
|
||||
commandOptions.secret = auth.password;
|
||||
commandOptions.username = logInInfo.username;
|
||||
commandOptions.secret = logInInfo.secret;
|
||||
}
|
||||
|
||||
commandOptions.registryName = nonNullProp(parseDockerLikeImageName(commandOptions.image), 'registry');
|
||||
|
|
|
@ -5,45 +5,43 @@
|
|||
|
||||
import type { Site } from '@azure/arm-appservice'; // These are only dev-time imports so don't need to be lazy
|
||||
import type { IAppServiceWizardContext } from "@microsoft/vscode-azext-azureappservice"; // These are only dev-time imports so don't need to be lazy
|
||||
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
|
||||
import { env, l10n, Uri, window } from "vscode";
|
||||
import { AzureWizard, AzureWizardExecuteStep, AzureWizardPromptStep, IActionContext, createSubscriptionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
|
||||
import { CommonTag } from '@microsoft/vscode-docker-registries';
|
||||
import { Uri, env, l10n, window } from "vscode";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { RegistryApi } from '../../../tree/registries/all/RegistryApi';
|
||||
import { azureRegistryProviderId } from '../../../tree/registries/azure/azureRegistryProvider';
|
||||
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
|
||||
import { RemoteTagTreeItem } from '../../../tree/registries/RemoteTagTreeItem';
|
||||
import { getAzActTreeItem, getAzExtAppService, getAzExtAzureUtils } from '../../../utils/lazyPackages';
|
||||
import { AzureSubscriptionRegistryItem } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getAzExtAppService, getAzExtAzureUtils } from '../../../utils/lazyPackages';
|
||||
import { registryExperience } from '../../../utils/registryExperience';
|
||||
import { DockerAssignAcrPullRoleStep } from './DockerAssignAcrPullRoleStep';
|
||||
import { DockerSiteCreateStep } from './DockerSiteCreateStep';
|
||||
import { DockerWebhookCreateStep } from './DockerWebhookCreateStep';
|
||||
import { WebSitesPortPromptStep } from './WebSitesPortPromptStep';
|
||||
|
||||
|
||||
export interface IAppServiceContainerWizardContext extends IAppServiceWizardContext {
|
||||
webSitesPort?: number;
|
||||
}
|
||||
|
||||
export async function deployImageToAzure(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
|
||||
export async function deployImageToAzure(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>([registryExpectedContextValues.dockerHub.tag, registryExpectedContextValues.dockerV2.tag], context);
|
||||
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: 'commontag' } });
|
||||
}
|
||||
|
||||
const azExtAzureUtils = await getAzExtAzureUtils();
|
||||
const vscAzureAppService = await getAzExtAppService();
|
||||
const azActTreeItem = await getAzActTreeItem();
|
||||
const promptSteps: AzureWizardPromptStep<IAppServiceWizardContext>[] = [];
|
||||
|
||||
const subscriptionItem = await registryExperience<AzureSubscriptionRegistryItem>(context, {
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: /azuresubscription/i },
|
||||
});
|
||||
const subscriptionContext = createSubscriptionContext(subscriptionItem.wrappedItem.subscription);
|
||||
const wizardContext: IActionContext & Partial<IAppServiceContainerWizardContext> = {
|
||||
...context,
|
||||
...subscriptionContext,
|
||||
newSiteOS: vscAzureAppService.WebsiteOS.linux,
|
||||
newSiteKind: vscAzureAppService.AppKind.app
|
||||
};
|
||||
const promptSteps: AzureWizardPromptStep<IAppServiceWizardContext>[] = [];
|
||||
// Create a temporary azure account tree item since Azure might not be connected
|
||||
const azureAccountTreeItem = new azActTreeItem.AzureAccountTreeItem(ext.registriesRoot, { id: azureRegistryProviderId, api: RegistryApi.DockerV2 });
|
||||
const subscriptionStep = await azureAccountTreeItem.getSubscriptionPromptStep(wizardContext);
|
||||
if (subscriptionStep) {
|
||||
promptSteps.push(subscriptionStep);
|
||||
}
|
||||
|
||||
promptSteps.push(new vscAzureAppService.SiteNameStep());
|
||||
promptSteps.push(new azExtAzureUtils.ResourceGroupListStep());
|
||||
|
|
|
@ -3,27 +3,32 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { IActionContext, createSubscriptionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { ext } from '../../../extensionVariables';
|
||||
import { AzureRegistryTreeItem } from '../../../tree/registries/azure/AzureRegistryTreeItem';
|
||||
import { AzureRepositoryTreeItem } from '../../../tree/registries/azure/AzureRepositoryTreeItem';
|
||||
import type { SubscriptionTreeItem } from '../../../tree/registries/azure/SubscriptionTreeItem'; // These are only dev-time imports so don't need to be lazy
|
||||
import { registryExpectedContextValues } from '../../../tree/registries/registryContextValues';
|
||||
import { getAzExtAzureUtils, getAzSubTreeItem } from '../../../utils/lazyPackages';
|
||||
import { AzureRegistry, AzureRepository, AzureSubscriptionRegistryItem, isAzureRegistry, isAzureSubscriptionRegistryItem } from '../../../tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { UnifiedRegistryItem } from '../../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getAzExtAzureUtils } from '../../../utils/lazyPackages';
|
||||
import { registryExperience } from '../../../utils/registryExperience';
|
||||
|
||||
export async function openInAzurePortal(context: IActionContext, node?: SubscriptionTreeItem | AzureRegistryTreeItem | AzureRepositoryTreeItem): Promise<void> {
|
||||
export async function openInAzurePortal(context: IActionContext, node?: UnifiedRegistryItem<AzureRegistry | AzureSubscriptionRegistryItem | AzureRepository>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, context);
|
||||
node = await registryExperience<AzureRegistry>(context, {
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: [/commonregistry/i] },
|
||||
});
|
||||
}
|
||||
|
||||
const azSubTreeItem = await getAzSubTreeItem();
|
||||
const azureRegistryItem = node.wrappedItem;
|
||||
const azExtAzureUtils = await getAzExtAzureUtils();
|
||||
|
||||
if (node instanceof azSubTreeItem.SubscriptionTreeItem) {
|
||||
await azExtAzureUtils.openInPortal(node.subscription, node.subscription.subscriptionId);
|
||||
} else if (node instanceof AzureRegistryTreeItem) {
|
||||
await azExtAzureUtils.openInPortal(node.parent.subscription, node.registryId);
|
||||
let subscriptionContext = undefined;
|
||||
if (isAzureSubscriptionRegistryItem(azureRegistryItem)) {
|
||||
subscriptionContext = createSubscriptionContext(azureRegistryItem.subscription);
|
||||
await azExtAzureUtils.openInPortal(subscriptionContext, `/subscriptions/${subscriptionContext.subscriptionId}`);
|
||||
} else if (isAzureRegistry(azureRegistryItem)) {
|
||||
subscriptionContext = createSubscriptionContext(azureRegistryItem.parent.subscription);
|
||||
await azExtAzureUtils.openInPortal(subscriptionContext, azureRegistryItem.id);
|
||||
} else {
|
||||
await azExtAzureUtils.openInPortal(node.parent.parent.subscription, `${node.parent.registryId}/repository`);
|
||||
subscriptionContext = createSubscriptionContext(azureRegistryItem.parent.parent.subscription);
|
||||
await azExtAzureUtils.openInPortal(subscriptionContext, `${azureRegistryItem.parent.id}/repository`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import type { Run } from '@azure/arm-containerregistry';
|
||||
import { scheduleRunRequest, RootStrategy } from './scheduleRunRequest';
|
||||
import { delay } from '../../../../utils/promiseUtils';
|
||||
import { IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import * as vscode from 'vscode';
|
||||
import { getArmContainerRegistry } from '../../../../utils/lazyPackages';
|
||||
import { delay } from '../../../../utils/promiseUtils';
|
||||
import { RootStrategy, scheduleRunRequest } from './scheduleRunRequest';
|
||||
|
||||
const WAIT_MS = 5000;
|
||||
|
||||
|
@ -18,7 +18,7 @@ export async function buildImageInAzure(context: IActionContext, uri?: vscode.Ur
|
|||
}
|
||||
|
||||
const getRun = await scheduleRunRequest(context, "DockerBuildRequest", uri, rootStrategy);
|
||||
|
||||
|
||||
let run = await getRun();
|
||||
const { KnownRunStatus } = await getArmContainerRegistry();
|
||||
while (
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type { TaskRunRequest } from "@azure/arm-containerregistry"; // These are only dev-time imports so don't need to be lazy
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { l10n, window } from "vscode";
|
||||
import { ext } from "../../../../extensionVariables";
|
||||
import { AzureTaskTreeItem } from "../../../../tree/registries/azure/AzureTaskTreeItem";
|
||||
|
||||
export async function runAzureTask(context: IActionContext, node?: AzureTaskTreeItem): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<AzureTaskTreeItem>(AzureTaskTreeItem.contextValue, context);
|
||||
}
|
||||
|
||||
const registryTI = node.parent.parent;
|
||||
const runRequest: TaskRunRequest = { type: 'TaskRunRequest', taskId: node.id };
|
||||
const run = await (await registryTI.getClient(context)).registries.beginScheduleRunAndWait(registryTI.resourceGroup, registryTI.registryName, runRequest);
|
||||
await node.parent.refresh(context);
|
||||
// don't wait
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
window.showInformationMessage(l10n.t('Successfully scheduled run "{0}" for task "{1}".', run.runId, node.taskName));
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import { scheduleRunRequest } from './scheduleRunRequest';
|
||||
|
||||
export async function runFileAsAzureTask(context: IActionContext, uri?: vscode.Uri): Promise<void> {
|
||||
if (!vscode.workspace.isTrusted) {
|
||||
throw new UserCancelledError('enforceTrust');
|
||||
}
|
||||
|
||||
await scheduleRunRequest(context, "FileTaskRunRequest", uri);
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type { ContainerRegistryManagementClient, DockerBuildRequest as AcrDockerBuildRequest, FileTaskRunRequest as AcrFileTaskRunRequest, OS as AcrOS, Run as AcrRun } from "@azure/arm-containerregistry"; // These are only dev-time imports so don't need to be lazy
|
||||
import type { DockerBuildRequest as AcrDockerBuildRequest, FileTaskRunRequest as AcrFileTaskRunRequest, OS as AcrOS, Run as AcrRun, ContainerRegistryManagementClient } from "@azure/arm-containerregistry"; // These are only dev-time imports so don't need to be lazy
|
||||
import { IActionContext, IAzureQuickPickItem, nonNullProp } from '@microsoft/vscode-azext-utils';
|
||||
import * as fse from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
|
@ -12,12 +12,14 @@ import * as readline from 'readline';
|
|||
import * as tar from 'tar';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../../../extensionVariables';
|
||||
import { AzureRegistryTreeItem } from '../../../../tree/registries/azure/AzureRegistryTreeItem';
|
||||
import { registryExpectedContextValues } from "../../../../tree/registries/registryContextValues";
|
||||
import { AzureRegistry, AzureRegistryItem } from "../../../../tree/registries/Azure/AzureRegistryDataProvider";
|
||||
import { UnifiedRegistryItem } from "../../../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { createAzureContainerRegistryClient, getResourceGroupFromId } from "../../../../utils/azureUtils";
|
||||
import { getStorageBlob } from '../../../../utils/lazyPackages';
|
||||
import { delay } from '../../../../utils/promiseUtils';
|
||||
import { Item, quickPickDockerFileItem, quickPickYamlFileItem } from '../../../../utils/quickPickFile';
|
||||
import { quickPickWorkspaceFolder } from '../../../../utils/quickPickWorkspaceFolder';
|
||||
import { registryExperience } from "../../../../utils/registryExperience";
|
||||
import { addImageTaggingTelemetry, getTagFromUserInput } from '../../../images/tagImage';
|
||||
|
||||
const idPrecision = 6;
|
||||
|
@ -45,7 +47,12 @@ export async function scheduleRunRequest(context: IActionContext, requestType: '
|
|||
throw new Error(vscode.l10n.t('Run Request Type Currently not supported.'));
|
||||
}
|
||||
|
||||
const node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, context);
|
||||
const node: UnifiedRegistryItem<AzureRegistryItem> = await registryExperience<AzureRegistry>(context, {
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: /commonregistry/i },
|
||||
});
|
||||
const registryItem: AzureRegistryItem = node.wrappedItem;
|
||||
const resourceGroup = getResourceGroupFromId(registryItem.id);
|
||||
|
||||
const osPick = ['Linux', 'Windows'].map(item => <IAzureQuickPickItem<AcrOS>>{ label: item, data: item });
|
||||
const osType: AcrOS = (await context.ui.showQuickPick(osPick, { placeHolder: vscode.l10n.t('Select image base OS') })).data;
|
||||
|
@ -63,7 +70,8 @@ export async function scheduleRunRequest(context: IActionContext, requestType: '
|
|||
rootUri = vscode.Uri.file(path.dirname(fileItem.absoluteFilePath));
|
||||
}
|
||||
|
||||
const uploadedSourceLocation: string = await uploadSourceCode(await node.getClient(context), node.registryName, node.resourceGroup, rootUri, tarFilePath);
|
||||
const azureRegistryClient = await createAzureContainerRegistryClient(registryItem.subscription);
|
||||
const uploadedSourceLocation: string = await uploadSourceCode(azureRegistryClient, registryItem.label, resourceGroup, rootUri, tarFilePath);
|
||||
ext.outputChannel.info(vscode.l10n.t('Uploaded source code from {0}', tarFilePath));
|
||||
|
||||
let runRequest: AcrDockerBuildRequest | AcrFileTaskRunRequest;
|
||||
|
@ -88,14 +96,13 @@ export async function scheduleRunRequest(context: IActionContext, requestType: '
|
|||
// Schedule the run and Clean up.
|
||||
ext.outputChannel.info(vscode.l10n.t('Set up run request'));
|
||||
|
||||
const client = await node.getClient(context);
|
||||
const run = await client.registries.beginScheduleRunAndWait(node.resourceGroup, node.registryName, runRequest);
|
||||
const run = await azureRegistryClient.registries.beginScheduleRunAndWait(resourceGroup, registryItem.label, runRequest);
|
||||
ext.outputChannel.info(vscode.l10n.t('Scheduled run {0}', run.runId));
|
||||
|
||||
void streamLogs(context, node, run);
|
||||
void streamLogs(context, registryItem, run);
|
||||
|
||||
// function returns the AcrRun info
|
||||
return async () => client.runs.get(node.resourceGroup, node.registryName, run.runId);
|
||||
return async () => azureRegistryClient.runs.get(resourceGroup, registryItem.label, run.runId);
|
||||
} finally {
|
||||
if (await fse.pathExists(tarFilePath)) {
|
||||
await fse.unlink(tarFilePath);
|
||||
|
@ -155,8 +162,10 @@ async function uploadSourceCode(client: ContainerRegistryManagementClient, regis
|
|||
|
||||
const blobCheckInterval = 1000;
|
||||
const maxBlobChecks = 30;
|
||||
async function streamLogs(context: IActionContext, node: AzureRegistryTreeItem, run: AcrRun): Promise<void> {
|
||||
const result = await (await node.getClient(context)).runs.getLogSasUrl(node.resourceGroup, node.registryName, run.runId);
|
||||
async function streamLogs(context: IActionContext, registryItem: AzureRegistryItem, run: AcrRun): Promise<void> {
|
||||
const azureRegistryClient = await createAzureContainerRegistryClient(registryItem.subscription);
|
||||
const resourceGroup = getResourceGroupFromId(registryItem.id);
|
||||
const result = await azureRegistryClient.runs.getLogSasUrl(resourceGroup, registryItem.label, run.runId);
|
||||
|
||||
const storageBlob = await getStorageBlob();
|
||||
const blobClient = new storageBlob.BlobClient(nonNullProp(result, 'logLink'));
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, nonNullProp, openReadOnlyContent } from "@microsoft/vscode-azext-utils";
|
||||
import { l10n } from 'vscode';
|
||||
import { ext } from "../../../../extensionVariables";
|
||||
import { AzureTaskRunTreeItem } from "../../../../tree/registries/azure/AzureTaskRunTreeItem";
|
||||
import { bufferToString } from "../../../../utils/execAsync";
|
||||
import { getStorageBlob } from "../../../../utils/lazyPackages";
|
||||
|
||||
export async function viewAzureTaskLogs(context: IActionContext, node?: AzureTaskRunTreeItem): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<AzureTaskRunTreeItem>(AzureTaskRunTreeItem.contextValue, context);
|
||||
}
|
||||
|
||||
const registryTI = node.parent.parent.parent;
|
||||
await node.runWithTemporaryDescription(context, l10n.t('Retrieving logs...'), async () => {
|
||||
const result = await (await registryTI.getClient(context)).runs.getLogSasUrl(registryTI.resourceGroup, registryTI.registryName, node.runId);
|
||||
|
||||
const storageBlob = await getStorageBlob();
|
||||
const blobClient = new storageBlob.BlobClient(nonNullProp(result, 'logLink'));
|
||||
const contentBuffer = await blobClient.downloadToBuffer();
|
||||
const content = bufferToString(contentBuffer);
|
||||
|
||||
await openReadOnlyContent(node, content, '.log');
|
||||
});
|
||||
}
|
|
@ -6,31 +6,32 @@
|
|||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { l10n, ProgressLocation, window } from "vscode";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { registryExpectedContextValues } from "../../../tree/registries/registryContextValues";
|
||||
import { RemoteTagTreeItem } from "../../../tree/registries/RemoteTagTreeItem";
|
||||
import { registryRequest } from "../../../utils/registryRequestUtils";
|
||||
import { AzureRegistryDataProvider, AzureTag } from "../../../tree/registries/Azure/AzureRegistryDataProvider";
|
||||
import { getFullImageNameFromRegistryTagItem } from "../../../tree/registries/registryTreeUtils";
|
||||
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { registryExperience } from "../../../utils/registryExperience";
|
||||
|
||||
export async function untagAzureImage(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
|
||||
export async function untagAzureImage(context: IActionContext, node?: UnifiedRegistryItem<AzureTag>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>(registryExpectedContextValues.azure.tag, {
|
||||
...context,
|
||||
suppressCreatePick: true,
|
||||
noItemFoundErrorMessage: l10n.t('No images are available to untag')
|
||||
// we can't pass in the azure tree provider because it's not a UnifiedRegistryItem and we need the provider to untag
|
||||
node = await registryExperience<AzureTag>(context, {
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: /commontag/i },
|
||||
});
|
||||
}
|
||||
|
||||
const confirmUntag: string = l10n.t('Are you sure you want to untag image "{0}"? This does not delete the manifest referenced by the tag.', node.repoNameAndTag);
|
||||
const fullTag = getFullImageNameFromRegistryTagItem(node.wrappedItem);
|
||||
const confirmUntag: string = l10n.t('Are you sure you want to untag image "{0}"? This does not delete the manifest referenced by the tag.', fullTag);
|
||||
// no need to check result - cancel will throw a UserCancelledError
|
||||
await context.ui.showWarningMessage(confirmUntag, { modal: true }, { title: "Untag" });
|
||||
|
||||
const untagging = l10n.t('Untagging image "{0}"...', node.repoNameAndTag);
|
||||
const repoTI = node.parent;
|
||||
const untagging = l10n.t('Untagging image "{0}"...', fullTag);
|
||||
await window.withProgress({ location: ProgressLocation.Notification, title: untagging }, async () => {
|
||||
await registryRequest(repoTI, 'DELETE', `v2/_acr/${repoTI.repoName}/tags/${node.tag}`);
|
||||
await repoTI.refresh(context);
|
||||
const provider = node.provider as unknown as AzureRegistryDataProvider;
|
||||
await provider.untagImage(node.wrappedItem);
|
||||
});
|
||||
|
||||
// don't wait
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
window.showInformationMessage(l10n.t('Successfully untagged image "{0}".', node.repoNameAndTag));
|
||||
void ext.registriesTree.refresh();
|
||||
void window.showInformationMessage(l10n.t('Successfully untagged image "{0}".', fullTag));
|
||||
}
|
||||
|
|
|
@ -5,15 +5,18 @@
|
|||
|
||||
import { IActionContext, openReadOnlyJson } from "@microsoft/vscode-azext-utils";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { AzureRegistryTreeItem } from "../../../tree/registries/azure/AzureRegistryTreeItem";
|
||||
import { AzureTaskRunTreeItem } from "../../../tree/registries/azure/AzureTaskRunTreeItem";
|
||||
import { AzureTaskTreeItem } from "../../../tree/registries/azure/AzureTaskTreeItem";
|
||||
import { registryExpectedContextValues } from "../../../tree/registries/registryContextValues";
|
||||
import { AzureRegistry } from "../../../tree/registries/Azure/AzureRegistryDataProvider";
|
||||
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { registryExperience } from "../../../utils/registryExperience";
|
||||
|
||||
export async function viewAzureProperties(context: IActionContext, node?: AzureRegistryTreeItem | AzureTaskTreeItem | AzureTaskRunTreeItem): Promise<void> {
|
||||
export async function viewAzureProperties(context: IActionContext, node?: UnifiedRegistryItem<AzureRegistry>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<AzureRegistryTreeItem>(registryExpectedContextValues.azure.registry, context);
|
||||
node = await registryExperience<AzureRegistry>(context, {
|
||||
registryFilter: { include: [ext.azureRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: /commonregistry/i },
|
||||
});
|
||||
}
|
||||
|
||||
await openReadOnlyJson(node, node.properties);
|
||||
const registryItem = node.wrappedItem;
|
||||
await openReadOnlyJson({ label: registryItem.label, fullId: registryItem.id }, registryItem.registryProperties);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { ext } from "../../extensionVariables";
|
||||
|
||||
export async function connectRegistry(context: IActionContext): Promise<void> {
|
||||
await ext.registriesRoot.connectRegistry(context);
|
||||
export async function connectRegistry(): Promise<void> {
|
||||
await ext.registriesRoot.connectRegistryProvider();
|
||||
}
|
||||
|
|
|
@ -4,20 +4,17 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { CommonTag } from '@microsoft/vscode-docker-registries';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
|
||||
import { RemoteTagTreeItem } from '../../tree/registries/RemoteTagTreeItem';
|
||||
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getFullImageNameFromRegistryTagItem } from '../../tree/registries/registryTreeUtils';
|
||||
import { registryExperience } from '../../utils/registryExperience';
|
||||
|
||||
export async function copyRemoteFullTag(context: IActionContext, node?: RemoteTagTreeItem): Promise<string> {
|
||||
export async function copyRemoteFullTag(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<string> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>([registryExpectedContextValues.dockerV2.tag, registryExpectedContextValues.dockerHub.tag], {
|
||||
...context,
|
||||
noItemFoundErrorMessage: vscode.l10n.t('No remote images are available to copy the full tag')
|
||||
});
|
||||
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: /commontag/i } });
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
// Don't wait
|
||||
void vscode.env.clipboard.writeText(node.fullTag);
|
||||
return node.fullTag;
|
||||
const fullTag = getFullImageNameFromRegistryTagItem(node.wrappedItem);
|
||||
void vscode.env.clipboard.writeText(fullTag);
|
||||
return fullTag;
|
||||
}
|
||||
|
|
|
@ -3,34 +3,23 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, nonNullProp } from "@microsoft/vscode-azext-utils";
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { CommonTag, RegistryV2DataProvider } from "@microsoft/vscode-docker-registries";
|
||||
import * as vscode from "vscode";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { AzureTaskRunTreeItem } from "../../tree/registries/azure/AzureTaskRunTreeItem";
|
||||
import { DockerV2TagTreeItem } from "../../tree/registries/dockerV2/DockerV2TagTreeItem";
|
||||
import { registryExpectedContextValues } from "../../tree/registries/registryContextValues";
|
||||
import { UnifiedRegistryItem } from "../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { registryExperience } from "../../utils/registryExperience";
|
||||
|
||||
export async function copyRemoteImageDigest(context: IActionContext, node?: DockerV2TagTreeItem | AzureTaskRunTreeItem): Promise<void> {
|
||||
export async function copyRemoteImageDigest(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<DockerV2TagTreeItem>(registryExpectedContextValues.dockerV2.tag, {
|
||||
...context,
|
||||
noItemFoundErrorMessage: vscode.l10n.t('No remote images are available to copy the digest')
|
||||
node = await registryExperience<CommonTag>(context, {
|
||||
registryFilter: { exclude: [ext.dockerHubRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: /commontag/i, },
|
||||
});
|
||||
}
|
||||
|
||||
let digest: string;
|
||||
if (node instanceof AzureTaskRunTreeItem) {
|
||||
if (node.outputImage) {
|
||||
digest = nonNullProp(node.outputImage, 'digest');
|
||||
} else {
|
||||
throw new Error(vscode.l10n.t('Failed to find output image for this task run.'));
|
||||
}
|
||||
} else {
|
||||
await node.runWithTemporaryDescription(context, vscode.l10n.t('Getting digest...'), async () => {
|
||||
digest = await (<DockerV2TagTreeItem>node).getDigest();
|
||||
});
|
||||
}
|
||||
const v2DataProvider = node.provider as unknown as RegistryV2DataProvider;
|
||||
const digest = await v2DataProvider.getImageDigest(node.wrappedItem);
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
vscode.env.clipboard.writeText(digest);
|
||||
void vscode.env.clipboard.writeText(digest);
|
||||
}
|
||||
|
|
|
@ -3,35 +3,51 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { l10n, ProgressLocation, window } from 'vscode';
|
||||
import { DialogResponses, IActionContext, UserCancelledError, parseError } from '@microsoft/vscode-azext-utils';
|
||||
import { CommonRegistryDataProvider, CommonTag } from '@microsoft/vscode-docker-registries';
|
||||
import { ProgressLocation, l10n, window } from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { DockerV2TagTreeItem } from '../../tree/registries/dockerV2/DockerV2TagTreeItem';
|
||||
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
|
||||
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getImageNameFromRegistryTagItem } from '../../tree/registries/registryTreeUtils';
|
||||
import { registryExperience } from '../../utils/registryExperience';
|
||||
|
||||
export async function deleteRemoteImage(context: IActionContext, node?: DockerV2TagTreeItem): Promise<void> {
|
||||
export async function deleteRemoteImage(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<DockerV2TagTreeItem>(registryExpectedContextValues.dockerV2.tag, {
|
||||
...context,
|
||||
suppressCreatePick: true,
|
||||
noItemFoundErrorMessage: l10n.t('No remote images are available to delete')
|
||||
node = await registryExperience<CommonTag>(context, {
|
||||
registryFilter: { exclude: [ext.githubRegistryDataProvider.label, ext.dockerHubRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: /commontag/i },
|
||||
});
|
||||
}
|
||||
|
||||
const confirmDelete = l10n.t('Are you sure you want to delete image "{0}"? This will delete all images that have the same digest.', node.repoNameAndTag);
|
||||
const provider = node.provider as unknown as CommonRegistryDataProvider;
|
||||
if (typeof provider.deleteTag !== 'function') {
|
||||
throw new Error(l10n.t('Deleting remote images is not supported on this registry.'));
|
||||
}
|
||||
|
||||
const tagName = getImageNameFromRegistryTagItem(node.wrappedItem);
|
||||
const confirmDelete = l10n.t('Are you sure you want to delete image "{0}"? This will delete all images that have the same digest.', tagName);
|
||||
// no need to check result - cancel will throw a UserCancelledError
|
||||
await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);
|
||||
|
||||
const repoTI = node.parent;
|
||||
const deleting = l10n.t('Deleting image "{0}"...', node.repoNameAndTag);
|
||||
const deleting = l10n.t('Deleting image "{0}"...', tagName);
|
||||
await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
|
||||
await node.deleteTreeItem(context);
|
||||
try {
|
||||
await provider.deleteTag(node.wrappedItem);
|
||||
} catch (error) {
|
||||
const errorType: string = parseError(error).errorType.toLowerCase();
|
||||
if (errorType === '405' || errorType === 'unsupported') {
|
||||
// Don't wait
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
context.ui.showWarningMessage('Deleting remote images is not supported on this registry. It may need to be enabled.', { learnMoreLink: 'https://aka.ms/AA7jsql' });
|
||||
throw new UserCancelledError();
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Other tags that also matched the image may have been deleted, so refresh the whole repository
|
||||
await repoTI.refresh(context);
|
||||
const message = l10n.t('Successfully deleted image "{0}".', node.repoNameAndTag);
|
||||
// don't wait
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
window.showInformationMessage(message);
|
||||
void ext.registriesTree.refresh();
|
||||
void window.showInformationMessage(l10n.t('Successfully deleted image "{0}".', tagName));
|
||||
}
|
||||
|
|
|
@ -3,17 +3,16 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, InvalidTreeItem } from "@microsoft/vscode-azext-utils";
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { CommonRegistry } from "@microsoft/vscode-docker-registries";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { ICachedRegistryProvider } from "../../tree/registries/ICachedRegistryProvider";
|
||||
import { IRegistryProviderTreeItem } from "../../tree/registries/IRegistryProviderTreeItem";
|
||||
import { UnifiedRegistryItem } from "../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { registryExperience } from "../../utils/registryExperience";
|
||||
|
||||
export async function disconnectRegistry(context: IActionContext, node?: InvalidTreeItem | IRegistryProviderTreeItem): Promise<void> {
|
||||
let cachedProvider: ICachedRegistryProvider | undefined;
|
||||
if (node instanceof InvalidTreeItem) {
|
||||
cachedProvider = <ICachedRegistryProvider>node.data;
|
||||
} else if (node) {
|
||||
cachedProvider = node.cachedProvider;
|
||||
export async function disconnectRegistry(context: IActionContext, node?: UnifiedRegistryItem<unknown>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await registryExperience<CommonRegistry>(context, { registryFilter: { exclude: [ext.genericRegistryV2DataProvider.label] } });
|
||||
}
|
||||
await ext.registriesRoot.disconnectRegistry(context, cachedProvider);
|
||||
|
||||
await ext.registriesTree.disconnectRegistryProvider(node);
|
||||
}
|
||||
|
|
|
@ -4,30 +4,32 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { CommonRegistryItem, isRegistry, isRepository, isTag } from "@microsoft/vscode-docker-registries";
|
||||
import * as vscode from "vscode";
|
||||
import { dockerHubUrl } from "../../../constants";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { DockerHubNamespaceTreeItem } from "../../../tree/registries/dockerHub/DockerHubNamespaceTreeItem";
|
||||
import { DockerHubRepositoryTreeItem } from "../../../tree/registries/dockerHub/DockerHubRepositoryTreeItem";
|
||||
import { registryExpectedContextValues } from "../../../tree/registries/registryContextValues";
|
||||
import { RemoteTagTreeItem } from "../../../tree/registries/RemoteTagTreeItem";
|
||||
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { registryExperience } from "../../../utils/registryExperience";
|
||||
|
||||
export async function openDockerHubInBrowser(context: IActionContext, node?: DockerHubNamespaceTreeItem | DockerHubRepositoryTreeItem | RemoteTagTreeItem): Promise<void> {
|
||||
export async function openDockerHubInBrowser(context: IActionContext, node?: UnifiedRegistryItem<CommonRegistryItem>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<DockerHubNamespaceTreeItem>(registryExpectedContextValues.dockerHub.registry, {
|
||||
...context,
|
||||
noItemFoundErrorMessage: vscode.l10n.t('No Docker Hub registries available to browse')
|
||||
node = await registryExperience<CommonRegistryItem>(context, {
|
||||
registryFilter: { include: [ext.dockerHubRegistryDataProvider.label] },
|
||||
contextValueFilter: { include: [/commonregistry/i] },
|
||||
});
|
||||
}
|
||||
|
||||
let url = dockerHubUrl;
|
||||
if (node instanceof DockerHubNamespaceTreeItem) {
|
||||
url += `u/${node.namespace}`;
|
||||
} else if (node instanceof DockerHubRepositoryTreeItem) {
|
||||
url += `r/${node.parent.namespace}/${node.repoName}`;
|
||||
const dockerHubItem = node.wrappedItem;
|
||||
|
||||
if (isRegistry(dockerHubItem)) {
|
||||
url = `${url}u/${dockerHubItem.label}`;
|
||||
} else if (isRepository(dockerHubItem)) {
|
||||
url = `${url}r/${dockerHubItem.parent.label}/${dockerHubItem.label}`;
|
||||
} else if (isTag(dockerHubItem)) {
|
||||
url = `${url}r/${dockerHubItem.parent.parent.label}/${dockerHubItem.parent.label}/tags`;
|
||||
} else {
|
||||
const repoTI = <DockerHubRepositoryTreeItem>node.parent;
|
||||
url += `r/${repoTI.parent.namespace}/${repoTI.repoName}/tags`;
|
||||
throw new Error(`Unexpected node type ${dockerHubItem.additionalContextValues || ''}`);
|
||||
}
|
||||
|
||||
await vscode.env.openExternal(vscode.Uri.parse(url));
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
|
||||
export async function addTrackedGenericV2Registry(context: IActionContext, node?: UnifiedRegistryItem<unknown>): Promise<void> {
|
||||
// if there are already registries, add a new registry to the existing root node
|
||||
if (ext.genericRegistryV2DataProvider.hasTrackedRegistries()) {
|
||||
await ext.genericRegistryV2DataProvider.addTrackedRegistry();
|
||||
} else {
|
||||
// if there are no registries, connect as usual
|
||||
await ext.registriesTree.connectRegistryProvider(ext.genericRegistryV2DataProvider);
|
||||
}
|
||||
|
||||
// don't wait
|
||||
void ext.registriesTree.refresh();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { V2Registry } from "@microsoft/vscode-docker-registries";
|
||||
import { ext } from "../../../extensionVariables";
|
||||
import { UnifiedRegistryItem } from "../../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
import { registryExperience } from "../../../utils/registryExperience";
|
||||
|
||||
export async function removeTrackedGenericV2Registry(context: IActionContext, node?: UnifiedRegistryItem<V2Registry>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await registryExperience<V2Registry>(context, {
|
||||
registryFilter: { include: [ext.genericRegistryV2DataProvider.label] },
|
||||
contextValueFilter: { include: /commonregistry/i },
|
||||
});
|
||||
}
|
||||
|
||||
await ext.genericRegistryV2DataProvider.removeTrackedRegistry(node.wrappedItem);
|
||||
|
||||
// remove the provider if it's the last one
|
||||
if (!ext.genericRegistryV2DataProvider.hasTrackedRegistries()) {
|
||||
await ext.registriesTree.disconnectRegistryProvider(node.parent);
|
||||
}
|
||||
|
||||
// don't wait
|
||||
void ext.registriesTree.refresh();
|
||||
}
|
|
@ -4,32 +4,25 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, parseError } from '@microsoft/vscode-azext-utils';
|
||||
import { CommonRegistry } from '@microsoft/vscode-docker-registries';
|
||||
import * as stream from 'stream';
|
||||
import * as vscode from 'vscode';
|
||||
import { NULL_GUID } from '../../constants';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
|
||||
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
|
||||
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { registryExperience } from '../../utils/registryExperience';
|
||||
|
||||
export async function logInToDockerCli(context: IActionContext, node?: RegistryTreeItemBase): Promise<void> {
|
||||
export async function logInToDockerCli(context: IActionContext, node?: UnifiedRegistryItem<CommonRegistry>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RegistryTreeItemBase>(registryExpectedContextValues.all.registry, context);
|
||||
node = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: /commonregistry/i } });
|
||||
}
|
||||
|
||||
const creds = await node.getDockerCliCredentials();
|
||||
const auth: { username?: string, password?: string, token?: string } = creds.auth || {};
|
||||
let username: string | undefined;
|
||||
let password: string | undefined;
|
||||
if (auth.token) {
|
||||
username = NULL_GUID;
|
||||
password = auth.token;
|
||||
} else if (auth.password) {
|
||||
username = auth.username;
|
||||
password = auth.password;
|
||||
}
|
||||
const creds = await node.provider?.getLoginInformation?.(node.wrappedItem);
|
||||
const username = creds?.username;
|
||||
const secret = creds?.secret;
|
||||
const server = creds?.server;
|
||||
|
||||
if (!username || !password) {
|
||||
ext.outputChannel.warn(vscode.l10n.t('Skipping login for "{0}" because it does not require authentication.', creds.registryPath));
|
||||
if (!username || !secret) {
|
||||
ext.outputChannel.warn(vscode.l10n.t('Skipping login for "{0}" because it does not require authentication.', node.provider.label));
|
||||
} else {
|
||||
const progressOptions: vscode.ProgressOptions = {
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
|
@ -42,10 +35,10 @@ export async function logInToDockerCli(context: IActionContext, node?: RegistryT
|
|||
client => client.login({
|
||||
username: username,
|
||||
passwordStdIn: true,
|
||||
registry: creds.registryPath,
|
||||
registry: server
|
||||
}),
|
||||
{
|
||||
stdInPipe: stream.Readable.from(password),
|
||||
stdInPipe: stream.Readable.from(secret),
|
||||
}
|
||||
);
|
||||
ext.outputChannel.info('Login succeeded.');
|
||||
|
|
|
@ -4,17 +4,21 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { CommonRegistry } from '@microsoft/vscode-docker-registries';
|
||||
import { l10n } from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
|
||||
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
|
||||
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
|
||||
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { registryExperience } from '../../utils/registryExperience';
|
||||
|
||||
export async function logOutOfDockerCli(context: IActionContext, node?: RegistryTreeItemBase): Promise<void> {
|
||||
export async function logOutOfDockerCli(context: IActionContext, node?: UnifiedRegistryItem<CommonRegistry>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RegistryTreeItemBase>(registryExpectedContextValues.all.registry, context);
|
||||
node = await registryExperience<CommonRegistry>(context, { contextValueFilter: { include: /commonregistry/i } });
|
||||
}
|
||||
const serverUrl = (await node.provider.getLoginInformation?.(node.wrappedItem))?.server;
|
||||
if (!serverUrl) {
|
||||
throw new Error(l10n.t('Unable to get server URL'));
|
||||
}
|
||||
|
||||
const creds = await node.getDockerCliCredentials();
|
||||
|
||||
const client = await ext.runtimeManager.getClient();
|
||||
const taskCRF = new TaskCommandRunnerFactory(
|
||||
|
@ -24,6 +28,6 @@ export async function logOutOfDockerCli(context: IActionContext, node?: Registry
|
|||
);
|
||||
|
||||
await taskCRF.getCommandRunner()(
|
||||
client.logout({ registry: creds.registryPath })
|
||||
client.logout({ registry: serverUrl }),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,32 +4,33 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import { CommonRegistry, CommonRepository, CommonTag } from '@microsoft/vscode-docker-registries/lib/clients/Common/models';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { TaskCommandRunnerFactory } from '../../runtimes/runners/TaskCommandRunnerFactory';
|
||||
import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
|
||||
import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase';
|
||||
import { RemoteRepositoryTreeItemBase } from '../../tree/registries/RemoteRepositoryTreeItemBase';
|
||||
import { RemoteTagTreeItem } from '../../tree/registries/RemoteTagTreeItem';
|
||||
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { getFullImageNameFromRegistryTagItem, getFullRepositoryNameFromRepositoryItem } from '../../tree/registries/registryTreeUtils';
|
||||
import { registryExperience } from '../../utils/registryExperience';
|
||||
import { logInToDockerCli } from './logInToDockerCli';
|
||||
|
||||
export async function pullRepository(context: IActionContext, node?: RemoteRepositoryTreeItemBase): Promise<void> {
|
||||
export async function pullRepository(context: IActionContext, node?: UnifiedRegistryItem<CommonRepository>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RemoteRepositoryTreeItemBase>(registryExpectedContextValues.all.repository, context);
|
||||
node = await registryExperience<CommonRepository>(context, { contextValueFilter: { include: /commonrepository/i } });
|
||||
}
|
||||
|
||||
await pullImages(context, node.parent, node.repoName, true);
|
||||
await pullImages(context, node.parent, getFullRepositoryNameFromRepositoryItem(node.wrappedItem), true);
|
||||
}
|
||||
|
||||
export async function pullImageFromRepository(context: IActionContext, node?: RemoteTagTreeItem): Promise<void> {
|
||||
export async function pullImageFromRepository(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
|
||||
if (!node) {
|
||||
node = await ext.registriesTree.showTreeItemPicker<RemoteTagTreeItem>(registryExpectedContextValues.all.tag, context);
|
||||
node = await registryExperience<CommonTag>(context, { contextValueFilter: { include: /commontag/i } });
|
||||
}
|
||||
|
||||
await pullImages(context, node.parent.parent, node.repoNameAndTag, false);
|
||||
await pullImages(context, node.parent.parent, getFullImageNameFromRegistryTagItem(node.wrappedItem), false);
|
||||
}
|
||||
|
||||
async function pullImages(context: IActionContext, node: RegistryTreeItemBase, imageRequest: string, allTags: boolean): Promise<void> {
|
||||
await logInToDockerCli(context, node);
|
||||
async function pullImages(context: IActionContext, node: UnifiedRegistryItem<unknown>, imageRequest: string, allTags: boolean): Promise<void> {
|
||||
const registryNode = node as UnifiedRegistryItem<CommonRegistry>;
|
||||
await logInToDockerCli(context, registryNode);
|
||||
|
||||
const client = await ext.runtimeManager.getClient();
|
||||
const taskCRF = new TaskCommandRunnerFactory({
|
||||
|
@ -39,7 +40,7 @@ async function pullImages(context: IActionContext, node: RegistryTreeItemBase, i
|
|||
await taskCRF.getCommandRunner()(
|
||||
client.pullImage(
|
||||
{
|
||||
imageRef: `${node.baseImagePath}/${imageRequest}`,
|
||||
imageRef: imageRequest,
|
||||
allTags: allTags,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -4,16 +4,22 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { RegistryConnectError, V2Registry, isGenericV2Registry } from "@microsoft/vscode-docker-registries";
|
||||
import { l10n } from 'vscode';
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { RegistryConnectErrorTreeItem } from "../../tree/registries/RegistryConnectErrorTreeItem";
|
||||
import { UnifiedRegistryItem } from "../../tree/registries/UnifiedRegistryTreeDataProvider";
|
||||
|
||||
export async function reconnectRegistry(context: IActionContext, node?: RegistryConnectErrorTreeItem): Promise<void> {
|
||||
if (!node?.cachedProvider || !node?.provider) {
|
||||
export async function reconnectRegistry(context: IActionContext, node?: UnifiedRegistryItem<RegistryConnectError>): Promise<void> {
|
||||
if (!node?.provider || !node?.wrappedItem || !node?.parent) {
|
||||
// This is not expected ever, so we'll throw an error which can be bubbled up to a Report Issue if it does
|
||||
throw new Error(l10n.t('Unable to determine provider to re-enter credentials. Please disconnect and connect again.'));
|
||||
}
|
||||
|
||||
await ext.registriesRoot.disconnectRegistry(context, node.cachedProvider);
|
||||
await ext.registriesRoot.connectRegistry(context, node.provider, node.url);
|
||||
if (isGenericV2Registry(node.parent.wrappedItem)) {
|
||||
await ext.genericRegistryV2DataProvider.removeTrackedRegistry(node.parent.wrappedItem as V2Registry);
|
||||
await ext.genericRegistryV2DataProvider.addTrackedRegistry();
|
||||
} else {
|
||||
await ext.registriesTree.disconnectRegistryProvider(node.parent);
|
||||
await ext.registriesRoot.connectRegistryProvider(node.provider);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext, IAzureQuickPickItem, IAzureQuickPickOptions, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import { PortBinding, VoidCommandResponse } from '@microsoft/vscode-container-client';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { PortBinding, VoidCommandResponse } from '../runtimes/docker';
|
||||
import { isDockerComposeClient } from '../runtimes/OrchestratorRuntimeManager';
|
||||
import { resolveVariables } from '../utils/resolveVariables';
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DialogResponses, IActionContext, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import { CommandLineArgs, ContainerOS, VoidCommandResponse, composeArgs, withArg, withQuotedArg } from '@microsoft/vscode-container-client';
|
||||
import * as fse from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { DebugConfiguration, MessageItem, ProgressLocation, l10n, window } from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { CommandLineArgs, ContainerOS, VoidCommandResponse, composeArgs, withArg, withQuotedArg } from '../../runtimes/docker';
|
||||
import { NetCoreTaskHelper, NetCoreTaskOptions } from '../../tasks/netcore/NetCoreTaskHelper';
|
||||
import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem';
|
||||
import { getNetCoreProjectInfo } from '../../utils/netCoreUtils';
|
||||
|
|
|
@ -25,7 +25,6 @@ import { registerListeners } from './telemetry/registerListeners';
|
|||
import { registerTrees } from './tree/registerTrees';
|
||||
import { AlternateYamlLanguageServiceClientFeature } from './utils/AlternateYamlLanguageServiceClientFeature';
|
||||
import { AzExtLogOutputChannelWrapper } from './utils/AzExtLogOutputChannelWrapper';
|
||||
import { AzureAccountExtensionListener } from './utils/AzureAccountExtensionListener';
|
||||
import { logDockerEnvironment, logSystemInfo } from './utils/diagnostics';
|
||||
import { DocumentSettingsClientFeature } from './utils/DocumentSettingsClientFeature';
|
||||
import { migrateOldEnvironmentSettingsIfNeeded } from './utils/migrateOldEnvironmentSettingsIfNeeded';
|
||||
|
@ -133,13 +132,16 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<unknown |
|
|||
// Don't wait
|
||||
void migrateOldEnvironmentSettingsIfNeeded();
|
||||
|
||||
// Call command to activate registry provider extensions
|
||||
// Don't wait
|
||||
void vscode.commands.executeCommand('vscode-docker.activateRegistryProviders');
|
||||
|
||||
return new DockerExtensionApi(ctx);
|
||||
}
|
||||
|
||||
export async function deactivate(ctx: vscode.ExtensionContext): Promise<void> {
|
||||
await callWithTelemetryAndErrorHandling('docker.deactivate', async (activateContext: IActionContext) => {
|
||||
activateContext.telemetry.properties.isActivationEvent = 'true';
|
||||
AzureAccountExtensionListener.dispose();
|
||||
|
||||
await Promise.all([
|
||||
dockerfileLanguageClient.stop(),
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzExtTreeDataProvider, AzExtTreeItem, IExperimentationServiceAdapter } from '@microsoft/vscode-azext-utils';
|
||||
import { DockerHubRegistryDataProvider, GenericRegistryV2DataProvider, GitHubRegistryDataProvider } from '@microsoft/vscode-docker-registries';
|
||||
import { ExtensionContext, StatusBarItem, TreeView } from 'vscode';
|
||||
import { ContainerRuntimeManager } from './runtimes/ContainerRuntimeManager';
|
||||
import { OrchestratorRuntimeManager } from './runtimes/OrchestratorRuntimeManager';
|
||||
|
@ -13,7 +14,8 @@ import { ContainersTreeItem } from './tree/containers/ContainersTreeItem';
|
|||
import { ContextsTreeItem } from './tree/contexts/ContextsTreeItem';
|
||||
import { ImagesTreeItem } from './tree/images/ImagesTreeItem';
|
||||
import { NetworksTreeItem } from './tree/networks/NetworksTreeItem';
|
||||
import { RegistriesTreeItem } from './tree/registries/RegistriesTreeItem';
|
||||
import { AzureRegistryDataProvider } from './tree/registries/Azure/AzureRegistryDataProvider';
|
||||
import { UnifiedRegistryItem, UnifiedRegistryTreeDataProvider } from './tree/registries/UnifiedRegistryTreeDataProvider';
|
||||
import { VolumesTreeItem } from './tree/volumes/VolumesTreeItem';
|
||||
import { AzExtLogOutputChannelWrapper } from './utils/AzExtLogOutputChannelWrapper';
|
||||
|
||||
|
@ -45,9 +47,13 @@ export namespace ext {
|
|||
|
||||
export const prefix: string = 'docker';
|
||||
|
||||
export let registriesTree: AzExtTreeDataProvider;
|
||||
export let registriesTreeView: TreeView<AzExtTreeItem>;
|
||||
export let registriesRoot: RegistriesTreeItem;
|
||||
export let registriesTree: UnifiedRegistryTreeDataProvider;
|
||||
export let registriesTreeView: TreeView<UnifiedRegistryItem<unknown>>;
|
||||
export let registriesRoot: UnifiedRegistryTreeDataProvider;
|
||||
export let genericRegistryV2DataProvider: GenericRegistryV2DataProvider;
|
||||
export let azureRegistryDataProvider: AzureRegistryDataProvider;
|
||||
export let dockerHubRegistryDataProvider: DockerHubRegistryDataProvider;
|
||||
export let githubRegistryDataProvider: GitHubRegistryDataProvider;
|
||||
|
||||
export let volumesTree: AzExtTreeDataProvider;
|
||||
export let volumesTreeView: TreeView<AzExtTreeItem>;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DockerClient, IContainersClient } from './docker';
|
||||
import { DockerClient, IContainersClient } from '@microsoft/vscode-container-client';
|
||||
import { ContextManager, IContextManager } from './ContextManager';
|
||||
import { RuntimeManager } from './RuntimeManager';
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { InspectContextsItem, ListContextItem } from './docker';
|
||||
import { InspectContextsItem, ListContextItem } from '@microsoft/vscode-container-client';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../extensionVariables';
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isAutoConfigurableDockerComposeClient } from './clients/AutoConfigurableDockerComposeClient';
|
||||
import { DockerComposeClient, IContainerOrchestratorClient } from './docker';
|
||||
import { DockerComposeClient, IContainerOrchestratorClient } from '@microsoft/vscode-container-client';
|
||||
import { RuntimeManager } from './RuntimeManager';
|
||||
import { isAutoConfigurableDockerComposeClient } from './clients/AutoConfigurableDockerComposeClient';
|
||||
|
||||
export class OrchestratorRuntimeManager extends RuntimeManager<IContainerOrchestratorClient> {
|
||||
public readonly onOrchestratorRuntimeClientRegistered = this.runtimeClientRegisteredEmitter.event;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ClientIdentity } from '@microsoft/vscode-container-client';
|
||||
import * as vscode from 'vscode';
|
||||
import { ClientIdentity } from './docker';
|
||||
|
||||
export abstract class RuntimeManager<TClient extends ClientIdentity> extends vscode.Disposable {
|
||||
private readonly _runtimeClients = new Map<string, TClient>();
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DockerClient } from '@microsoft/vscode-container-client';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { DockerClient } from '../docker';
|
||||
import { AutoConfigurableClient } from './AutoConfigurableClient';
|
||||
|
||||
export class AutoConfigurableDockerClient extends DockerClient implements AutoConfigurableClient {
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DockerComposeClient, IContainerOrchestratorClient } from '@microsoft/vscode-container-client';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { execAsync } from '../../utils/execAsync';
|
||||
import { AsyncLazy } from '../../utils/lazy';
|
||||
import { DockerComposeClient, IContainerOrchestratorClient } from '../docker';
|
||||
import { isDockerComposeClient } from '../OrchestratorRuntimeManager';
|
||||
import { AutoConfigurableClient } from './AutoConfigurableClient';
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ClientIdentity } from '../contracts/ContainerClient';
|
||||
|
||||
export abstract class ConfigurableClient implements ClientIdentity {
|
||||
public constructor(
|
||||
public readonly id: string,
|
||||
commandName: string,
|
||||
displayName: string,
|
||||
description: string
|
||||
) {
|
||||
this.#commandName = commandName;
|
||||
this.#displayName = displayName;
|
||||
this.#description = description;
|
||||
}
|
||||
|
||||
#commandName: string;
|
||||
public get commandName(): string {
|
||||
return this.#commandName;
|
||||
}
|
||||
|
||||
public set commandName(value: string) {
|
||||
this.#commandName = value;
|
||||
}
|
||||
|
||||
#displayName: string;
|
||||
public get displayName(): string {
|
||||
return this.#displayName;
|
||||
}
|
||||
|
||||
public set displayName(value: string) {
|
||||
this.#displayName = value;
|
||||
}
|
||||
|
||||
#description: string;
|
||||
public get description(): string {
|
||||
return this.#description;
|
||||
}
|
||||
|
||||
public set description(value: string) {
|
||||
this.#description = value;
|
||||
}
|
||||
}
|
|
@ -1,217 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { PromiseCommandResponse, VoidCommandResponse } from "../../contracts/CommandRunner";
|
||||
import { IContainersClient, InspectContextsCommandOptions, InspectContextsItem, ListContextItem, ListContextsCommandOptions, RemoveContextsCommandOptions, UseContextCommandOptions } from "../../contracts/ContainerClient";
|
||||
import { asIds } from "../../utils/asIds";
|
||||
import { CommandLineArgs, composeArgs, withArg } from "../../utils/commandLineBuilder";
|
||||
import { DockerClientBase } from "../DockerClientBase/DockerClientBase";
|
||||
import { withDockerJsonFormatArg } from "../DockerClientBase/withDockerJsonFormatArg";
|
||||
import { isDockerContextRecord } from "./DockerContextRecord";
|
||||
import { isDockerInspectContextRecord } from "./DockerInspectContextRecord";
|
||||
|
||||
export class DockerClient extends DockerClientBase implements IContainersClient {
|
||||
/**
|
||||
* The ID of the Docker client
|
||||
*/
|
||||
public static ClientId = 'com.microsoft.visualstudio.containers.docker';
|
||||
|
||||
/**
|
||||
* Constructs a new {@link DockerClient}
|
||||
* @param commandName (Optional, default `docker`) The command that will be run
|
||||
* as the base command. If quoting is necessary, it is the responsibility of the
|
||||
* caller to add.
|
||||
* @param displayName (Optional, default 'Docker') The human-friendly display
|
||||
* name of the client
|
||||
* @param description (Optional, with default) The human-friendly description of
|
||||
* the client
|
||||
*/
|
||||
public constructor(
|
||||
commandName: string = 'docker',
|
||||
displayName: string = 'Docker',
|
||||
description: string = 'Runs container commands using the Docker CLI'
|
||||
) {
|
||||
super(
|
||||
DockerClient.ClientId,
|
||||
commandName,
|
||||
displayName,
|
||||
description
|
||||
);
|
||||
}
|
||||
|
||||
//#region Context Commands
|
||||
|
||||
//#region ListContexts Command
|
||||
|
||||
private getListContextsCommandArgs(options: ListContextsCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withArg('context', 'ls'),
|
||||
withDockerJsonFormatArg,
|
||||
)();
|
||||
}
|
||||
|
||||
private async parseListContextsCommandOutput(
|
||||
output: string,
|
||||
strict: boolean,
|
||||
): Promise<ListContextItem[]> {
|
||||
const contexts = new Array<ListContextItem>();
|
||||
try {
|
||||
// Docker returns JSON per-line output, so we need to split each line
|
||||
// and parse as independent JSON objects
|
||||
output.split('\n').forEach((contextJson) => {
|
||||
try {
|
||||
// Ignore empty lines when parsing
|
||||
if (!contextJson) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rawContext = JSON.parse(contextJson);
|
||||
|
||||
// Validate that the image object matches the expected output
|
||||
// for the list contexts command
|
||||
if (!isDockerContextRecord(rawContext)) {
|
||||
throw new Error('Invalid context JSON');
|
||||
}
|
||||
|
||||
contexts.push({
|
||||
name: rawContext.Name,
|
||||
current: rawContext.Current,
|
||||
description: rawContext.Description,
|
||||
containerEndpoint: rawContext.DockerEndpoint,
|
||||
});
|
||||
} catch (err) {
|
||||
if (strict) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
if (strict) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return contexts;
|
||||
}
|
||||
|
||||
override async listContexts(options: ListContextsCommandOptions): Promise<PromiseCommandResponse<ListContextItem[]>> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getListContextsCommandArgs(options),
|
||||
parse: this.parseListContextsCommandOutput,
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region RemoveContexts Command
|
||||
|
||||
private getRemoveContextsCommandArgs(options: RemoveContextsCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withArg('context', 'rm'),
|
||||
withArg(...options.contexts),
|
||||
withArg('--force'),
|
||||
)();
|
||||
}
|
||||
|
||||
private async parseRemoveContextsCommandOutput(
|
||||
output: string,
|
||||
strict: boolean,
|
||||
): Promise<string[]> {
|
||||
return asIds(output);
|
||||
}
|
||||
|
||||
override async removeContexts(options: RemoveContextsCommandOptions): Promise<PromiseCommandResponse<string[]>> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getRemoveContextsCommandArgs(options),
|
||||
parse: this.parseRemoveContextsCommandOutput,
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region UseContext Command
|
||||
|
||||
private getUseContextCommandArgs(options: UseContextCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withArg('context', 'use'),
|
||||
withArg(options.context),
|
||||
)();
|
||||
}
|
||||
|
||||
override async useContext(options: UseContextCommandOptions): Promise<VoidCommandResponse> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getUseContextCommandArgs(options),
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region InspectContexts Command
|
||||
|
||||
private getInspectContextsCommandArgs(options: InspectContextsCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withArg('context', 'inspect'),
|
||||
withDockerJsonFormatArg,
|
||||
withArg(...options.contexts),
|
||||
)();
|
||||
}
|
||||
|
||||
private async parseInspectContextsCommandOutput(
|
||||
output: string,
|
||||
strict: boolean,
|
||||
): Promise<InspectContextsItem[]> {
|
||||
try {
|
||||
return output.split('\n').reduce<Array<InspectContextsItem>>((volumes, inspectString) => {
|
||||
if (!inspectString) {
|
||||
return volumes;
|
||||
}
|
||||
|
||||
try {
|
||||
const inspect = JSON.parse(inspectString);
|
||||
|
||||
if (!isDockerInspectContextRecord(inspect)) {
|
||||
throw new Error('Invalid context inspect json');
|
||||
}
|
||||
|
||||
// Return the normalized InspectVolumesItem record
|
||||
const volume: InspectContextsItem = {
|
||||
name: inspect.Name,
|
||||
description: inspect.Metadata?.Description,
|
||||
raw: inspectString,
|
||||
};
|
||||
|
||||
return [...volumes, volume];
|
||||
} catch (err) {
|
||||
if (strict) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return volumes;
|
||||
}, new Array<InspectContextsItem>());
|
||||
} catch (err) {
|
||||
if (strict) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return new Array<InspectContextsItem>();
|
||||
}
|
||||
|
||||
override async inspectContexts(options: InspectContextsCommandOptions): Promise<PromiseCommandResponse<InspectContextsItem[]>> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getInspectContextsCommandArgs(options),
|
||||
parse: this.parseInspectContextsCommandOutput,
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#endregion
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export type DockerContextRecord = {
|
||||
Name: string;
|
||||
Current: boolean;
|
||||
Description?: string;
|
||||
DockerEndpoint?: string;
|
||||
};
|
||||
|
||||
export function isDockerContextRecord(maybeContext: unknown): maybeContext is DockerContextRecord {
|
||||
const context = maybeContext as DockerContextRecord;
|
||||
|
||||
if (!context || typeof context !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof context.Name !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof context.Current !== 'boolean') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export type DockerInspectContextRecord = {
|
||||
Name: string;
|
||||
Metadata?: {
|
||||
Description?: string;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Actually test properties
|
||||
export function isDockerInspectContextRecord(maybeContext: unknown): maybeContext is DockerInspectContextRecord {
|
||||
return true;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,50 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EventAction, EventType } from "../../contracts/ContainerClient";
|
||||
|
||||
export type DockerEventRecord = {
|
||||
Type: EventType;
|
||||
Action: EventAction;
|
||||
Actor: {
|
||||
ID: string;
|
||||
Attributes: Record<string, unknown>;
|
||||
};
|
||||
time: number;
|
||||
};
|
||||
|
||||
export function isDockerEventRecord(maybeEvent: unknown): maybeEvent is DockerEventRecord {
|
||||
const event = maybeEvent as DockerEventRecord;
|
||||
|
||||
if (!event || typeof event !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof event.Type !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof event.Action !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof event.Actor !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof event.Actor.ID !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof event.Actor.Attributes !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof event.time !== 'number') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ContainerOS, isContainerOS } from "../../contracts/ContainerClient";
|
||||
|
||||
export type DockerInfoRecord = {
|
||||
OperatingSystem?: string;
|
||||
OSType?: ContainerOS;
|
||||
};
|
||||
|
||||
export function isDockerInfoRecord(maybeInfo: unknown): maybeInfo is DockerInfoRecord {
|
||||
const info = maybeInfo as DockerInfoRecord;
|
||||
|
||||
if (typeof info.OSType === 'string' && !isContainerOS(info.OSType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { InspectContainersItem, InspectContainersItemMount, InspectContainersItemNetwork, PortBinding } from '../../contracts/ContainerClient';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
import { toArray } from '../../utils/toArray';
|
||||
import { parseDockerLikeEnvironmentVariables } from './parseDockerLikeEnvironmentVariables';
|
||||
import { parseDockerLikeImageName } from './parseDockerLikeImageName';
|
||||
|
||||
export type DockerInspectContainerPortHost = {
|
||||
HostIp?: string;
|
||||
HostPort?: number;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerBindMount = {
|
||||
Type: 'bind';
|
||||
Source: string;
|
||||
Destination: string;
|
||||
RW: boolean;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerVolumeMount = {
|
||||
Type: 'volume';
|
||||
Name: string;
|
||||
Source: string;
|
||||
Destination: string;
|
||||
Driver: string;
|
||||
RW: boolean;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerMount =
|
||||
| DockerInspectContainerBindMount
|
||||
| DockerInspectContainerVolumeMount;
|
||||
|
||||
export type DockerInspectNetwork = {
|
||||
Gateway: string;
|
||||
IPAddress: string;
|
||||
MacAddress: string;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerConfig = {
|
||||
Image: string;
|
||||
Status: string;
|
||||
Entrypoint: Array<string> | string | null;
|
||||
Cmd: Array<string> | string | null;
|
||||
Env?: Array<string> | null;
|
||||
Labels?: Record<string, string> | null;
|
||||
WorkingDir?: string | null;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerHostConfig = {
|
||||
PublishAllPorts?: boolean | null;
|
||||
Isolation?: string | null;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerNetworkSettings = {
|
||||
Networks?: Record<string, DockerInspectNetwork> | null;
|
||||
IPAddress?: string;
|
||||
Ports?: Record<string, Array<DockerInspectContainerPortHost>> | null;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerState = {
|
||||
Status?: string;
|
||||
StartedAt?: string;
|
||||
FinishedAt?: string;
|
||||
};
|
||||
|
||||
export type DockerInspectContainerRecord = {
|
||||
Id: string;
|
||||
Name: string;
|
||||
Image: string;
|
||||
Platform: string;
|
||||
Created: string;
|
||||
Mounts: Array<DockerInspectContainerMount>;
|
||||
State: DockerInspectContainerState;
|
||||
Config: DockerInspectContainerConfig;
|
||||
HostConfig: DockerInspectContainerHostConfig;
|
||||
NetworkSettings: DockerInspectContainerNetworkSettings;
|
||||
};
|
||||
|
||||
// TODO: Actually test properties
|
||||
export function isDockerInspectContainerRecord(maybeContainer: unknown): maybeContainer is DockerInspectContainerRecord {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeDockerInspectContainerRecord(container: DockerInspectContainerRecord): InspectContainersItem {
|
||||
// Parse the environment variables assigned to the container at runtime
|
||||
const environmentVariables = parseDockerLikeEnvironmentVariables(container.Config?.Env || []);
|
||||
|
||||
// Parse the networks assigned to the container and normalize to InspectContainersItemNetwork
|
||||
// records
|
||||
const networks = Object.entries(container.NetworkSettings?.Networks || {}).map<InspectContainersItemNetwork>(([name, dockerNetwork]) => {
|
||||
return {
|
||||
name,
|
||||
gateway: dockerNetwork.Gateway || undefined,
|
||||
ipAddress: dockerNetwork.IPAddress || undefined,
|
||||
macAddress: dockerNetwork.MacAddress || undefined,
|
||||
};
|
||||
});
|
||||
|
||||
// Parse the exposed ports for the container and normalize to a PortBinding record
|
||||
const ports = Object.entries(container.NetworkSettings?.Ports || {}).map<PortBinding>(([rawPort, hostBinding]) => {
|
||||
const [port, protocol] = rawPort.split('/');
|
||||
return {
|
||||
hostIp: hostBinding?.[0]?.HostIp,
|
||||
hostPort: hostBinding?.[0]?.HostPort,
|
||||
containerPort: parseInt(port),
|
||||
protocol: protocol.toLowerCase() === 'tcp'
|
||||
? 'tcp'
|
||||
: protocol.toLowerCase() === 'udp'
|
||||
? 'udp'
|
||||
: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
// Parse the volume and bind mounts associated with the given runtime and normalize to
|
||||
// InspectContainersItemMount records
|
||||
const mounts = (container.Mounts || []).reduce<Array<InspectContainersItemMount>>((curMounts, mount) => {
|
||||
switch (mount?.Type) {
|
||||
case 'bind':
|
||||
return [...curMounts, {
|
||||
type: 'bind',
|
||||
source: mount.Source,
|
||||
destination: mount.Destination,
|
||||
readOnly: !mount.RW,
|
||||
}];
|
||||
case 'volume':
|
||||
return [...curMounts, {
|
||||
type: 'volume',
|
||||
name: mount.Name,
|
||||
source: mount.Source,
|
||||
destination: mount.Destination,
|
||||
driver: mount.Driver,
|
||||
readOnly: !mount.RW,
|
||||
}];
|
||||
}
|
||||
|
||||
}, new Array<InspectContainersItemMount>());
|
||||
const labels = container.Config?.Labels ?? {};
|
||||
|
||||
const createdAt = dayjs.utc(container.Created);
|
||||
const startedAt = container.State?.StartedAt
|
||||
? dayjs.utc(container.State?.StartedAt)
|
||||
: undefined;
|
||||
const finishedAt = container.State?.FinishedAt
|
||||
? dayjs.utc(container.State?.FinishedAt)
|
||||
: undefined;
|
||||
|
||||
// Return the normalized InspectContainersItem record
|
||||
return {
|
||||
id: container.Id,
|
||||
name: container.Name,
|
||||
imageId: container.Image,
|
||||
image: parseDockerLikeImageName(container.Config.Image),
|
||||
isolation: container.HostConfig?.Isolation,
|
||||
status: container.State?.Status,
|
||||
environmentVariables,
|
||||
networks,
|
||||
ipAddress: container.NetworkSettings?.IPAddress ? container.NetworkSettings?.IPAddress : undefined,
|
||||
ports,
|
||||
mounts,
|
||||
labels,
|
||||
entrypoint: toArray(container.Config?.Entrypoint ?? []),
|
||||
command: toArray(container.Config?.Cmd ?? []),
|
||||
currentDirectory: container.Config?.WorkingDir || undefined,
|
||||
createdAt: createdAt.toDate(),
|
||||
startedAt: startedAt && (startedAt.isSame(createdAt) || startedAt.isAfter(createdAt))
|
||||
? startedAt.toDate()
|
||||
: undefined,
|
||||
finishedAt: finishedAt && (finishedAt.isSame(createdAt) || finishedAt.isAfter(createdAt))
|
||||
? finishedAt.toDate()
|
||||
: undefined,
|
||||
raw: JSON.stringify(container),
|
||||
};
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ImageNameInfo, InspectImagesItem, PortBinding } from "../../contracts/ContainerClient";
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
import { toArray } from "../../utils/toArray";
|
||||
import { parseDockerLikeEnvironmentVariables } from "./parseDockerLikeEnvironmentVariables";
|
||||
import { parseDockerLikeImageName } from "./parseDockerLikeImageName";
|
||||
|
||||
export type DockerInspectImageConfig = {
|
||||
Entrypoint?: Array<string> | string | null;
|
||||
Cmd?: Array<string> | string | null;
|
||||
Env?: Array<string>,
|
||||
Labels?: Record<string, string> | null,
|
||||
ExposedPorts?: Record<string, unknown> | null;
|
||||
Volumes?: Record<string, unknown> | null;
|
||||
WorkingDir?: string | null;
|
||||
User?: string | null;
|
||||
};
|
||||
|
||||
export type DockerInspectImageRecord = {
|
||||
Id: string;
|
||||
RepoTags: Array<string>;
|
||||
Config: DockerInspectImageConfig,
|
||||
RepoDigests: Array<string>;
|
||||
Architecture: string;
|
||||
Os: string;
|
||||
Created: string;
|
||||
User?: string;
|
||||
};
|
||||
|
||||
function isDockerInspectImageConfig(maybeImageConfig: unknown): maybeImageConfig is DockerInspectImageConfig {
|
||||
const imageConfig = maybeImageConfig as DockerInspectImageConfig;
|
||||
|
||||
if (!imageConfig || typeof imageConfig !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.Env && !Array.isArray(imageConfig.Env)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.Labels && typeof imageConfig.Labels !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.ExposedPorts && typeof imageConfig.ExposedPorts !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.Volumes && typeof imageConfig.Volumes !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.WorkingDir && typeof imageConfig.WorkingDir !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.User && typeof imageConfig.User !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.Entrypoint && !Array.isArray(imageConfig.Entrypoint) && typeof imageConfig.Entrypoint !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageConfig.Cmd && !Array.isArray(imageConfig.Cmd) && typeof imageConfig.Cmd !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function isDockerInspectImageRecord(maybeImage: unknown): maybeImage is DockerInspectImageRecord {
|
||||
const image = maybeImage as DockerInspectImageRecord;
|
||||
|
||||
if (!image || typeof image !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.Id !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Array.isArray(image.RepoTags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDockerInspectImageConfig(image.Config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Array.isArray(image.RepoDigests)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.Architecture !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.Os !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.Created !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeDockerInspectImageRecord(image: DockerInspectImageRecord): InspectImagesItem {
|
||||
// This is effectively doing firstOrDefault on the RepoTags for the image. If there are any values
|
||||
// in RepoTags, the first one will be parsed and returned as the tag name for the image.
|
||||
const imageNameInfo: ImageNameInfo = parseDockerLikeImageName(image.RepoTags?.[0]);
|
||||
|
||||
// Parse any environment variables defined for the image
|
||||
const environmentVariables = parseDockerLikeEnvironmentVariables(image.Config?.Env || []);
|
||||
|
||||
// Parse any default ports exposed by the image
|
||||
const ports = Object.entries(image.Config?.ExposedPorts || {}).map<PortBinding>(([rawPort]) => {
|
||||
const [port, protocol] = rawPort.split('/');
|
||||
return {
|
||||
containerPort: parseInt(port),
|
||||
protocol: protocol.toLowerCase() === 'tcp' ? 'tcp' : protocol.toLowerCase() === 'udp' ? 'udp' : undefined,
|
||||
};
|
||||
});
|
||||
|
||||
// Parse any default volumes specified by the image
|
||||
const volumes = Object.entries(image.Config?.Volumes || {}).map<string>(([rawVolume]) => rawVolume);
|
||||
|
||||
// Parse any labels assigned to the image
|
||||
const labels = image.Config?.Labels ?? {};
|
||||
|
||||
// Parse and normalize the image architecture
|
||||
const architecture = image.Architecture?.toLowerCase() === 'amd64'
|
||||
? 'amd64'
|
||||
: image.Architecture?.toLowerCase() === 'arm64' ? 'arm64' : undefined;
|
||||
|
||||
// Parse and normalize the image OS
|
||||
const os = image.Os?.toLowerCase() === 'linux'
|
||||
? 'linux'
|
||||
: image.Architecture?.toLowerCase() === 'windows'
|
||||
? 'windows'
|
||||
: undefined;
|
||||
|
||||
// Determine if the image has been pushed to a remote repo
|
||||
// (no repo digests or only localhost/ repo digests)
|
||||
const isLocalImage = !(image.RepoDigests || []).some((digest) => !digest.toLowerCase().startsWith('localhost/'));
|
||||
|
||||
return {
|
||||
id: image.Id,
|
||||
image: imageNameInfo,
|
||||
repoDigests: image.RepoDigests,
|
||||
isLocalImage,
|
||||
environmentVariables,
|
||||
ports,
|
||||
volumes,
|
||||
labels,
|
||||
entrypoint: toArray(image.Config?.Entrypoint || []),
|
||||
command: toArray(image.Config?.Cmd || []),
|
||||
currentDirectory: image.Config?.WorkingDir || undefined,
|
||||
architecture,
|
||||
operatingSystem: os,
|
||||
createdAt: dayjs(image.Created).toDate(),
|
||||
user: image.Config?.User || undefined,
|
||||
raw: JSON.stringify(image),
|
||||
};
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { InspectNetworksItem, NetworkIpamConfig } from '../../contracts/ContainerClient';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
|
||||
export type DockerIpamConfig = {
|
||||
Subnet: string;
|
||||
Gateway: string;
|
||||
};
|
||||
|
||||
export type DockerIpam = {
|
||||
Driver: string;
|
||||
Config: Array<DockerIpamConfig>;
|
||||
};
|
||||
|
||||
export type DockerInspectNetworkRecord = {
|
||||
Id: string;
|
||||
Name: string;
|
||||
Driver: string;
|
||||
Scope: string;
|
||||
Labels: Record<string, string>;
|
||||
IPAM: DockerIpam;
|
||||
EnableIPv6: boolean;
|
||||
Internal: boolean;
|
||||
Attachable: boolean;
|
||||
Ingress: boolean;
|
||||
Created: string;
|
||||
};
|
||||
|
||||
export function isDockerInspectNetworkRecord(maybeNetwork: unknown): maybeNetwork is DockerInspectNetworkRecord {
|
||||
const network = maybeNetwork as DockerInspectNetworkRecord;
|
||||
|
||||
if (!network || typeof network !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Id !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Name !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Scope !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Labels !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (network.IPAM === null || typeof network.IPAM !== 'object' || typeof network.IPAM.Driver !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.EnableIPv6 !== 'boolean') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Internal !== 'boolean') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Attachable !== 'boolean') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Ingress !== 'boolean') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Created !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeDockerInspectNetworkRecord(network: DockerInspectNetworkRecord): InspectNetworksItem {
|
||||
const ipam: NetworkIpamConfig = {
|
||||
driver: network.IPAM.Driver,
|
||||
config: network.IPAM.Config.map(({ Subnet, Gateway }) => ({
|
||||
subnet: Subnet,
|
||||
gateway: Gateway,
|
||||
})),
|
||||
};
|
||||
|
||||
const createdAt = dayjs.utc(network.Created).toDate();
|
||||
|
||||
// Return the normalized InspectNetworksItem record
|
||||
return {
|
||||
id: network.Id,
|
||||
name: network.Name,
|
||||
driver: network.Driver,
|
||||
scope: network.Scope,
|
||||
labels: network.Labels || {},
|
||||
ipam,
|
||||
ipv6: network.EnableIPv6,
|
||||
internal: network.Internal,
|
||||
attachable: network.Attachable,
|
||||
ingress: network.Ingress,
|
||||
createdAt,
|
||||
raw: JSON.stringify(network),
|
||||
};
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { InspectVolumesItem } from '../../contracts/ContainerClient';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
|
||||
export type DockerInspectVolumeRecord = {
|
||||
Name: string;
|
||||
Driver: string;
|
||||
Mountpoint: string;
|
||||
Scope: string;
|
||||
Labels: Record<string, string>;
|
||||
Options: Record<string, unknown>;
|
||||
CreatedAt: string;
|
||||
};
|
||||
|
||||
// TODO: Actually test properties
|
||||
export function isDockerInspectVolumeRecord(maybeVolume: unknown): maybeVolume is DockerInspectVolumeRecord {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeDockerInspectVolumeRecord(volume: DockerInspectVolumeRecord): InspectVolumesItem {
|
||||
const createdAt = dayjs.utc(volume.CreatedAt);
|
||||
|
||||
// Return the normalized InspectVolumesItem record
|
||||
return {
|
||||
name: volume.Name,
|
||||
driver: volume.Driver,
|
||||
mountpoint: volume.Mountpoint,
|
||||
scope: volume.Scope,
|
||||
labels: volume.Labels,
|
||||
options: volume.Options,
|
||||
createdAt: createdAt.toDate(),
|
||||
raw: JSON.stringify(volume),
|
||||
};
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ListContainersItem, PortBinding } from "../../contracts/ContainerClient";
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
import { parseDockerLikeImageName } from "./parseDockerLikeImageName";
|
||||
import { parseDockerLikeLabels } from "./parseDockerLikeLabels";
|
||||
import { parseDockerRawPortString } from "./parseDockerRawPortString";
|
||||
|
||||
export type DockerListContainerRecord = {
|
||||
ID: string;
|
||||
Names: string;
|
||||
Image: string;
|
||||
Ports: string;
|
||||
Networks: string;
|
||||
Labels: string;
|
||||
CreatedAt: string;
|
||||
State?: string;
|
||||
Status: string;
|
||||
};
|
||||
|
||||
export function isDockerListContainerRecord(maybeContainer: unknown): maybeContainer is DockerListContainerRecord {
|
||||
const container = maybeContainer as DockerListContainerRecord;
|
||||
|
||||
if (!container || typeof container !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.ID !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.Names !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.Image !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.Ports !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.Networks !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.Labels !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.CreatedAt !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof container.Status !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeDockerListContainerRecord(container: DockerListContainerRecord, strict: boolean): ListContainersItem {
|
||||
const labels = parseDockerLikeLabels(container.Labels);
|
||||
|
||||
const ports = container.Ports
|
||||
.split(',')
|
||||
.map((port) => port.trim())
|
||||
.filter((port) => !!port)
|
||||
.reduce<Array<PortBinding>>((portBindings, rawPort) => {
|
||||
const parsedPort = parseDockerRawPortString(rawPort);
|
||||
if (parsedPort) {
|
||||
return portBindings.concat(parsedPort);
|
||||
} else if (strict) {
|
||||
throw new Error('Invalid container JSON');
|
||||
} else {
|
||||
return portBindings;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const networks = container.Networks
|
||||
.split(',');
|
||||
|
||||
const name = container.Names.split(',')[0].trim();
|
||||
const createdAt = dayjs.utc(container.CreatedAt).toDate();
|
||||
|
||||
return {
|
||||
id: container.ID,
|
||||
name,
|
||||
labels,
|
||||
image: parseDockerLikeImageName(container.Image),
|
||||
ports,
|
||||
networks,
|
||||
createdAt,
|
||||
state: normalizeContainerState(container),
|
||||
status: container.Status,
|
||||
};
|
||||
}
|
||||
|
||||
// Exported just for tests, also why the typing is just a subset of the full record
|
||||
export function normalizeContainerState(container: Pick<DockerListContainerRecord, 'State' | 'Status'>): string {
|
||||
if (container.State) {
|
||||
return container.State;
|
||||
}
|
||||
|
||||
if (/paused/i.test(container.Status)) {
|
||||
return 'paused';
|
||||
} else if (/exit|terminate|dead/i.test(container.Status)) {
|
||||
return 'exited';
|
||||
} else if (/created/i.test(container.Status)) {
|
||||
return 'created';
|
||||
} else if (/up/i.test(container.Status)) {
|
||||
return 'running';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ListImagesItem } from '../../contracts/ContainerClient';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
import { parseDockerLikeImageName } from './parseDockerLikeImageName';
|
||||
import { tryParseSize } from './tryParseSize';
|
||||
|
||||
export type DockerListImageRecord = {
|
||||
ID: string;
|
||||
Repository: string;
|
||||
Tag: string;
|
||||
CreatedAt: string;
|
||||
Size: string | number;
|
||||
};
|
||||
|
||||
export function isDockerListImageRecord(maybeImage: unknown): maybeImage is DockerListImageRecord {
|
||||
const image = maybeImage as DockerListImageRecord;
|
||||
|
||||
if (!image || typeof image !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.ID !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.Repository !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.Tag !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.CreatedAt !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof image.Size !== 'string' && typeof image.Size !== 'number') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeDockerListImageRecord(image: DockerListImageRecord): ListImagesItem {
|
||||
const createdAt = dayjs.utc(image.CreatedAt).toDate();
|
||||
const size = tryParseSize(image.Size);
|
||||
|
||||
const repositoryAndTag = `${image.Repository}${image.Tag ? `:${image.Tag}` : ''}`;
|
||||
|
||||
return {
|
||||
id: image.ID,
|
||||
image: parseDockerLikeImageName(repositoryAndTag),
|
||||
// labels: {}, // TODO: image labels are conspicuously absent from Docker image listing output
|
||||
createdAt,
|
||||
size,
|
||||
};
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ListNetworkItem } from '../../contracts/ContainerClient';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
import { parseDockerLikeLabels } from './parseDockerLikeLabels';
|
||||
|
||||
export type DockerListNetworkRecord = {
|
||||
ID: string;
|
||||
Name: string;
|
||||
Driver: string;
|
||||
Labels: string;
|
||||
Scope: string;
|
||||
IPv6: string;
|
||||
CreatedAt: string;
|
||||
Internal: string;
|
||||
};
|
||||
|
||||
export function isDockerListNetworkRecord(maybeNetwork: unknown): maybeNetwork is DockerListNetworkRecord {
|
||||
const network = maybeNetwork as DockerListNetworkRecord;
|
||||
|
||||
if (!network || typeof network !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.ID !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Name !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Driver !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Labels !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Scope !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.IPv6 !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.CreatedAt !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof network.Internal !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function normalizeDockerListNetworkRecord(network: DockerListNetworkRecord): ListNetworkItem {
|
||||
// Parse the labels assigned to the networks and normalize to key value pairs
|
||||
const labels = parseDockerLikeLabels(network.Labels);
|
||||
|
||||
const createdAt = dayjs.utc(network.CreatedAt).toDate();
|
||||
|
||||
return {
|
||||
id: network.ID,
|
||||
name: network.Name,
|
||||
driver: network.Driver,
|
||||
labels,
|
||||
scope: network.Scope,
|
||||
ipv6: network.IPv6.toLowerCase() === 'true',
|
||||
internal: network.Internal.toLowerCase() === 'true',
|
||||
createdAt,
|
||||
};
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export type DockerVersionRecord = {
|
||||
Client: { ApiVersion: string };
|
||||
Server: { ApiVersion: string };
|
||||
};
|
||||
|
||||
export function isDockerVersionRecord(maybeVersion: unknown): maybeVersion is DockerVersionRecord {
|
||||
const version = maybeVersion as DockerVersionRecord;
|
||||
|
||||
if (typeof version?.Client?.ApiVersion !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof version?.Server?.ApiVersion !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export type DockerVolumeRecord = {
|
||||
Name: string;
|
||||
Driver: string;
|
||||
Labels: string;
|
||||
Mountpoint: string;
|
||||
Scope: string;
|
||||
CreatedAt?: string;
|
||||
Size?: string;
|
||||
};
|
||||
|
||||
export function isDockerVolumeRecord(maybeVolume: unknown): maybeVolume is DockerVolumeRecord {
|
||||
const volume = maybeVolume as DockerVolumeRecord;
|
||||
|
||||
if (!volume || typeof volume !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof volume.Name !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof volume.Driver !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof volume.Labels !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof volume.Mountpoint !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof volume.Scope !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Parse the standard Docker environment variable format into a key value record object
|
||||
* @param environmentVariables A Docker like list of key=value environment variables
|
||||
* @returns An object of key value pairs for the environment variables
|
||||
*/
|
||||
export function parseDockerLikeEnvironmentVariables(environmentVariables: Array<string>): Record<string, string> {
|
||||
return environmentVariables.reduce<Record<string, string>>((evs, ev) => {
|
||||
const index = ev.indexOf('=');
|
||||
if (index > -1) {
|
||||
const name = ev.slice(0, index);
|
||||
const value = ev.slice(index + 1);
|
||||
|
||||
return {
|
||||
...evs,
|
||||
[name]: value,
|
||||
};
|
||||
}
|
||||
|
||||
return evs;
|
||||
}, {});
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ImageNameInfo } from '../../contracts/ContainerClient';
|
||||
|
||||
/**
|
||||
* A regex for parsing image names. Because this is only used to parse CLI output, we can assume
|
||||
* the image names are valid.
|
||||
*
|
||||
* Registry: Everything before the first slash--must be either exactly "localhost", or contain a DNS
|
||||
* separator "." or port separator ":". Port, if present, will also be included. If it does not meet
|
||||
* these rules, it is not the registry but instead part of the image name. See
|
||||
* https://stackoverflow.com/questions/37861791/how-are-docker-image-names-parsed.
|
||||
*
|
||||
* Image name: Everything after the registry (if the registry is valid) until the tag. Otherwise,
|
||||
* everything until the tag.
|
||||
*
|
||||
* Tag: Everything after the ":", if it is present.
|
||||
*/
|
||||
const imageNameRegex = /^((?<registry>((localhost|([\w-]+(\.[\w-]+)+))(:\d+)?)|([\w-]+:\d+))\/)?(?<image>[\w-./<>]+)(:(?<tag>[\w-.<>]+))?(@(?<digest>.+))?$/;
|
||||
|
||||
// In certain cases, Docker makes image/tag names "<none>", which is not really valid. We will reinterpret those as `undefined`.
|
||||
const noneImageName = /[<>]/i;
|
||||
|
||||
/**
|
||||
* Parse an image name and return its components.
|
||||
* @param originalName The original image name
|
||||
* @returns The separated registry, image, and tag, along with the input original name
|
||||
* and a verbose name composed of as much information as possible.
|
||||
*/
|
||||
export function parseDockerLikeImageName(originalName: string | undefined): ImageNameInfo {
|
||||
if (!originalName) {
|
||||
return {
|
||||
originalName,
|
||||
};
|
||||
}
|
||||
|
||||
const match = imageNameRegex.exec(originalName);
|
||||
|
||||
if (!match || !match.groups) {
|
||||
throw new Error('Invalid image name');
|
||||
}
|
||||
|
||||
const { registry, image, tag, digest } = match.groups;
|
||||
|
||||
return {
|
||||
originalName,
|
||||
image: noneImageName.test(image) ? undefined : image,
|
||||
tag: noneImageName.test(tag) ? undefined : tag,
|
||||
digest,
|
||||
registry,
|
||||
};
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Labels } from "../../contracts/ContainerClient";
|
||||
|
||||
/**
|
||||
* Parse Docker-like label string
|
||||
* @param rawLabels Comma seperated string of labels
|
||||
* @returns A {@link Labels} record
|
||||
*/
|
||||
export function parseDockerLikeLabels(rawLabels: string): Labels {
|
||||
return rawLabels.split(',').reduce((labels, labelPair) => {
|
||||
const index = labelPair.indexOf('=');
|
||||
labels[labelPair.substring(0, index)] = labelPair.substring(index + 1);
|
||||
return labels;
|
||||
}, {} as Labels);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { PortBinding } from "../../contracts/ContainerClient";
|
||||
|
||||
/**
|
||||
* Attempt to parse a Docker-like raw port binding string
|
||||
* @param portString the raw port string to parse, e.g. "1234/tcp" or "0.0.0.0:1234->1234/udp"
|
||||
* @returns Parsed raw port string as a PortBinding record or undefined if invalid
|
||||
*/
|
||||
export function parseDockerRawPortString(portString: string): PortBinding | undefined {
|
||||
const portRegex = /((?<hostIp>[\da-f.:[\]]+)(:(?<hostPort>\d+)))?(\s*->\s*)?((?<containerPort>\d+)\/(?<protocol>tcp|udp))/i;
|
||||
const result = portRegex.exec(portString);
|
||||
|
||||
if (!result || !result.groups) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const hostIp = result.groups['hostIp'] || undefined;
|
||||
const hostPort = result.groups['hostPort'] ? Number.parseInt(result.groups['hostPort']) : undefined;
|
||||
const containerPort = result.groups['containerPort'] ? Number.parseInt(result.groups['containerPort']) : undefined;
|
||||
const protocol = result.groups['protocol'] || undefined;
|
||||
|
||||
if (containerPort === undefined || (protocol !== 'tcp' && protocol !== 'udp')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
hostIp,
|
||||
hostPort,
|
||||
containerPort,
|
||||
protocol,
|
||||
};
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { ListFilesCommandOptions, ListFilesItem } from '../../contracts/ContainerClient';
|
||||
import { dayjs } from '../../utils/dayjs';
|
||||
|
||||
const DateFormats = [
|
||||
'MMM D HH:mm', // Linux format
|
||||
'MMM D YYYY', // Linux format for last year
|
||||
'MM/DD/YYYY hh:mm A', // Windows format
|
||||
];
|
||||
|
||||
const SupportedFileTypes = [vscode.FileType.Directory, vscode.FileType.File];
|
||||
|
||||
type FileMode = {
|
||||
mode?: number;
|
||||
fileType: vscode.FileType;
|
||||
};
|
||||
|
||||
export function parseListFilesCommandLinuxOutput(
|
||||
options: ListFilesCommandOptions,
|
||||
output: string
|
||||
): ListFilesItem[] {
|
||||
const regex = /^(?<type>[0-9a-fA-F]+)\s+(?<links>\d+)\s+(?<group>\d+)\s+(?<owner>\d+)\s+(?<size>\d+)\s+(?<atime>\d+)\s+(?<mtime>\d+)\s+(?<ctime>\d+)\s+(?<name>.*)$/gm;
|
||||
|
||||
const items = new Array<ListFilesItem>();
|
||||
for (const match of output.matchAll(regex)) {
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
const name = path.basename(match.groups!.name);
|
||||
const { mode, fileType } = parseLinuxType(match.groups!.type);
|
||||
const size = Number.parseInt(match.groups!.size, 10);
|
||||
const mtime = dayjs.unix(Number.parseInt(match.groups!.mtime, 10)).valueOf();
|
||||
const ctime = dayjs.unix(Number.parseInt(match.groups!.ctime, 10)).valueOf();
|
||||
const atime = dayjs.unix(Number.parseInt(match.groups!.atime, 10)).valueOf();
|
||||
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
// Ignore relative directory items...
|
||||
if (fileType === vscode.FileType.Directory && (name === '.' || name === '..')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore everything other than directories and plain files
|
||||
if (!SupportedFileTypes.includes(fileType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
items.push({
|
||||
name,
|
||||
path: path.posix.join(options.path, name),
|
||||
type: fileType,
|
||||
mode,
|
||||
ctime,
|
||||
mtime,
|
||||
atime,
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
export function parseListFilesCommandWindowsOutput(
|
||||
options: ListFilesCommandOptions,
|
||||
output: string
|
||||
): ListFilesItem[] {
|
||||
const regex = /^(?<mtime>(?<date>\d{1,2}(\/|\.)\d{1,2}(\/|\.)\d{4})\s+(?<time>\d{1,2}:\d{1,2}( (AM|PM))?))\s+((?<type><DIR>|<SYMLINKD>)|(?<size>\d+))\s+(?<name>.*)$/gm;
|
||||
|
||||
const items = new Array<ListFilesItem>();
|
||||
for (const match of output.matchAll(regex)) {
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
const name = match.groups!.name;
|
||||
const fileType = parseWindowsType(match.groups!.type);
|
||||
const size = fileType === vscode.FileType.Directory ? 0 : Number.parseInt(match.groups!.size, 10);
|
||||
const mtime = dayjs(match.groups!.mtime, DateFormats).valueOf();
|
||||
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
// Ignore relative directory items...
|
||||
if (fileType === vscode.FileType.Directory && (name === '.' || name === '..')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore everything other than directories and plain files
|
||||
if (!SupportedFileTypes.includes(fileType)) {
|
||||
return items;
|
||||
}
|
||||
|
||||
items.push({
|
||||
name,
|
||||
path: path.win32.join(options.path, name),
|
||||
type: fileType,
|
||||
mtime,
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function parseLinuxType(fullModeHex: string): FileMode {
|
||||
const fullMode = parseInt(fullModeHex, 16);
|
||||
const fileType = (fullMode & 0xf000) >> 12;
|
||||
const mode = fullMode & 0xfff;
|
||||
switch (fileType) {
|
||||
case 4:
|
||||
return { mode, fileType: vscode.FileType.Directory };
|
||||
case 8:
|
||||
return { mode, fileType: vscode.FileType.File };
|
||||
case 10:
|
||||
return { mode, fileType: vscode.FileType.SymbolicLink };
|
||||
default:
|
||||
return { mode, fileType: vscode.FileType.Unknown };
|
||||
}
|
||||
}
|
||||
|
||||
function parseWindowsType(type: string | undefined): vscode.FileType {
|
||||
switch (type?.toUpperCase()) {
|
||||
case '<DIR>':
|
||||
return vscode.FileType.Directory;
|
||||
case '':
|
||||
case undefined:
|
||||
// Blank or undefined type is a file
|
||||
return vscode.FileType.File;
|
||||
case '<SYMLINKD>':
|
||||
case '<SYMLINK>':
|
||||
return vscode.FileType.SymbolicLink;
|
||||
default:
|
||||
return vscode.FileType.Unknown;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Tries to parse a size (in many forms) into a value in bytes
|
||||
* @param value The value to try to parse into a size
|
||||
* @returns An integer value in bytes, if the input can be parsed, otherwise undefined
|
||||
*/
|
||||
export function tryParseSize(value: string | number | undefined | null): number | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
} else if (typeof value === 'number') {
|
||||
return Math.round(value);
|
||||
} else {
|
||||
if (value.toLowerCase() === 'n/a') {
|
||||
return undefined;
|
||||
} else {
|
||||
// Parses values like "1234", "1234b", "1234kb", "1234 MB", "12.34 GB" etc. into size (the numerical part)
|
||||
// and sizeUnit (the kb/mb/gb, if present)
|
||||
const result = /(?<size>\d+(\.\d+)?)\s*(?<sizeUnit>[kmg]?b)?/i.exec(value);
|
||||
|
||||
if (result?.groups?.size) {
|
||||
const size: number = Number.parseFloat(result.groups.size);
|
||||
const unit: string | undefined = result.groups.sizeUnit;
|
||||
|
||||
switch (unit?.toLowerCase()) {
|
||||
case 'kb':
|
||||
return Math.round(size * 1024);
|
||||
case 'mb':
|
||||
return Math.round(size * 1024 * 1024);
|
||||
case 'gb':
|
||||
return Math.round(size * 1024 * 1024 * 1024);
|
||||
default:
|
||||
return Math.round(size);
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ReadFileCommandOptions, WriteFileCommandOptions } from "../../contracts/ContainerClient";
|
||||
import { CommandLineCurryFn, withArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function withContainerPathArg(options: ReadFileCommandOptions | WriteFileCommandOptions): CommandLineCurryFn {
|
||||
return withArg(`${options.container}:${options.path}`);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunContainerExtraHost } from "../../contracts/ContainerClient";
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function formatAddHost(addHost: RunContainerExtraHost): string {
|
||||
return `${addHost.hostname}:${addHost.ip}`;
|
||||
}
|
||||
|
||||
export function withDockerAddHostArg(addHosts?: Array<RunContainerExtraHost>) {
|
||||
return withNamedArg('--add-host', (addHosts || []).map(formatAddHost));
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function withDockerBuildArg(buildArgs?: Record<string, string>) {
|
||||
return withNamedArg('--build-arg', Object.entries(buildArgs || {}).map(([key, value]) => `${key}=${value}`));
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function withDockerEnvArg(env?: Record<string, string>) {
|
||||
return withNamedArg('--env', Object.entries(env || {}).map(([key, value]) => `${key}=${value}`));
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function withDockerExposePortsArg(ports?: Array<number>) {
|
||||
return withNamedArg('--expose', (ports || []).map(port => port.toString()), { shouldQuote: false });
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ShellQuotedString } from 'vscode';
|
||||
import { CommandLineCurryFn, withNamedArg } from '../../utils/commandLineBuilder';
|
||||
|
||||
export function withDockerFilterArg(filter: string | ShellQuotedString | (string | ShellQuotedString | null | undefined)[] | null | undefined): CommandLineCurryFn {
|
||||
return withNamedArg('--filter', filter);
|
||||
}
|
||||
|
||||
export function withDockerBooleanFilterArg(filter: string, value: boolean | null | undefined): CommandLineCurryFn {
|
||||
return withDockerFilterArg(typeof value === 'boolean' ? `${filter}=${value}` : undefined);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { withNamedArg } from '../../utils/commandLineBuilder';
|
||||
|
||||
export const withDockerIgnoreSizeArg = withNamedArg('--size','false', { assignValue: true, shouldQuote: false });
|
|
@ -1,8 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { withNamedArg } from '../../utils/commandLineBuilder';
|
||||
|
||||
export const withDockerJsonFormatArg = withNamedArg('--format', '{{json .}}');
|
|
@ -1,24 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { LabelFilters } from "../../contracts/ContainerClient";
|
||||
import { conditional } from "../../utils/conditional";
|
||||
import { withDockerFilterArg } from "./withDockerFilterArg";
|
||||
|
||||
export function formatDockerLabelFilter(name: string, value: boolean | string): string | undefined {
|
||||
if (typeof value === 'boolean' && value) {
|
||||
return `label=${name}`;
|
||||
} else if (typeof value === 'string') {
|
||||
return conditional`label=${name}=${value}`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function withDockerLabelFilterArgs(labels?: LabelFilters) {
|
||||
return withDockerFilterArg(
|
||||
Object.entries(labels || {}).map(([label, value]) => formatDockerLabelFilter(label, value)),
|
||||
);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Labels } from "../../contracts/ContainerClient";
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function withDockerLabelsArg(labels?: Labels) {
|
||||
return withNamedArg(
|
||||
'--label',
|
||||
Object.entries(labels || {}).map(([label, value]) => `${label}=${value}`),
|
||||
);
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunContainerMount } from "../../contracts/ContainerClient";
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function formatDockerMount(mount: RunContainerMount): string {
|
||||
const mountParts = new Array<string>(
|
||||
`type=${mount.type}`,
|
||||
`source=${mount.source}`,
|
||||
`destination=${mount.destination}`,
|
||||
mount.readOnly ? 'readonly' : '',
|
||||
);
|
||||
|
||||
return mountParts.filter((part) => !!part).join(',');
|
||||
}
|
||||
|
||||
export function withDockerMountsArg(mounts?: Array<RunContainerMount>) {
|
||||
return withNamedArg('--mount', (mounts || []).map(formatDockerMount));
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { withArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export const withDockerNoTruncArg = withArg('--no-trunc');
|
|
@ -1,36 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ContainerPlatform } from "../../contracts/ContainerClient";
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
import { getNativeArchitecture } from "../../utils/getNativeArchitecture";
|
||||
import { normalizeContainerOS } from "../../utils/normalizeContainerOS";
|
||||
|
||||
export function formatDockerPlatform(platform: ContainerPlatform): string | undefined {
|
||||
if (!platform?.os && !platform?.architecture) {
|
||||
return undefined;
|
||||
}
|
||||
const os = normalizeContainerOS(platform?.os);
|
||||
const architecture = platform?.architecture || getNativeArchitecture();
|
||||
|
||||
return `${os}/${architecture}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method formats the `platform` flag for the Docker CLI.
|
||||
*
|
||||
* The `os` and `architecture` properties are extracted and used to create a new `ContainerPlatform`
|
||||
* object. If either property is missing, a default value ofp `'linux'` for `os` or the result of
|
||||
* `getNativeArchitecture()` for `architecture` is used.
|
||||
*
|
||||
* If an empty object is passed in, `undefined` is returned, which will allow the Docker CLI to
|
||||
* skip the `--platform` flag entirely and use the default platform.
|
||||
*
|
||||
* @param platform
|
||||
* @returns
|
||||
*/
|
||||
export function withDockerPlatformArg(platform: ContainerPlatform) {
|
||||
return withNamedArg('--platform', formatDockerPlatform(platform));
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { PortBinding } from "../../contracts/ContainerClient";
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function withDockerPortsArg(ports?: Array<PortBinding>) {
|
||||
return withNamedArg(
|
||||
'--publish',
|
||||
(ports || []).map((port) => {
|
||||
let binding = port.hostIp ? `${port.hostIp}:` : '';
|
||||
binding += `${port.hostPort || ''}:`;
|
||||
binding += port.containerPort;
|
||||
if (port.protocol) {
|
||||
binding += `/${port.protocol}`;
|
||||
}
|
||||
return binding;
|
||||
}),
|
||||
);
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { GeneratorCommandResponse, PromiseCommandResponse, VoidCommandResponse } from '../../contracts/CommandRunner';
|
||||
import {
|
||||
CommonOrchestratorCommandOptions,
|
||||
ConfigCommandOptions,
|
||||
ConfigItem,
|
||||
DownCommandOptions,
|
||||
IContainerOrchestratorClient,
|
||||
LogsCommandOptions,
|
||||
RestartCommandOptions,
|
||||
StartCommandOptions,
|
||||
StopCommandOptions,
|
||||
UpCommandOptions,
|
||||
} from '../../contracts/ContainerOrchestratorClient';
|
||||
import {
|
||||
CommandLineArgs,
|
||||
CommandLineCurryFn,
|
||||
composeArgs,
|
||||
withArg,
|
||||
withFlagArg,
|
||||
withNamedArg,
|
||||
withVerbatimArg,
|
||||
} from '../../utils/commandLineBuilder';
|
||||
import { stringStreamToGenerator } from '../../utils/streamToGenerator';
|
||||
import { ConfigurableClient } from '../ConfigurableClient';
|
||||
|
||||
function withCommonOrchestratorArgs(options: CommonOrchestratorCommandOptions): CommandLineCurryFn {
|
||||
return composeArgs(
|
||||
withNamedArg('--file', options.files),
|
||||
withNamedArg('--env-file', options.environmentFile),
|
||||
withNamedArg('--project-name', options.projectName),
|
||||
);
|
||||
}
|
||||
|
||||
function withComposeArg(composeV2: boolean): CommandLineCurryFn {
|
||||
// If using Compose V2, then add the `compose` argument at the beginning
|
||||
// That way, the command is `docker compose` instead of `docker-compose`
|
||||
return withArg(composeV2 ? 'compose' : undefined);
|
||||
}
|
||||
|
||||
export class DockerComposeClient extends ConfigurableClient implements IContainerOrchestratorClient {
|
||||
/**
|
||||
* The ID of the Docker Compose client
|
||||
*/
|
||||
public static ClientId = 'com.microsoft.visualstudio.orchestrators.dockercompose';
|
||||
|
||||
/**
|
||||
* Constructs a new {@link DockerComposeClient}
|
||||
* @param commandName (Optional, default `docker`) The command that will be run
|
||||
* as the base command. If quoting is necessary, it is the responsibility of the
|
||||
* caller to add.
|
||||
* @param displayName (Optional, default 'Docker Compose') The human-friendly display
|
||||
* name of the client
|
||||
* @param description (Optional, with default) The human-friendly description of
|
||||
* the client
|
||||
* @param composeV2 (Optional, default `true`) If true, `compose` will be added as the
|
||||
* first argument to all commands. The base command should be `docker`.
|
||||
*/
|
||||
public constructor(
|
||||
commandName?: string,
|
||||
displayName: string = 'Docker Compose',
|
||||
description: string = 'Runs orchestrator commands using the Docker Compose CLI',
|
||||
composeV2: boolean = true
|
||||
) {
|
||||
super(
|
||||
DockerComposeClient.ClientId,
|
||||
commandName || composeV2 ? 'docker' : 'docker-compose',
|
||||
displayName,
|
||||
description
|
||||
);
|
||||
this.#composeV2 = composeV2;
|
||||
}
|
||||
|
||||
#composeV2: boolean;
|
||||
public get composeV2(): boolean {
|
||||
return this.#composeV2;
|
||||
}
|
||||
|
||||
public set composeV2(value: boolean) {
|
||||
this.#composeV2 = value;
|
||||
}
|
||||
|
||||
//#region Up command
|
||||
|
||||
protected getUpCommandArgs(options: UpCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withComposeArg(this.composeV2),
|
||||
withCommonOrchestratorArgs(options),
|
||||
withNamedArg('--profile', options.profiles),
|
||||
withArg('up'),
|
||||
withFlagArg('--detach', options.detached),
|
||||
withFlagArg('--build', options.build),
|
||||
withNamedArg('--scale', Object.entries(options.scale || {}).map(([service, scale]) => `${service}=${scale}`)),
|
||||
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
|
||||
withFlagArg('--wait', options.wait),
|
||||
withVerbatimArg(options.customOptions),
|
||||
withArg(...(options.services || [])),
|
||||
)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the necessary information for running of an orchestrator up command for Docker Compose
|
||||
* @param options Standard orchestrator up command options
|
||||
* @returns A CommandResponse indicating how to run an orchestrator up command for Docker Compose
|
||||
*/
|
||||
public async up(options: UpCommandOptions): Promise<VoidCommandResponse> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getUpCommandArgs(options),
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion Up command
|
||||
|
||||
//#region Down command
|
||||
|
||||
protected getDownCommandArgs(options: DownCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withComposeArg(this.composeV2),
|
||||
withCommonOrchestratorArgs(options),
|
||||
withArg('down'),
|
||||
withNamedArg('--rmi', options.removeImages),
|
||||
withFlagArg('--volumes', options.removeVolumes),
|
||||
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
|
||||
withVerbatimArg(options.customOptions),
|
||||
)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the necessary information for running of an orchestrator down command for Docker Compose
|
||||
* @param options Standard orchestrator down command options
|
||||
* @returns A CommandResponse indicating how to run an orchestrator down command for Docker Compose
|
||||
*/
|
||||
public async down(options: DownCommandOptions): Promise<VoidCommandResponse> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getDownCommandArgs(options),
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion Down command
|
||||
|
||||
//#region Start command
|
||||
|
||||
protected getStartCommandArgs(options: StartCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withComposeArg(this.composeV2),
|
||||
withCommonOrchestratorArgs(options),
|
||||
withArg('start'),
|
||||
)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the necessary information for running of an orchestrator start command for Docker Compose
|
||||
* @param options Standard orchestrator start command options
|
||||
* @returns A CommandResponse indicating how to run an orchestrator start command for Docker Compose
|
||||
*/
|
||||
public async start(options: StartCommandOptions): Promise<VoidCommandResponse> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getStartCommandArgs(options),
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion Start command
|
||||
|
||||
//#region Stop command
|
||||
|
||||
protected getStopCommandArgs(options: StopCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withComposeArg(this.composeV2),
|
||||
withCommonOrchestratorArgs(options),
|
||||
withArg('stop'),
|
||||
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
|
||||
)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the necessary information for running of an orchestrator stop command for Docker Compose
|
||||
* @param options Standard orchestrator stop command options
|
||||
* @returns A CommandResponse indicating how to run an orchestrator stop command for Docker Compose
|
||||
*/
|
||||
public async stop(options: StopCommandOptions): Promise<VoidCommandResponse> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getStopCommandArgs(options),
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion Stop command
|
||||
|
||||
//#region Restart command
|
||||
|
||||
protected getRestartCommandArgs(options: RestartCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withComposeArg(this.composeV2),
|
||||
withCommonOrchestratorArgs(options),
|
||||
withArg('restart'),
|
||||
withNamedArg('--timeout', options.timeoutSeconds?.toString(10)),
|
||||
)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the necessary information for running of an orchestrator restart command for Docker Compose
|
||||
* @param options Standard orchestrator restart command options
|
||||
* @returns A CommandResponse indicating how to run an orchestrator restart command for Docker Compose
|
||||
*/
|
||||
public async restart(options: RestartCommandOptions): Promise<VoidCommandResponse> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getRestartCommandArgs(options),
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion Restart command
|
||||
|
||||
//#region Logs command
|
||||
|
||||
protected getLogsCommandArgs(options: LogsCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withComposeArg(this.composeV2),
|
||||
withCommonOrchestratorArgs(options),
|
||||
withArg('logs'),
|
||||
withFlagArg('--follow', options.follow),
|
||||
withNamedArg('--tail', options.tail?.toString(10)),
|
||||
)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the necessary information for running of an orchestrator logs command for Docker Compose
|
||||
* @param options Standard orchestrator logs command options
|
||||
* @returns A CommandResponse indicating how to run an orchestrator logs command for Docker Compose
|
||||
*/
|
||||
public async logs(options: LogsCommandOptions): Promise<GeneratorCommandResponse<string>> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getLogsCommandArgs(options),
|
||||
parseStream: (output, strict) => stringStreamToGenerator(output),
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion Logs command
|
||||
|
||||
//#region Config command
|
||||
|
||||
protected getConfigCommandArgs(options: ConfigCommandOptions): CommandLineArgs {
|
||||
return composeArgs(
|
||||
withComposeArg(this.composeV2),
|
||||
withCommonOrchestratorArgs(options),
|
||||
withArg('config'),
|
||||
withArg(`--${options.configType}`),
|
||||
)();
|
||||
}
|
||||
|
||||
protected async parseConfigCommandOutput(
|
||||
output: string,
|
||||
strict: boolean,
|
||||
): Promise<Array<ConfigItem>> {
|
||||
return output.split('\n').filter((config) => config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the necessary information for running of an orchestrator config command for Docker Compose
|
||||
* @param options Standard orchestrator config command options
|
||||
* @returns A CommandResponse indicating how to run an orchestrator config command for Docker Compose
|
||||
*/
|
||||
public async config(options: ConfigCommandOptions): Promise<PromiseCommandResponse<Array<ConfigItem>>> {
|
||||
return {
|
||||
command: this.commandName,
|
||||
args: this.getConfigCommandArgs(options),
|
||||
parse: this.parseConfigCommandOutput,
|
||||
};
|
||||
}
|
||||
|
||||
//#endregion Config command
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as stream from 'stream';
|
||||
import {
|
||||
CommandResponseBase,
|
||||
CommandRunner,
|
||||
GeneratorCommandResponse,
|
||||
ICommandRunnerFactory,
|
||||
Like,
|
||||
normalizeCommandResponseLike,
|
||||
PromiseCommandResponse,
|
||||
StreamingCommandRunner,
|
||||
VoidCommandResponse,
|
||||
} from '../contracts/CommandRunner';
|
||||
import { CancellationTokenLike } from '../typings/CancellationTokenLike';
|
||||
import { AccumulatorStream } from '../utils/AccumulatorStream';
|
||||
import { CancellationError } from '../utils/CancellationError';
|
||||
import { CommandLineArgs } from '../utils/commandLineBuilder';
|
||||
import {
|
||||
spawnStreamAsync,
|
||||
StreamSpawnOptions,
|
||||
} from '../utils/spawnStreamAsync';
|
||||
|
||||
export type ShellStreamCommandRunnerOptions = StreamSpawnOptions & {
|
||||
strict?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* A {@link CommandRunnerFactory} that executes commands on a given shell and
|
||||
* manages access to the necessary stdio streams
|
||||
*/
|
||||
export class ShellStreamCommandRunnerFactory<TOptions extends ShellStreamCommandRunnerOptions> implements ICommandRunnerFactory {
|
||||
public constructor(protected readonly options: TOptions) { }
|
||||
|
||||
public getCommandRunner(): CommandRunner {
|
||||
return async <T>(commandResponseLike: Like<VoidCommandResponse> | Like<PromiseCommandResponse<T>>) => {
|
||||
const commandResponse = await normalizeCommandResponseLike(commandResponseLike);
|
||||
const { command, args } = this.getCommandAndArgs(commandResponse);
|
||||
|
||||
throwIfCancellationRequested(this.options.cancellationToken);
|
||||
|
||||
let result: T | undefined;
|
||||
|
||||
let accumulator: AccumulatorStream | undefined;
|
||||
|
||||
try {
|
||||
if (commandResponse.parse) {
|
||||
accumulator = new AccumulatorStream();
|
||||
}
|
||||
|
||||
// Determine the appropriate combination of streams that need to read from stdout
|
||||
let stdOutPipe: NodeJS.WritableStream | undefined = accumulator;
|
||||
if (accumulator && this.options.stdOutPipe) {
|
||||
const stdOutPassThrough = new stream.PassThrough();
|
||||
stdOutPassThrough.pipe(this.options.stdOutPipe);
|
||||
stdOutPassThrough.pipe(accumulator);
|
||||
|
||||
stdOutPipe = stdOutPassThrough;
|
||||
} else if (this.options.stdOutPipe) {
|
||||
stdOutPipe = this.options.stdOutPipe;
|
||||
}
|
||||
|
||||
await spawnStreamAsync(command, args, { ...this.options, stdOutPipe: stdOutPipe });
|
||||
|
||||
throwIfCancellationRequested(this.options.cancellationToken);
|
||||
|
||||
if (accumulator && commandResponse.parse) {
|
||||
const output = await accumulator.getString();
|
||||
throwIfCancellationRequested(this.options.cancellationToken);
|
||||
result = await commandResponse.parse(output, !!this.options.strict);
|
||||
}
|
||||
|
||||
throwIfCancellationRequested(this.options.cancellationToken);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return result!;
|
||||
} finally {
|
||||
accumulator?.destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public getStreamingCommandRunner(): StreamingCommandRunner {
|
||||
return this.streamingCommandRunner.bind(this);
|
||||
}
|
||||
|
||||
private async *streamingCommandRunner<T>(commandResponseLike: Like<GeneratorCommandResponse<T>>): AsyncGenerator<T> {
|
||||
const commandResponse = await normalizeCommandResponseLike(commandResponseLike);
|
||||
const { command, args } = this.getCommandAndArgs(commandResponse);
|
||||
|
||||
throwIfCancellationRequested(this.options.cancellationToken);
|
||||
|
||||
const dataStream: stream.PassThrough = new stream.PassThrough();
|
||||
const innerGenerator = commandResponse.parseStream(dataStream, !!this.options.strict);
|
||||
|
||||
// The process promise will be awaited only after the innerGenerator finishes
|
||||
const processPromise = spawnStreamAsync(command, args, { ...this.options, stdOutPipe: dataStream });
|
||||
|
||||
for await (const element of innerGenerator) {
|
||||
yield element;
|
||||
}
|
||||
|
||||
await processPromise;
|
||||
}
|
||||
|
||||
protected getCommandAndArgs(commandResponse: CommandResponseBase): { command: string, args: CommandLineArgs } {
|
||||
return commandResponse;
|
||||
}
|
||||
}
|
||||
|
||||
function throwIfCancellationRequested(token?: CancellationTokenLike): void {
|
||||
if (token?.isCancellationRequested) {
|
||||
throw new CancellationError('Command cancelled', token);
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import {
|
||||
CommandResponseBase,
|
||||
ICommandRunnerFactory,
|
||||
} from '../contracts/CommandRunner';
|
||||
import { CommandLineArgs, composeArgs, withArg, withNamedArg } from '../utils/commandLineBuilder';
|
||||
import {
|
||||
ShellStreamCommandRunnerFactory,
|
||||
ShellStreamCommandRunnerOptions,
|
||||
} from './shellStream';
|
||||
|
||||
export type WslShellCommandRunnerOptions = ShellStreamCommandRunnerOptions & {
|
||||
wslPath?: string;
|
||||
distro?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Special case of {@link ShellStreamCommandRunnerFactory} for executing commands in a wsl distro
|
||||
*/
|
||||
export class WslShellCommandRunnerFactory extends ShellStreamCommandRunnerFactory<WslShellCommandRunnerOptions> implements ICommandRunnerFactory {
|
||||
protected getCommandAndArgs(commandResponse: CommandResponseBase): { command: string, args: CommandLineArgs } {
|
||||
const command = this.options.wslPath ?? 'wsl.exe';
|
||||
const args = composeArgs(
|
||||
withNamedArg('-d', this.options.distro),
|
||||
withArg('--'),
|
||||
withArg(commandResponse.command),
|
||||
withArg(...commandResponse.args),
|
||||
)();
|
||||
|
||||
return { command, args };
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CommandLineArgs } from '../utils/commandLineBuilder';
|
||||
|
||||
/**
|
||||
* A command response includes the command (i.e., the executable) to execute, and arguments to pass
|
||||
*/
|
||||
export type CommandResponseBase = {
|
||||
command: string;
|
||||
args: CommandLineArgs;
|
||||
};
|
||||
|
||||
/**
|
||||
* A {@link CommandResponseBase} that also includes a method to parse the output of the command
|
||||
*/
|
||||
export type PromiseCommandResponse<T> = CommandResponseBase & {
|
||||
parse: (output: string, strict: boolean) => Promise<T>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A {@link CommandResponseBase} that also includes a method to parse streaming output of the command
|
||||
* as an {@link AsyncGenerator}
|
||||
*/
|
||||
export type GeneratorCommandResponse<T> = CommandResponseBase & {
|
||||
parseStream: (output: NodeJS.ReadableStream, strict: boolean) => AsyncGenerator<T>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A {@link CommandResponseBase} that cannot include parsing methods--i.e. the output is `void`
|
||||
*/
|
||||
export type VoidCommandResponse = CommandResponseBase & {
|
||||
parse?: never;
|
||||
parseStream?: never;
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper type that allows for several simple ways to resolve an item
|
||||
*/
|
||||
export type Like<T> = T | Promise<T> | (() => T | Promise<T>);
|
||||
|
||||
/**
|
||||
* A {@link CommandRunner} provides instructions on how to invoke a command
|
||||
*/
|
||||
export type CommandRunner =
|
||||
(<T>(commandResponseLike: Like<PromiseCommandResponse<T>>) => Promise<T>) &
|
||||
((commandResponseLike: Like<VoidCommandResponse>) => Promise<void>);
|
||||
|
||||
/**
|
||||
* A {@link StreamingCommandRunner} provides instructions on how to invoke a streaming command
|
||||
*/
|
||||
export type StreamingCommandRunner = <T>(commandResponseLike: Like<GeneratorCommandResponse<T>>) => AsyncGenerator<T>;
|
||||
|
||||
/**
|
||||
* A {@link ICommandRunnerFactory} is used to build a CommandRunner instance
|
||||
* based for a specific configuration
|
||||
*/
|
||||
export interface ICommandRunnerFactory {
|
||||
getCommandRunner(): CommandRunner;
|
||||
getStreamingCommandRunner(): StreamingCommandRunner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a `Like<CommandResponse>` into a `CommandResponse`
|
||||
* @param commandResponseLike The command response-like to normalize
|
||||
* @returns The command response
|
||||
*/
|
||||
export function normalizeCommandResponseLike<TCommandResponse extends CommandResponseBase>(commandResponseLike: Like<TCommandResponse>): Promise<TCommandResponse> {
|
||||
if (typeof commandResponseLike === 'function') {
|
||||
return Promise.resolve(commandResponseLike());
|
||||
} else {
|
||||
return Promise.resolve(commandResponseLike);
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,192 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { GeneratorCommandResponse, PromiseCommandResponse, VoidCommandResponse } from "./CommandRunner";
|
||||
import { ClientIdentity, CommonCommandOptions } from "./ContainerClient";
|
||||
|
||||
// #region Container orchestrator commands
|
||||
// Common command options
|
||||
export type CommonOrchestratorCommandOptions = CommonCommandOptions & {
|
||||
/**
|
||||
* Orchestrator files, e.g. compose files
|
||||
*/
|
||||
files?: Array<string>;
|
||||
/**
|
||||
* Environment variable file
|
||||
*/
|
||||
environmentFile?: string;
|
||||
/**
|
||||
* Project name
|
||||
*/
|
||||
projectName?: string;
|
||||
};
|
||||
|
||||
// Up command types
|
||||
export type UpCommandOptions = CommonOrchestratorCommandOptions & {
|
||||
/**
|
||||
* Whether to build while up'ing
|
||||
*/
|
||||
build?: boolean;
|
||||
/**
|
||||
* Whether to run in a detached session
|
||||
*/
|
||||
detached?: boolean;
|
||||
/**
|
||||
* A timeout in seconds
|
||||
*/
|
||||
timeoutSeconds?: number;
|
||||
/**
|
||||
* Whether to wait until services are running and healthy
|
||||
*/
|
||||
wait?: boolean;
|
||||
/**
|
||||
* Specific services to start
|
||||
*/
|
||||
services?: Array<string>;
|
||||
/**
|
||||
* Specific service profiles to start
|
||||
*/
|
||||
profiles?: Array<string>;
|
||||
/**
|
||||
* Override specific service scaling
|
||||
*/
|
||||
scale?: Record<string, number>;
|
||||
/**
|
||||
* Additional custom options to pass
|
||||
*/
|
||||
customOptions?: string;
|
||||
};
|
||||
|
||||
type UpCommand = {
|
||||
/**
|
||||
* Generate a {@link VoidCommandResponse} for up'ing services with a container orchestrator
|
||||
* @param options Command options
|
||||
*/
|
||||
up(options: UpCommandOptions): Promise<VoidCommandResponse>;
|
||||
};
|
||||
|
||||
// Down command types
|
||||
export type DownCommandOptions = CommonOrchestratorCommandOptions & {
|
||||
/**
|
||||
* Whether to remove named volumes
|
||||
*/
|
||||
removeVolumes?: boolean;
|
||||
/**
|
||||
* Whether to remove images
|
||||
*/
|
||||
removeImages?: 'all' | 'local';
|
||||
/**
|
||||
* A timeout in seconds
|
||||
*/
|
||||
timeoutSeconds?: number;
|
||||
/**
|
||||
* Additional custom options to pass
|
||||
*/
|
||||
customOptions?: string;
|
||||
};
|
||||
|
||||
type DownCommand = {
|
||||
/**
|
||||
* Generate a {@link VoidCommandResponse} for down'ing services with a container orchestrator
|
||||
* @param options Command options
|
||||
*/
|
||||
down(options: DownCommandOptions): Promise<VoidCommandResponse>;
|
||||
};
|
||||
|
||||
// Start command types
|
||||
// No special options
|
||||
export type StartCommandOptions = CommonOrchestratorCommandOptions;
|
||||
|
||||
type StartCommand = {
|
||||
/**
|
||||
* Generate a {@link VoidCommandResponse} for starting services with a container orchestrator
|
||||
* @param options Command options
|
||||
*/
|
||||
start(options: StartCommandOptions): Promise<VoidCommandResponse>;
|
||||
};
|
||||
|
||||
// Stop command types
|
||||
export type StopCommandOptions = CommonOrchestratorCommandOptions & {
|
||||
/**
|
||||
* A timeout in seconds
|
||||
*/
|
||||
timeoutSeconds?: number;
|
||||
};
|
||||
|
||||
type StopCommand = {
|
||||
/**
|
||||
* Generate a {@link VoidCommandResponse} for stopping services with a container orchestrator
|
||||
* @param options Command options
|
||||
*/
|
||||
stop(options: StopCommandOptions): Promise<VoidCommandResponse>;
|
||||
};
|
||||
|
||||
// Restart command types
|
||||
export type RestartCommandOptions = CommonOrchestratorCommandOptions & {
|
||||
/**
|
||||
* A timeout in seconds
|
||||
*/
|
||||
timeoutSeconds?: number;
|
||||
};
|
||||
|
||||
type RestartCommand = {
|
||||
/**
|
||||
* Generate a {@link VoidCommandResponse} for restarting services with a container orchestrator
|
||||
* @param options Command options
|
||||
*/
|
||||
restart(options: RestartCommandOptions): Promise<VoidCommandResponse>;
|
||||
};
|
||||
|
||||
// Logs command types
|
||||
export type LogsCommandOptions = CommonOrchestratorCommandOptions & {
|
||||
/**
|
||||
* Whether or not to follow the log output
|
||||
*/
|
||||
follow?: boolean;
|
||||
/**
|
||||
* Maximum number of lines to show from the end of the logs
|
||||
*/
|
||||
tail?: number;
|
||||
};
|
||||
|
||||
type LogsCommand = {
|
||||
/**
|
||||
* Generate a {@link GeneratorCommandResponse} for getting collated logs from services with a container orchestrator
|
||||
* @param options Command options
|
||||
*/
|
||||
logs(options: LogsCommandOptions): Promise<GeneratorCommandResponse<string>>;
|
||||
};
|
||||
|
||||
// Config command types
|
||||
export type ConfigCommandOptions = CommonOrchestratorCommandOptions & {
|
||||
configType: 'services' | 'images' | 'profiles' | 'volumes';
|
||||
};
|
||||
|
||||
// The output is just a simple string
|
||||
export type ConfigItem = string;
|
||||
|
||||
type ConfigCommand = {
|
||||
/**
|
||||
* Generate a {@link PromiseCommandResponse} for getting config information for services
|
||||
* @param options Command options
|
||||
*/
|
||||
config(options: ConfigCommandOptions): Promise<PromiseCommandResponse<Array<ConfigItem>>>;
|
||||
};
|
||||
|
||||
// #endregion
|
||||
|
||||
/**
|
||||
* Standard interface for executing commands against container runtimes.
|
||||
* Individual runtimes implement this interface.
|
||||
*/
|
||||
export interface IContainerOrchestratorClient extends
|
||||
ClientIdentity,
|
||||
UpCommand,
|
||||
DownCommand,
|
||||
StartCommand,
|
||||
StopCommand,
|
||||
RestartCommand,
|
||||
LogsCommand,
|
||||
ConfigCommand { }
|
|
@ -1,13 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ShellQuotedString, ShellQuoting } from 'vscode';
|
||||
import { CommandLineArgs } from '../utils/commandLineBuilder';
|
||||
|
||||
export interface IShell {
|
||||
quote(args: CommandLineArgs): Array<string>;
|
||||
goTemplateQuotedString(arg: string, quoting: ShellQuoting): ShellQuotedString;
|
||||
getShellOrDefault(shell?: string | boolean): string | boolean | undefined;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export * from './clients/DockerClient/DockerClient';
|
||||
export * from './clients/DockerComposeClient/DockerComposeClient';
|
||||
export * from './commandRunners/shellStream';
|
||||
export * from './commandRunners/wslStream';
|
||||
export * from './contracts/CommandRunner';
|
||||
export * from './contracts/ContainerClient';
|
||||
export * from './contracts/ContainerOrchestratorClient';
|
||||
export * from './typings/CancellationTokenLike';
|
||||
export * from './typings/DisposableLike';
|
||||
export * from './typings/EventLike';
|
||||
export * from './utils/AccumulatorStream';
|
||||
export * from './utils/CancellationError';
|
||||
export * from './utils/ChildProcessError';
|
||||
export * from './utils/CommandNotSupportedError';
|
||||
export * from './utils/commandLineBuilder';
|
||||
export * from './utils/getNativeArchitecture';
|
||||
export * from './utils/normalizeContainerOS';
|
||||
export * from './utils/spawnStreamAsync';
|
|
@ -1,135 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { expect } from 'chai';
|
||||
import * as crypto from 'crypto';
|
||||
import { describe, it } from 'mocha';
|
||||
import { ShellQuoting } from 'vscode';
|
||||
|
||||
import {
|
||||
DockerClient,
|
||||
} from '../clients/DockerClient/DockerClient';
|
||||
import { BuildImageCommandOptions, RunContainerCommandOptions } from '../contracts/ContainerClient';
|
||||
import { escaped } from '../utils/commandLineBuilder';
|
||||
import { Bash, Powershell } from '../utils/spawnStreamAsync';
|
||||
|
||||
describe('DockerClient', () => {
|
||||
const client = new DockerClient();
|
||||
|
||||
describe('#listImagesAsync()', () => {
|
||||
it('parses date formats', async () => {
|
||||
const commandResult = await client.listImages({});
|
||||
const results = await commandResult.parse(
|
||||
[
|
||||
'{"Containers":"N/A","CreatedAt":"2021-06-08 08:07:21 +0100 BST","CreatedSince":"17 months ago","Digest":"\u003cnone\u003e","ID":"someid","Repository":"some/repository","SharedSize":"N/A","Size":"1MB","Tag":"sometag","UniqueSize":"N/A","VirtualSize":"1MB"}',
|
||||
'{"Containers":"N/A","CreatedAt":"2021-06-08 08:07:21.000Z","CreatedSince":"17 months ago","Digest":"\u003cnone\u003e","ID":"otherid","Repository":"some/repository","SharedSize":"N/A","Size":"1MB","Tag":"sometag","UniqueSize":"N/A","VirtualSize":"1MB"}',
|
||||
].join('\n'),
|
||||
false,
|
||||
);
|
||||
|
||||
expect(results).to.have.lengthOf(2);
|
||||
expect(results[0]).to.have.property('createdAt');
|
||||
expect(results[0].createdAt.getDay()).to.not.be.NaN;
|
||||
expect(results[1]).to.have.property('createdAt');
|
||||
expect(results[1].createdAt.getDay()).to.not.be.NaN;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#buildImageAsync()', () => {
|
||||
it('handles default values', async () => {
|
||||
const path = crypto.randomBytes(60).toString('utf8');
|
||||
|
||||
const commandResult = await client.buildImage({
|
||||
path,
|
||||
});
|
||||
|
||||
expect(commandResult).to.have.a.property('command', 'docker');
|
||||
expect(commandResult).to.have.a.property('args').that.deep.equals(
|
||||
[
|
||||
escaped('image'),
|
||||
escaped('build'),
|
||||
{ value: path, quoting: ShellQuoting.Strong },
|
||||
]);
|
||||
});
|
||||
it('handles pull=true', async () => {
|
||||
const commandResult = await client.buildImage({
|
||||
path: '.',
|
||||
pull: true,
|
||||
});
|
||||
|
||||
expect(commandResult).to.have.property('args').with.lengthOf(4);
|
||||
});
|
||||
it('handles pull=false', async () => {
|
||||
const commandResult = await client.buildImage({
|
||||
path: '.',
|
||||
pull: false,
|
||||
});
|
||||
|
||||
expect(commandResult).to.have.property('args').with.lengthOf(3);
|
||||
});
|
||||
it('handles file', async () => {
|
||||
const file = crypto.randomBytes(60).toString('utf8');
|
||||
|
||||
const commandResult = await client.buildImage({
|
||||
path: '.',
|
||||
file,
|
||||
});
|
||||
|
||||
expect(commandResult).to.have.property('args').that.deep.equals([
|
||||
escaped('image'),
|
||||
escaped('build'),
|
||||
escaped('--file'),
|
||||
{ value: file, quoting: ShellQuoting.Strong },
|
||||
{ value: '.', quoting: ShellQuoting.Strong },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('DockerClient (unit)', () => {
|
||||
const client = new DockerClient();
|
||||
|
||||
it('Should produce the expected lack of quoting/escaping customOptions', async () => {
|
||||
const options: BuildImageCommandOptions = {
|
||||
path: '.',
|
||||
customOptions: '--no-cache --progress plain'
|
||||
};
|
||||
|
||||
const commandResponse = await client.buildImage(options);
|
||||
const pwshQuoted = new Powershell().quote(commandResponse.args);
|
||||
const bashQuoted = new Bash().quote(commandResponse.args);
|
||||
|
||||
expect(pwshQuoted).to.deep.equal(['image', 'build', '--no-cache --progress plain', '\'.\'']);
|
||||
expect(bashQuoted).to.deep.equal(['image', 'build', '--no-cache --progress plain', '\'.\'']);
|
||||
});
|
||||
|
||||
it('Should produce the expected lack of quoting/escaping a single string command', async () => {
|
||||
const options: RunContainerCommandOptions = {
|
||||
imageRef: 'someimage',
|
||||
command: 'sh -c "echo hello world"',
|
||||
};
|
||||
|
||||
const commandResponse = await client.runContainer(options);
|
||||
const pwshQuoted = new Powershell().quote(commandResponse.args);
|
||||
const bashQuoted = new Bash().quote(commandResponse.args);
|
||||
|
||||
expect(pwshQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh -c "echo hello world"']);
|
||||
expect(bashQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh -c "echo hello world"']);
|
||||
});
|
||||
|
||||
it('Should produce the expected quoting/escaping of an array command', async () => {
|
||||
const options: RunContainerCommandOptions = {
|
||||
imageRef: 'someimage',
|
||||
command: ['sh', '-c', 'echo hello world'],
|
||||
};
|
||||
|
||||
const commandResponse = await client.runContainer(options);
|
||||
const pwshQuoted = new Powershell().quote(commandResponse.args);
|
||||
const bashQuoted = new Bash().quote(commandResponse.args);
|
||||
|
||||
expect(pwshQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh', '-c', 'echo` hello` world']);
|
||||
expect(bashQuoted).to.deep.equal(['container', 'run', 'someimage', 'sh', '-c', 'echo\\ hello\\ world']);
|
||||
});
|
||||
});
|
|
@ -1,132 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { DockerComposeClient } from '../clients/DockerComposeClient/DockerComposeClient';
|
||||
import { ShellStreamCommandRunnerFactory } from '../commandRunners/shellStream';
|
||||
import {
|
||||
CommonOrchestratorCommandOptions,
|
||||
ConfigCommandOptions,
|
||||
DownCommandOptions,
|
||||
LogsCommandOptions,
|
||||
RestartCommandOptions,
|
||||
StartCommandOptions,
|
||||
StopCommandOptions,
|
||||
UpCommandOptions
|
||||
} from '../contracts/ContainerOrchestratorClient';
|
||||
import { AccumulatorStream } from '../utils/AccumulatorStream';
|
||||
import { Bash, Cmd, NoShell, Powershell } from '../utils/spawnStreamAsync';
|
||||
|
||||
const commonOptions: CommonOrchestratorCommandOptions = {
|
||||
files: ['docker-compose.yml'],
|
||||
};
|
||||
|
||||
xdescribe('DockerComposeClient', () => {
|
||||
const client = new DockerComposeClient();
|
||||
const cwd = 'TODO';
|
||||
const runnerFactory = new ShellStreamCommandRunnerFactory({
|
||||
cwd: cwd,
|
||||
onCommand: (command: string) => { console.log(`Executing ${command}`); },
|
||||
});
|
||||
const runner = runnerFactory.getCommandRunner();
|
||||
|
||||
it('Should support up command', async () => {
|
||||
const options: UpCommandOptions = {
|
||||
...commonOptions,
|
||||
detached: true,
|
||||
build: true,
|
||||
};
|
||||
|
||||
await runner(client.up(options));
|
||||
});
|
||||
|
||||
it('Should support stop command', async () => {
|
||||
const options: StopCommandOptions = {
|
||||
...commonOptions,
|
||||
};
|
||||
|
||||
await runner(client.stop(options));
|
||||
});
|
||||
|
||||
it('Should support start command', async () => {
|
||||
const options: StartCommandOptions = {
|
||||
...commonOptions,
|
||||
};
|
||||
|
||||
await runner(client.start(options));
|
||||
});
|
||||
|
||||
it('Should support restart command', async () => {
|
||||
const options: RestartCommandOptions = {
|
||||
...commonOptions,
|
||||
};
|
||||
|
||||
await runner(client.restart(options));
|
||||
});
|
||||
|
||||
it('Should support logs command', async () => {
|
||||
const options: LogsCommandOptions = {
|
||||
...commonOptions,
|
||||
};
|
||||
|
||||
const accumulator = new AccumulatorStream();
|
||||
const logsCRF = new ShellStreamCommandRunnerFactory({
|
||||
cwd: cwd,
|
||||
stdOutPipe: accumulator,
|
||||
onCommand: (command: string) => { console.log(`Executing ${command}`); },
|
||||
});
|
||||
|
||||
await logsCRF.getStreamingCommandRunner()(client.logs(options));
|
||||
const logs = await accumulator.getString();
|
||||
expect(logs).to.be.ok;
|
||||
});
|
||||
|
||||
it('Should support down command', async () => {
|
||||
const options: DownCommandOptions = {
|
||||
...commonOptions,
|
||||
};
|
||||
|
||||
await runner(client.down(options));
|
||||
});
|
||||
|
||||
it('Should support config command', async () => {
|
||||
const options: ConfigCommandOptions = {
|
||||
...commonOptions,
|
||||
configType: 'services',
|
||||
};
|
||||
|
||||
const result = await runner(client.config(options));
|
||||
expect(result).to.be.ok;
|
||||
expect(result).to.contain('registry');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DockerComposeClient (unit)', () => {
|
||||
const client = new DockerComposeClient();
|
||||
client.composeV2 = false;
|
||||
|
||||
it('Should produce the expected lack of quoting/escaping customOptions', async () => {
|
||||
const options: UpCommandOptions = {
|
||||
...commonOptions,
|
||||
detached: true,
|
||||
build: true,
|
||||
customOptions: '--timeout 10 --wait'
|
||||
};
|
||||
|
||||
const commandResponse = await client.up(options);
|
||||
const pwshQuoted = new Powershell().quote(commandResponse.args);
|
||||
const cmdQuoted = new Cmd().quote(commandResponse.args);
|
||||
const bashQuoted = new Bash().quote(commandResponse.args);
|
||||
const noShellQuotedWindows = new NoShell(true).quote(commandResponse.args);
|
||||
const noShellQuotedLinux = new NoShell(false).quote(commandResponse.args);
|
||||
|
||||
expect(pwshQuoted).to.deep.equal(['--file', '\'docker-compose.yml\'', 'up', '--detach', '--build', '--timeout 10 --wait']);
|
||||
expect(cmdQuoted).to.deep.equal(['--file', '"docker-compose.yml"', 'up', '--detach', '--build', '--timeout 10 --wait']);
|
||||
expect(bashQuoted).to.deep.equal(['--file', '\'docker-compose.yml\'', 'up', '--detach', '--build', '--timeout 10 --wait']);
|
||||
expect(noShellQuotedWindows).to.deep.equal(['--file', '"docker-compose.yml"', 'up', '--detach', '--build', '--timeout 10 --wait']);
|
||||
expect(noShellQuotedLinux).to.deep.equal(['--file', 'docker-compose.yml', 'up', '--detach', '--build', '--timeout 10 --wait']);
|
||||
});
|
||||
});
|
|
@ -1,56 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { expect } from 'chai';
|
||||
import * as crypto from 'crypto';
|
||||
import { describe, it } from 'mocha';
|
||||
import { ShellQuotedString, ShellQuoting } from 'vscode';
|
||||
|
||||
import { range } from '../utils/range';
|
||||
import {
|
||||
escaped,
|
||||
quoted,
|
||||
withArg,
|
||||
} from '../utils/commandLineBuilder';
|
||||
|
||||
describe('commandLineBuilder', () => {
|
||||
describe('#withArg()', () => {
|
||||
it('creates arg list if no initial args provided', () => {
|
||||
const arg = crypto.randomBytes(crypto.randomInt(20, 101)).toString('utf8');
|
||||
const args = withArg(quoted(arg))();
|
||||
|
||||
expect(args).to.have.lengthOf(1);
|
||||
expect(args).to.deep.equal([quoted(arg)]);
|
||||
});
|
||||
it('creates arg list if empty initial args provided', () => {
|
||||
const arg = crypto.randomBytes(crypto.randomInt(20, 101)).toString('utf8');
|
||||
const args = withArg(arg)([]);
|
||||
|
||||
expect(args).to.have.lengthOf(1);
|
||||
expect(args).to.deep.equal([escaped(arg)]);
|
||||
});
|
||||
it('appends to initial arg list', () => {
|
||||
const initialArgs = new Array<ShellQuotedString>({ value: 'first', quoting: ShellQuoting.Escape }, { value: 'second', quoting: ShellQuoting.Strong });
|
||||
const newArgsCount = crypto.randomInt(1, 5);
|
||||
const newArgs: Array<ShellQuotedString> = [...range(newArgsCount)].map(() => {
|
||||
return { value: crypto.randomBytes(crypto.randomInt(20, 101)).toString('utf8'), quoting: ShellQuoting.Weak };
|
||||
});
|
||||
const args = withArg(...newArgs)(initialArgs);
|
||||
|
||||
expect(initialArgs).to.have.lengthOf(2);
|
||||
expect(args).to.have.lengthOf(2 + newArgsCount);
|
||||
expect(args).to.deep.equal([...initialArgs, ...newArgs]);
|
||||
});
|
||||
it("doesn't append empty args", () => {
|
||||
const initialArgs = new Array<ShellQuotedString>({ value: 'first', quoting: ShellQuoting.Escape }, { value: 'second', quoting: ShellQuoting.Strong });
|
||||
const newArgs = ['third', '', 'fifth'];
|
||||
const args = withArg(...newArgs)(initialArgs);
|
||||
|
||||
expect(initialArgs).to.have.lengthOf(2);
|
||||
expect(args).to.have.lengthOf(4);
|
||||
expect(args).to.deep.equal([...initialArgs, escaped('third'), escaped('fifth')]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { describe, it } from 'mocha';
|
||||
import { normalizeContainerState } from '../clients/DockerClientBase/DockerListContainerRecord';
|
||||
|
||||
describe('normalizeContainerState', () => {
|
||||
|
||||
it('Should use the state if it is present', () => {
|
||||
expect(normalizeContainerState({ State: 'running', Status: 'Ignore' })).to.equal('running');
|
||||
expect(normalizeContainerState({ State: 'exited', Status: 'Ignore' })).to.equal('exited');
|
||||
expect(normalizeContainerState({ State: 'paused', Status: 'Ignore' })).to.equal('paused');
|
||||
expect(normalizeContainerState({ State: 'fake', Status: 'Ignore' })).to.equal('fake');
|
||||
});
|
||||
|
||||
it('Should use the status if the state is not present', () => {
|
||||
expect(normalizeContainerState({ Status: 'Up 2 minutes (Paused)' })).to.equal('paused');
|
||||
|
||||
expect(normalizeContainerState({ Status: 'Up 2 minutes' })).to.equal('running');
|
||||
|
||||
expect(normalizeContainerState({ Status: 'Exited (0) 2 minutes ago' })).to.equal('exited');
|
||||
expect(normalizeContainerState({ Status: 'Terminated (1) 2 minutes ago' })).to.equal('exited');
|
||||
expect(normalizeContainerState({ Status: 'Dead' })).to.equal('exited');
|
||||
|
||||
expect(normalizeContainerState({ Status: 'Created' })).to.equal('created');
|
||||
});
|
||||
|
||||
it('Should return state unknown if the status is unrecognized', () => {
|
||||
expect(normalizeContainerState({ Status: 'Foo' })).to.equal('unknown');
|
||||
});
|
||||
});
|
||||
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче