mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 11:01:37 -05:00
Compare commits
403 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db817a7192 | ||
|
|
2c8e93cc96 | ||
|
|
44e9a97f09 | ||
|
|
298ddc4195 | ||
|
|
d9134d6085 | ||
|
|
b17b4ce880 | ||
|
|
2304c32453 | ||
|
|
2b68e4a7df | ||
|
|
8f06e72318 | ||
|
|
5fa740ead4 | ||
|
|
e5096e61e5 | ||
|
|
2a3195636e | ||
|
|
5fb9b8ccd3 | ||
|
|
7089e2299a | ||
|
|
b553cbb68c | ||
|
|
c712411e77 | ||
|
|
48d5cc554c | ||
|
|
39bfd69dc9 | ||
|
|
d690b80493 | ||
|
|
eb48a9f993 | ||
|
|
5a54abaf44 | ||
|
|
47c161f9f1 | ||
|
|
807f8e68f3 | ||
|
|
fba8536c33 | ||
|
|
36fc1bb71a | ||
|
|
ccaa96c81e | ||
|
|
ac2f279c88 | ||
|
|
91cb99b8c8 | ||
|
|
02b1a525e3 | ||
|
|
9bf4a4b18c | ||
|
|
8a01553c49 | ||
|
|
21b913845f | ||
|
|
220e4feb1d | ||
|
|
13884c0457 | ||
|
|
b3bb6ebc6e | ||
|
|
424eb90dd8 | ||
|
|
df804d0729 | ||
|
|
79269cdfd5 | ||
|
|
2a650d4d74 | ||
|
|
017b4ecdb3 | ||
|
|
9c84bf3fd5 | ||
|
|
397b54a8c3 | ||
|
|
cb3604c0a1 | ||
|
|
1a7f0673ea | ||
|
|
0d043207b9 | ||
|
|
f995dea971 | ||
|
|
49e20488bc | ||
|
|
3e47b27192 | ||
|
|
f4fa18ec05 | ||
|
|
c6d1fa2b7d | ||
|
|
c4df7667ff | ||
|
|
6a303cfa25 | ||
|
|
4ffa5cc1da | ||
|
|
172e1cf3bf | ||
|
|
e6a32e52f5 | ||
|
|
d2b6f6844d | ||
|
|
e9ef95ef1f | ||
|
|
10eeb5374f | ||
|
|
332951bc8e | ||
|
|
4daf3280ff | ||
|
|
87bb2c74d9 | ||
|
|
ba011853a0 | ||
|
|
461a158ac3 | ||
|
|
85f59f1103 | ||
|
|
335b9f445f | ||
|
|
7cda45c904 | ||
|
|
4159fdc1a3 | ||
|
|
190da30979 | ||
|
|
ed9c74b900 | ||
|
|
6783766c33 | ||
|
|
b27018b379 | ||
|
|
021d07e04a | ||
|
|
bf0baec392 | ||
|
|
923cbac400 | ||
|
|
ab938f2536 | ||
|
|
a55b1804e9 | ||
|
|
4bfa6b3a5d | ||
|
|
d20f24be18 | ||
|
|
8a17bae7a6 | ||
|
|
d14c73fad5 | ||
|
|
ce878e1def | ||
|
|
a64a0d1db6 | ||
|
|
feab43f16d | ||
|
|
0d60fe775f | ||
|
|
6680be6a73 | ||
|
|
e026ab85a7 | ||
|
|
e53c903205 | ||
|
|
03dbe8565f | ||
|
|
708793cb23 | ||
|
|
43ae4fb0aa | ||
|
|
6b1d552277 | ||
|
|
f24f576b72 | ||
|
|
c23328564f | ||
|
|
cd6dd3dafa | ||
|
|
4081e15bef | ||
|
|
b05e3813d1 | ||
|
|
3048311f40 | ||
|
|
1045392d91 | ||
|
|
7b23ca8ee7 | ||
|
|
4d67eca8bb | ||
|
|
74c4b7311e | ||
|
|
713c74adfd | ||
|
|
408a8a6f19 | ||
|
|
e1485e49d3 | ||
|
|
30b66934cd | ||
|
|
fd49c081c2 | ||
|
|
1327120024 | ||
|
|
d2b5043972 | ||
|
|
a0e55ea3fd | ||
|
|
1f32de29c1 | ||
|
|
12be06d682 | ||
|
|
27ca9b13f8 | ||
|
|
be45905830 | ||
|
|
05d0a89655 | ||
|
|
3ba575dcd0 | ||
|
|
3e200b7f0f | ||
|
|
cbce1f7008 | ||
|
|
e99101447e | ||
|
|
0ddb326e44 | ||
|
|
460446a15c | ||
|
|
4eea24997f | ||
|
|
0b1e9c7c66 | ||
|
|
d51a7a9eb7 | ||
|
|
0f0b959e14 | ||
|
|
b2ceb09e4d | ||
|
|
53953f5cda | ||
|
|
fbd5e819a2 | ||
|
|
bdc391d376 | ||
|
|
6b618fb121 | ||
|
|
1f3e59c9f9 | ||
|
|
1956078c8c | ||
|
|
11230f59fc | ||
|
|
21bad7a01f | ||
|
|
6f9a27ecc7 | ||
|
|
c504113d13 | ||
|
|
c92ff60592 | ||
|
|
e9013d1a2a | ||
|
|
9c4580fe40 | ||
|
|
cb060cb5db | ||
|
|
6c3d85cc45 | ||
|
|
14ae89e87c | ||
|
|
24c48f025d | ||
|
|
f0a556f004 | ||
|
|
fd4d6abb4d | ||
|
|
41cc839380 | ||
|
|
c2a4380b96 | ||
|
|
6f402ac79f | ||
|
|
bf7c1306b1 | ||
|
|
c1509cf09d | ||
|
|
014bca031c | ||
|
|
4f864fd5bd | ||
|
|
2da67567e4 | ||
|
|
5b19d2b1fc | ||
|
|
a6837dcd40 | ||
|
|
af80751a1f | ||
|
|
dd02597c3b | ||
|
|
2926a3cbd8 | ||
|
|
b02bb3bfd4 | ||
|
|
67a4683bb1 | ||
|
|
9baee1c22c | ||
|
|
8cb67b4f9d | ||
|
|
0cd47bc328 | ||
|
|
07fb58d5e1 | ||
|
|
2d80d5e611 | ||
|
|
4bd63b615b | ||
|
|
335f667507 | ||
|
|
1819036d7d | ||
|
|
4f76f116ac | ||
|
|
1eba7c7d2a | ||
|
|
83234dd52c | ||
|
|
bae23b7fce | ||
|
|
3db61eaa82 | ||
|
|
5cf85a0361 | ||
|
|
ffe27f5bde | ||
|
|
78bcd9d54c | ||
|
|
1a9797f0ff | ||
|
|
0de94ff8a4 | ||
|
|
472233d9a7 | ||
|
|
f69e31b0d5 | ||
|
|
60b696cc31 | ||
|
|
549037f744 | ||
|
|
ca5e1e6133 | ||
|
|
3e3ff163db | ||
|
|
ca755365ce | ||
|
|
ea979de19f | ||
|
|
473ddfcdf1 | ||
|
|
a627285a4c | ||
|
|
322847469d | ||
|
|
6c5fac997f | ||
|
|
1871fd383e | ||
|
|
f5b147ca4b | ||
|
|
9d2b206156 | ||
|
|
a372c76e07 | ||
|
|
b1ce07d3ae | ||
|
|
bc09fb30d8 | ||
|
|
c13f219318 | ||
|
|
6b018c5d06 | ||
|
|
e69158d9b2 | ||
|
|
520cfb780a | ||
|
|
e686fed209 | ||
|
|
80ab19ac23 | ||
|
|
25228fa58e | ||
|
|
676d35090f | ||
|
|
e1a36a356c | ||
|
|
3274c0b734 | ||
|
|
9c95e1289f | ||
|
|
ef29871b62 | ||
|
|
a2a87f8d2b | ||
|
|
83c01c6bcb | ||
|
|
c1d850804c | ||
|
|
6590d5f58a | ||
|
|
a225925bc4 | ||
|
|
ab39f1f44f | ||
|
|
8d89364d72 | ||
|
|
af2bc859d1 | ||
|
|
8e72fdaa52 | ||
|
|
e9661f90d0 | ||
|
|
30b111034d | ||
|
|
df18359309 | ||
|
|
03857e0afd | ||
|
|
eaf1e08752 | ||
|
|
d39ceffa94 | ||
|
|
406b171c66 | ||
|
|
6d89b9e203 | ||
|
|
733bb69d25 | ||
|
|
4609694141 | ||
|
|
3be0c5130a | ||
|
|
e50b512580 | ||
|
|
eb62d054de | ||
|
|
e870a309c0 | ||
|
|
3afd3b0ff3 | ||
|
|
e3a2ed95d4 | ||
|
|
20c4f085c8 | ||
|
|
02af7e9299 | ||
|
|
0ae9b36d93 | ||
|
|
2bbb2842e5 | ||
|
|
a5b4eeb932 | ||
|
|
44de602e52 | ||
|
|
63fb4e2827 | ||
|
|
0a839c7321 | ||
|
|
e9747a61ac | ||
|
|
43c3bf4d24 | ||
|
|
0bf642d200 | ||
|
|
b2b69376c4 | ||
|
|
38ad60478c | ||
|
|
cf6a7198f9 | ||
|
|
ac8a926a70 | ||
|
|
aef7244939 | ||
|
|
628e2adc64 | ||
|
|
0c58f09e59 | ||
|
|
e3baf5c443 | ||
|
|
f70bf590cd | ||
|
|
473a414bc3 | ||
|
|
9ad4ec6464 | ||
|
|
a15c315a1c | ||
|
|
58036bb364 | ||
|
|
8a3509e006 | ||
|
|
1d3ead4031 | ||
|
|
498bb47d7f | ||
|
|
f2df9f3917 | ||
|
|
0414ab6e6a | ||
|
|
14a7a5534f | ||
|
|
edc60e0ad1 | ||
|
|
1a97e3de06 | ||
|
|
f5b1bd0bc2 | ||
|
|
05d7e24e66 | ||
|
|
83842ee9e1 | ||
|
|
a13039b14b | ||
|
|
8fce79f385 | ||
|
|
2efea63000 | ||
|
|
c208abf0c5 | ||
|
|
1359354387 | ||
|
|
cd0f9b71c5 | ||
|
|
04ec9caad1 | ||
|
|
259306a8db | ||
|
|
36a8991682 | ||
|
|
1461929f86 | ||
|
|
4bfc549927 | ||
|
|
40db0d6f6f | ||
|
|
6aac0b6056 | ||
|
|
8e234d9b2d | ||
|
|
70819252a9 | ||
|
|
ba264d8311 | ||
|
|
5de002e5c1 | ||
|
|
0b771abad2 | ||
|
|
00041c8ecd | ||
|
|
0225d6d9f9 | ||
|
|
fb4260d71c | ||
|
|
fa253158f4 | ||
|
|
45e3c6ae49 | ||
|
|
d526fe0f7f | ||
|
|
5707b58fda | ||
|
|
1a9f72dfe0 | ||
|
|
078f3a2b54 | ||
|
|
5bcfb9ab32 | ||
|
|
9bd45cf66a | ||
|
|
89c48bbe75 | ||
|
|
6b549696c5 | ||
|
|
3aaf8a24bf | ||
|
|
41ffd6e8ae | ||
|
|
c0a6f3e012 | ||
|
|
eae8de0373 | ||
|
|
23ec6ac567 | ||
|
|
f4cfb4a5ef | ||
|
|
80a9c82813 | ||
|
|
bcd6178d67 | ||
|
|
f10e281ffc | ||
|
|
c2b32fd64a | ||
|
|
80f150dfb4 | ||
|
|
a5c5fcbde1 | ||
|
|
0d76e845d5 | ||
|
|
979d50eb0e | ||
|
|
7099922c35 | ||
|
|
b54b4a4445 | ||
|
|
03989a5af0 | ||
|
|
1847c2e322 | ||
|
|
f7371e9ed5 | ||
|
|
f696274740 | ||
|
|
1c48320ce0 | ||
|
|
96ecf79d32 | ||
|
|
6d243e0ac8 | ||
|
|
8bf60f133f | ||
|
|
3b9a3aba87 | ||
|
|
f0c986858a | ||
|
|
7ee13b4afb | ||
|
|
bca4102542 | ||
|
|
31ac8d6acc | ||
|
|
e82b7615b3 | ||
|
|
6f10f7a21a | ||
|
|
46fb68214f | ||
|
|
c2381424bc | ||
|
|
31328e79be | ||
|
|
96657e300a | ||
|
|
a2e6aa9e64 | ||
|
|
8c2d79e9cf | ||
|
|
cd140b5527 | ||
|
|
a0456bf4f7 | ||
|
|
55e3947cf7 | ||
|
|
db5156e4cd | ||
|
|
eece0677a7 | ||
|
|
24e8c20511 | ||
|
|
886717d330 | ||
|
|
26b27a616a | ||
|
|
0c663e5555 | ||
|
|
0f087915f6 | ||
|
|
a78fa9c0f2 | ||
|
|
b1752ea635 | ||
|
|
ec150917c2 | ||
|
|
7a9a69c439 | ||
|
|
9e9862c6f0 | ||
|
|
7b76d929cd | ||
|
|
1811dfa423 | ||
|
|
3abbc8fd97 | ||
|
|
4b88b67bed | ||
|
|
a2734807ca | ||
|
|
d0d4df313e | ||
|
|
1efd5e6502 | ||
|
|
b12cac0ac3 | ||
|
|
578aa6ccd2 | ||
|
|
3b90530717 | ||
|
|
f199c7a63c | ||
|
|
50a2526d1f | ||
|
|
7fb8a28b59 | ||
|
|
30a825438e | ||
|
|
f63da13210 | ||
|
|
08d73675d4 | ||
|
|
f0f6c00a0e | ||
|
|
965458ca74 | ||
|
|
b30f7ee41c | ||
|
|
a2eb53ce0b | ||
|
|
619c816e7f | ||
|
|
3d6fb7a8fa | ||
|
|
891624c085 | ||
|
|
a7c4686980 | ||
|
|
93aa052856 | ||
|
|
61d05f6782 | ||
|
|
60ccae48f1 | ||
|
|
4b454581fd | ||
|
|
f0aadebd2c | ||
|
|
d3f0ac7954 | ||
|
|
134f76c17f | ||
|
|
b9c877a109 | ||
|
|
aa243a8aae | ||
|
|
e5c1c6f544 | ||
|
|
9e9f85079e | ||
|
|
ae8e2e1f89 | ||
|
|
b2c70e9301 | ||
|
|
e022f4a0d1 | ||
|
|
8bc32e6371 | ||
|
|
f739c47984 | ||
|
|
13fb9fdfd2 | ||
|
|
9a5f51bfbf | ||
|
|
06bab6a38c | ||
|
|
c35a14d8fd | ||
|
|
b914073147 | ||
|
|
04ae18143b | ||
|
|
efe8e81b6e | ||
|
|
c33ddfabf9 | ||
|
|
8ec5451e64 | ||
|
|
20853ddf7e | ||
|
|
091d4cb924 | ||
|
|
cd0210c88a | ||
|
|
ed10f984b6 |
9
.gitattributes
vendored
Normal file
9
.gitattributes
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
* text=auto
|
||||
|
||||
LICENSE.txt eol=crlf
|
||||
ThirdPartyNotices.txt eol=crlf
|
||||
|
||||
*.bat eol=crlf
|
||||
*.cmd eol=crlf
|
||||
*.ps1 eol=lf
|
||||
*.sh eol=lf
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@ node_modules/
|
||||
out/
|
||||
out-build/
|
||||
out-editor/
|
||||
out-editor-esm/
|
||||
out-editor-min/
|
||||
out-monaco-editor-core/
|
||||
out-vscode/
|
||||
|
||||
@@ -32,8 +32,6 @@ addons:
|
||||
|
||||
before_install:
|
||||
- git submodule update --init --recursive
|
||||
- git clone --depth 1 https://github.com/creationix/nvm.git ./.nvm
|
||||
- source ./.nvm/nvm.sh
|
||||
- nvm install 8.9.1
|
||||
- nvm use 8.9.1
|
||||
- npm i -g yarn
|
||||
|
||||
4
.vscode/extensions.json
vendored
4
.vscode/extensions.json
vendored
@@ -1,9 +1,9 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"eg2.tslint",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"msjsdiag.debugger-for-chrome"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@@ -89,7 +89,8 @@
|
||||
"skipFiles": [
|
||||
"**/winjs*.js"
|
||||
],
|
||||
"webRoot": "${workspaceFolder}"
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"timeout": 15000
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -38,5 +38,6 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
|
||||
2
.yarnrc
2
.yarnrc
@@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "1.7.11"
|
||||
target "1.7.12"
|
||||
runtime "electron"
|
||||
|
||||
64
CHANGELOG.md
64
CHANGELOG.md
@@ -1,5 +1,69 @@
|
||||
# Change Log
|
||||
|
||||
## Version 0.31.4
|
||||
* Release date: July 19, 2018
|
||||
* Release status: Public Preview
|
||||
|
||||
## What's new in this version
|
||||
* SQL Server Agent for SQL Operations Studio extension improvements
|
||||
* Added view of Alerts, Operators, and Proxies and icons on left pane
|
||||
* Added dialogs for New Job, New Job Step, New Alert, and New Operator
|
||||
* Added Delete Job, Delete Alert, and Delete Operator (right-click)
|
||||
* Added Previous Runs visualization
|
||||
* Added Filters for each column name
|
||||
* SQL Server Profiler for SQL Operations Studio extension improvements
|
||||
* Added Hotkeys to quickly launch and start/stop Profiler
|
||||
* Added 5 Default Templates to view Extended Events
|
||||
* Added Server/Database connection name
|
||||
* Added support for Azure SQL Database instances
|
||||
* Added suggestion to exit Profiler when tab is closed when Profiler is still running
|
||||
* Release of Combine Scripts Extension
|
||||
* Wizard and Dialog Extensibility
|
||||
* Fix GitHub Issues
|
||||
|
||||
## Version 0.30.6
|
||||
* Release date: June 20, 2018
|
||||
* Release status: Public Preview
|
||||
|
||||
## What's new in this version
|
||||
* **SQL Server Profiler for SQL Operations Studio *Preview*** extension initial release
|
||||
* The new **SQL Data Warehouse** extension includes rich customizable dashboard widgets surfacing insights to your data warehouse. This unlocks key scenarios around managing and tuning your data warehouse to ensure it is optimized for consistent performance.
|
||||
* **Edit Data "Filtering and Sorting"** support
|
||||
* **SQL Server Agent for SQL Operations Studio *Preview*** extension enhancements for Jobs and Job History views
|
||||
* Improved **Wizard & Dialog UI Builder Framework** extensibility APIs
|
||||
* Update VS Code Platform source code integrating [March 2018 (1.22)](https://code.visualstudio.com/updates/v1_22) and [April 2018 (1.23)](https://code.visualstudio.com/updates/v1_23) releases
|
||||
* Fix GitHub Issues
|
||||
|
||||
## Version 0.29.3
|
||||
* Release date: May 7, 2018
|
||||
* Release status: Public Preview
|
||||
|
||||
## What's new in this version
|
||||
The May release is focused on stabilization and bug fixes leading up to the Build conference. This build contains the following highlights.
|
||||
|
||||
* Announcing **Redgate SQL Search** extension available in Extension Manager
|
||||
* Community Localization available for 10 languages: **German, Spanish, French, Italian, Japanese, Korean, Portuguese, Russian, Simplified Chinese and Traditional Chinese!**
|
||||
* Reduced telemetry collection, improved [opt-out](https://github.com/Microsoft/sqlopsstudio/wiki/How-to-Disable-Telemetry-Reporting) experience and in-product links to [Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement)
|
||||
* Extension Manager has improved Marketplace experience to easily discover community extensions
|
||||
* SQL Agent extension Jobs and Job History view improvement
|
||||
* Updates for **whoisactive** and **Server Reports** extensions
|
||||
* Continue to fix GitHub issues
|
||||
|
||||
## Version 0.28.6
|
||||
* Release date: April 25, 2018
|
||||
* Release status: Public Preview
|
||||
|
||||
## What's new in this version
|
||||
The April Public Preview release contains some of the following highlights.
|
||||
|
||||
* Improvements to SQL Agent *Preview* extension
|
||||
* Accessibility improvements for keyboard navigation, screen reader support and high-contrast mode.
|
||||
* Improved large and protected file support for saving Admin protected and >256M files within SQL Ops Studio
|
||||
* Integrated Terminal splitting to work with multiple open terminals at once
|
||||
* Reduced installation on-disk file count foot print for faster installs and startup times
|
||||
* Improvements to Server Reports extension
|
||||
* Continue to fix GitHub issues
|
||||
|
||||
## Version 0.27.3
|
||||
* Release date: March 28, 2017
|
||||
* Release status: Public Preview
|
||||
|
||||
10
LICENSE.txt
10
LICENSE.txt
@@ -4,11 +4,11 @@ MICROSOFT SQL OPERATIONS STUDIO
|
||||
|
||||
Microsoft Corporation ("Microsoft") grants you a nonexclusive, perpetual,
|
||||
royalty-free right to use, copy, and modify the software code provided by us
|
||||
("Software Code"). You may not sublicense the Software Code or any use of it
|
||||
(except to your affiliates and to vendors to perform work on your behalf)
|
||||
through distribution, network access, service agreement, lease, rental, or
|
||||
otherwise. Unless applicable law gives you more rights, Microsoft reserves all
|
||||
other rights not expressly granted herein, whether by implication, estoppel or
|
||||
("Software Code"). You may not sublicense the Software Code or any use of it
|
||||
(except to your affiliates and to vendors to perform work on your behalf)
|
||||
through distribution, network access, service agreement, lease, rental, or
|
||||
otherwise. Unless applicable law gives you more rights, Microsoft reserves all
|
||||
other rights not expressly granted herein, whether by implication, estoppel or
|
||||
otherwise.
|
||||
|
||||
THE SOFTWARE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
|
||||
384
OSSREADME.json
384
OSSREADME.json
@@ -808,5 +808,389 @@
|
||||
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
|
||||
"SOFTWARE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mdn-data",
|
||||
"version": "1.1.12",
|
||||
"repositoryURL": "https://github.com/mdn/data",
|
||||
"license": "MPL",
|
||||
"licenseDetail": [
|
||||
"Mozilla Public License Version 2.0",
|
||||
"",
|
||||
"Copyright (c) 2018 Mozilla Corporation",
|
||||
"",
|
||||
"==================================",
|
||||
"",
|
||||
"1. Definitions",
|
||||
"--------------",
|
||||
"",
|
||||
"1.1. \"Contributor\"",
|
||||
" means each individual or legal entity that creates, contributes to",
|
||||
" the creation of, or owns Covered Software.",
|
||||
"",
|
||||
"1.2. \"Contributor Version\"",
|
||||
" means the combination of the Contributions of others (if any) used",
|
||||
" by a Contributor and that particular Contributor's Contribution.",
|
||||
"",
|
||||
"1.3. \"Contribution\"",
|
||||
" means Covered Software of a particular Contributor.",
|
||||
"",
|
||||
"1.4. \"Covered Software\"",
|
||||
" means Source Code Form to which the initial Contributor has attached",
|
||||
" the notice in Exhibit A, the Executable Form of such Source Code",
|
||||
" Form, and Modifications of such Source Code Form, in each case",
|
||||
" including portions thereof.",
|
||||
"",
|
||||
"1.5. \"Incompatible With Secondary Licenses\"",
|
||||
" means",
|
||||
"",
|
||||
" (a) that the initial Contributor has attached the notice described",
|
||||
" in Exhibit B to the Covered Software; or",
|
||||
"",
|
||||
" (b) that the Covered Software was made available under the terms of",
|
||||
" version 1.1 or earlier of the License, but not also under the",
|
||||
" terms of a Secondary License.",
|
||||
"",
|
||||
"1.6. \"Executable Form\"",
|
||||
" means any form of the work other than Source Code Form.",
|
||||
"",
|
||||
"1.7. \"Larger Work\"",
|
||||
" means a work that combines Covered Software with other material, in",
|
||||
" a separate file or files, that is not Covered Software.",
|
||||
"",
|
||||
"1.8. \"License\"",
|
||||
" means this document.",
|
||||
"",
|
||||
"1.9. \"Licensable\"",
|
||||
" means having the right to grant, to the maximum extent possible,",
|
||||
" whether at the time of the initial grant or subsequently, any and",
|
||||
" all of the rights conveyed by this License.",
|
||||
"",
|
||||
"1.10. \"Modifications\"",
|
||||
" means any of the following:",
|
||||
"",
|
||||
" (a) any file in Source Code Form that results from an addition to,",
|
||||
" deletion from, or modification of the contents of Covered",
|
||||
" Software; or",
|
||||
"",
|
||||
" (b) any new file in Source Code Form that contains any Covered",
|
||||
" Software.",
|
||||
"",
|
||||
"1.11. \"Patent Claims\" of a Contributor",
|
||||
" means any patent claim(s), including without limitation, method,",
|
||||
" process, and apparatus claims, in any patent Licensable by such",
|
||||
" Contributor that would be infringed, but for the grant of the",
|
||||
" License, by the making, using, selling, offering for sale, having",
|
||||
" made, import, or transfer of either its Contributions or its",
|
||||
" Contributor Version.",
|
||||
"",
|
||||
"1.12. \"Secondary License\"",
|
||||
" means either the GNU General Public License, Version 2.0, the GNU",
|
||||
" Lesser General Public License, Version 2.1, the GNU Affero General",
|
||||
" Public License, Version 3.0, or any later versions of those",
|
||||
" licenses.",
|
||||
"",
|
||||
"1.13. \"Source Code Form\"",
|
||||
" means the form of the work preferred for making modifications.",
|
||||
"",
|
||||
"1.14. \"You\" (or \"Your\")",
|
||||
" means an individual or a legal entity exercising rights under this",
|
||||
" License. For legal entities, \"You\" includes any entity that",
|
||||
" controls, is controlled by, or is under common control with You. For",
|
||||
" purposes of this definition, \"control\" means (a) the power, direct",
|
||||
" or indirect, to cause the direction or management of such entity,",
|
||||
" whether by contract or otherwise, or (b) ownership of more than",
|
||||
" fifty percent (50%) of the outstanding shares or beneficial",
|
||||
" ownership of such entity.",
|
||||
"",
|
||||
"2. License Grants and Conditions",
|
||||
"--------------------------------",
|
||||
"",
|
||||
"2.1. Grants",
|
||||
"",
|
||||
"Each Contributor hereby grants You a world-wide, royalty-free,",
|
||||
"non-exclusive license:",
|
||||
"",
|
||||
"(a) under intellectual property rights (other than patent or trademark)",
|
||||
" Licensable by such Contributor to use, reproduce, make available,",
|
||||
" modify, display, perform, distribute, and otherwise exploit its",
|
||||
" Contributions, either on an unmodified basis, with Modifications, or",
|
||||
" as part of a Larger Work; and",
|
||||
"",
|
||||
"(b) under Patent Claims of such Contributor to make, use, sell, offer",
|
||||
" for sale, have made, import, and otherwise transfer either its",
|
||||
" Contributions or its Contributor Version.",
|
||||
"",
|
||||
"2.2. Effective Date",
|
||||
"",
|
||||
"The licenses granted in Section 2.1 with respect to any Contribution",
|
||||
"become effective for each Contribution on the date the Contributor first",
|
||||
"distributes such Contribution.",
|
||||
"",
|
||||
"2.3. Limitations on Grant Scope",
|
||||
"",
|
||||
"The licenses granted in this Section 2 are the only rights granted under",
|
||||
"this License. No additional rights or licenses will be implied from the",
|
||||
"distribution or licensing of Covered Software under this License.",
|
||||
"Notwithstanding Section 2.1(b) above, no patent license is granted by a",
|
||||
"Contributor:",
|
||||
"",
|
||||
"(a) for any code that a Contributor has removed from Covered Software;",
|
||||
" or",
|
||||
"",
|
||||
"(b) for infringements caused by: (i) Your and any other third party's",
|
||||
" modifications of Covered Software, or (ii) the combination of its",
|
||||
" Contributions with other software (except as part of its Contributor",
|
||||
" Version); or",
|
||||
"",
|
||||
"(c) under Patent Claims infringed by Covered Software in the absence of",
|
||||
" its Contributions.",
|
||||
"",
|
||||
"This License does not grant any rights in the trademarks, service marks,",
|
||||
"or logos of any Contributor (except as may be necessary to comply with",
|
||||
"the notice requirements in Section 3.4).",
|
||||
"",
|
||||
"2.4. Subsequent Licenses",
|
||||
"",
|
||||
"No Contributor makes additional grants as a result of Your choice to",
|
||||
"distribute the Covered Software under a subsequent version of this",
|
||||
"License (see Section 10.2) or under the terms of a Secondary License (if",
|
||||
"permitted under the terms of Section 3.3).",
|
||||
"",
|
||||
"2.5. Representation",
|
||||
"",
|
||||
"Each Contributor represents that the Contributor believes its",
|
||||
"Contributions are its original creation(s) or it has sufficient rights",
|
||||
"to grant the rights to its Contributions conveyed by this License.",
|
||||
"",
|
||||
"2.6. Fair Use",
|
||||
"",
|
||||
"This License is not intended to limit any rights You have under",
|
||||
"applicable copyright doctrines of fair use, fair dealing, or other",
|
||||
"equivalents.",
|
||||
"",
|
||||
"2.7. Conditions",
|
||||
"",
|
||||
"Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted",
|
||||
"in Section 2.1.",
|
||||
"",
|
||||
"3. Responsibilities",
|
||||
"-------------------",
|
||||
"",
|
||||
"3.1. Distribution of Source Form",
|
||||
"",
|
||||
"All distribution of Covered Software in Source Code Form, including any",
|
||||
"Modifications that You create or to which You contribute, must be under",
|
||||
"the terms of this License. You must inform recipients that the Source",
|
||||
"Code Form of the Covered Software is governed by the terms of this",
|
||||
"License, and how they can obtain a copy of this License. You may not",
|
||||
"attempt to alter or restrict the recipients' rights in the Source Code",
|
||||
"Form.",
|
||||
"",
|
||||
"3.2. Distribution of Executable Form",
|
||||
"",
|
||||
"If You distribute Covered Software in Executable Form then:",
|
||||
"",
|
||||
"(a) such Covered Software must also be made available in Source Code",
|
||||
" Form, as described in Section 3.1, and You must inform recipients of",
|
||||
" the Executable Form how they can obtain a copy of such Source Code",
|
||||
" Form by reasonable means in a timely manner, at a charge no more",
|
||||
" than the cost of distribution to the recipient; and",
|
||||
"",
|
||||
"(b) You may distribute such Executable Form under the terms of this",
|
||||
" License, or sublicense it under different terms, provided that the",
|
||||
" license for the Executable Form does not attempt to limit or alter",
|
||||
" the recipients' rights in the Source Code Form under this License.",
|
||||
"",
|
||||
"3.3. Distribution of a Larger Work",
|
||||
"",
|
||||
"You may create and distribute a Larger Work under terms of Your choice,",
|
||||
"provided that You also comply with the requirements of this License for",
|
||||
"the Covered Software. If the Larger Work is a combination of Covered",
|
||||
"Software with a work governed by one or more Secondary Licenses, and the",
|
||||
"Covered Software is not Incompatible With Secondary Licenses, this",
|
||||
"License permits You to additionally distribute such Covered Software",
|
||||
"under the terms of such Secondary License(s), so that the recipient of",
|
||||
"the Larger Work may, at their option, further distribute the Covered",
|
||||
"Software under the terms of either this License or such Secondary",
|
||||
"License(s).",
|
||||
"",
|
||||
"3.4. Notices",
|
||||
"",
|
||||
"You may not remove or alter the substance of any license notices",
|
||||
"(including copyright notices, patent notices, disclaimers of warranty,",
|
||||
"or limitations of liability) contained within the Source Code Form of",
|
||||
"the Covered Software, except that You may alter any license notices to",
|
||||
"the extent required to remedy known factual inaccuracies.",
|
||||
"",
|
||||
"3.5. Application of Additional Terms",
|
||||
"",
|
||||
"You may choose to offer, and to charge a fee for, warranty, support,",
|
||||
"indemnity or liability obligations to one or more recipients of Covered",
|
||||
"Software. However, You may do so only on Your own behalf, and not on",
|
||||
"behalf of any Contributor. You must make it absolutely clear that any",
|
||||
"such warranty, support, indemnity, or liability obligation is offered by",
|
||||
"You alone, and You hereby agree to indemnify every Contributor for any",
|
||||
"liability incurred by such Contributor as a result of warranty, support,",
|
||||
"indemnity or liability terms You offer. You may include additional",
|
||||
"disclaimers of warranty and limitations of liability specific to any",
|
||||
"jurisdiction.",
|
||||
"",
|
||||
"4. Inability to Comply Due to Statute or Regulation",
|
||||
"---------------------------------------------------",
|
||||
"",
|
||||
"If it is impossible for You to comply with any of the terms of this",
|
||||
"License with respect to some or all of the Covered Software due to",
|
||||
"statute, judicial order, or regulation then You must: (a) comply with",
|
||||
"the terms of this License to the maximum extent possible; and (b)",
|
||||
"describe the limitations and the code they affect. Such description must",
|
||||
"be placed in a text file included with all distributions of the Covered",
|
||||
"Software under this License. Except to the extent prohibited by statute",
|
||||
"or regulation, such description must be sufficiently detailed for a",
|
||||
"recipient of ordinary skill to be able to understand it.",
|
||||
"",
|
||||
"5. Termination",
|
||||
"--------------",
|
||||
"",
|
||||
"5.1. The rights granted under this License will terminate automatically",
|
||||
"if You fail to comply with any of its terms. However, if You become",
|
||||
"compliant, then the rights granted under this License from a particular",
|
||||
"Contributor are reinstated (a) provisionally, unless and until such",
|
||||
"Contributor explicitly and finally terminates Your grants, and (b) on an",
|
||||
"ongoing basis, if such Contributor fails to notify You of the",
|
||||
"non-compliance by some reasonable means prior to 60 days after You have",
|
||||
"come back into compliance. Moreover, Your grants from a particular",
|
||||
"Contributor are reinstated on an ongoing basis if such Contributor",
|
||||
"notifies You of the non-compliance by some reasonable means, this is the",
|
||||
"first time You have received notice of non-compliance with this License",
|
||||
"from such Contributor, and You become compliant prior to 30 days after",
|
||||
"Your receipt of the notice.",
|
||||
"",
|
||||
"5.2. If You initiate litigation against any entity by asserting a patent",
|
||||
"infringement claim (excluding declaratory judgment actions,",
|
||||
"counter-claims, and cross-claims) alleging that a Contributor Version",
|
||||
"directly or indirectly infringes any patent, then the rights granted to",
|
||||
"You by any and all Contributors for the Covered Software under Section",
|
||||
"2.1 of this License shall terminate.",
|
||||
"",
|
||||
"5.3. In the event of termination under Sections 5.1 or 5.2 above, all",
|
||||
"end user license agreements (excluding distributors and resellers) which",
|
||||
"have been validly granted by You or Your distributors under this License",
|
||||
"prior to termination shall survive termination.",
|
||||
"",
|
||||
"************************************************************************",
|
||||
"* *",
|
||||
"* 6. Disclaimer of Warranty *",
|
||||
"* ------------------------- *",
|
||||
"* *",
|
||||
"* Covered Software is provided under this License on an \"as is\" *",
|
||||
"* basis, without warranty of any kind, either expressed, implied, or *",
|
||||
"* statutory, including, without limitation, warranties that the *",
|
||||
"* Covered Software is free of defects, merchantable, fit for a *",
|
||||
"* particular purpose or non-infringing. The entire risk as to the *",
|
||||
"* quality and performance of the Covered Software is with You. *",
|
||||
"* Should any Covered Software prove defective in any respect, You *",
|
||||
"* (not any Contributor) assume the cost of any necessary servicing, *",
|
||||
"* repair, or correction. This disclaimer of warranty constitutes an *",
|
||||
"* essential part of this License. No use of any Covered Software is *",
|
||||
"* authorized under this License except under this disclaimer. *",
|
||||
"* *",
|
||||
"************************************************************************",
|
||||
"",
|
||||
"************************************************************************",
|
||||
"* *",
|
||||
"* 7. Limitation of Liability *",
|
||||
"* -------------------------- *",
|
||||
"* *",
|
||||
"* Under no circumstances and under no legal theory, whether tort *",
|
||||
"* (including negligence), contract, or otherwise, shall any *",
|
||||
"* Contributor, or anyone who distributes Covered Software as *",
|
||||
"* permitted above, be liable to You for any direct, indirect, *",
|
||||
"* special, incidental, or consequential damages of any character *",
|
||||
"* including, without limitation, damages for lost profits, loss of *",
|
||||
"* goodwill, work stoppage, computer failure or malfunction, or any *",
|
||||
"* and all other commercial damages or losses, even if such party *",
|
||||
"* shall have been informed of the possibility of such damages. This *",
|
||||
"* limitation of liability shall not apply to liability for death or *",
|
||||
"* personal injury resulting from such party's negligence to the *",
|
||||
"* extent applicable law prohibits such limitation. Some *",
|
||||
"* jurisdictions do not allow the exclusion or limitation of *",
|
||||
"* incidental or consequential damages, so this exclusion and *",
|
||||
"* limitation may not apply to You. *",
|
||||
"* *",
|
||||
"************************************************************************",
|
||||
"",
|
||||
"8. Litigation",
|
||||
"-------------",
|
||||
"",
|
||||
"Any litigation relating to this License may be brought only in the",
|
||||
"courts of a jurisdiction where the defendant maintains its principal",
|
||||
"place of business and such litigation shall be governed by laws of that",
|
||||
"jurisdiction, without reference to its conflict-of-law provisions.",
|
||||
"Nothing in this Section shall prevent a party's ability to bring",
|
||||
"cross-claims or counter-claims.",
|
||||
"",
|
||||
"9. Miscellaneous",
|
||||
"----------------",
|
||||
"",
|
||||
"This License represents the complete agreement concerning the subject",
|
||||
"matter hereof. If any provision of this License is held to be",
|
||||
"unenforceable, such provision shall be reformed only to the extent",
|
||||
"necessary to make it enforceable. Any law or regulation which provides",
|
||||
"that the language of a contract shall be construed against the drafter",
|
||||
"shall not be used to construe this License against a Contributor.",
|
||||
"",
|
||||
"10. Versions of the License",
|
||||
"---------------------------",
|
||||
"",
|
||||
"10.1. New Versions",
|
||||
"",
|
||||
"Mozilla Foundation is the license steward. Except as provided in Section",
|
||||
"10.3, no one other than the license steward has the right to modify or",
|
||||
"publish new versions of this License. Each version will be given a",
|
||||
"distinguishing version number.",
|
||||
"",
|
||||
"10.2. Effect of New Versions",
|
||||
"",
|
||||
"You may distribute the Covered Software under the terms of the version",
|
||||
"of the License under which You originally received the Covered Software,",
|
||||
"or under the terms of any subsequent version published by the license",
|
||||
"steward.",
|
||||
"",
|
||||
"10.3. Modified Versions",
|
||||
"",
|
||||
"If you create software not governed by this License, and you want to",
|
||||
"create a new license for such software, you may create and use a",
|
||||
"modified version of this License if you rename the license and remove",
|
||||
"any references to the name of the license steward (except to note that",
|
||||
"such modified license differs from this License).",
|
||||
"",
|
||||
"10.4. Distributing Source Code Form that is Incompatible With Secondary",
|
||||
"Licenses",
|
||||
"",
|
||||
"If You choose to distribute Source Code Form that is Incompatible With",
|
||||
"Secondary Licenses under the terms of this version of the License, the",
|
||||
"notice described in Exhibit B of this License must be attached.",
|
||||
"",
|
||||
"Exhibit A - Source Code Form License Notice",
|
||||
"-------------------------------------------",
|
||||
"",
|
||||
" This Source Code Form is subject to the terms of the Mozilla Public",
|
||||
" License, v. 2.0. If a copy of the MPL was not distributed with this",
|
||||
" file, You can obtain one at http://mozilla.org/MPL/2.0/.",
|
||||
"",
|
||||
"If it is not possible or desirable to put the notice in a particular",
|
||||
"file, then You may include the notice in a location (such as a LICENSE",
|
||||
"file in a relevant directory) where a recipient would be likely to look",
|
||||
"for such a notice.",
|
||||
"",
|
||||
"You may add additional accurate notices of copyright ownership.",
|
||||
"",
|
||||
"Exhibit B - \"Incompatible With Secondary Licenses\" Notice",
|
||||
"---------------------------------------------------------",
|
||||
"",
|
||||
" This Source Code Form is \"Incompatible With Secondary Licenses\", as",
|
||||
" defined by the Mozilla Public License, v. 2.0."
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
36
README.md
36
README.md
@@ -4,16 +4,16 @@
|
||||
|
||||
SQL Operations Studio is a data management tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.
|
||||
|
||||
**Download SQL Operations Studio March Public Preview**
|
||||
**Download SQL Operations Studio June Public Preview**
|
||||
|
||||
Platform | Link
|
||||
-- | --
|
||||
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=870837
|
||||
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=870838
|
||||
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=870839
|
||||
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=870840
|
||||
Linux DEB | https://go.microsoft.com/fwlink/?linkid=870842
|
||||
Linux RPM | https://go.microsoft.com/fwlink/?linkid=870841
|
||||
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=2005949
|
||||
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=2005950
|
||||
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=2005959
|
||||
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=2005960
|
||||
Linux RPM | https://go.microsoft.com/fwlink/?linkid=2006083
|
||||
Linux DEB | https://go.microsoft.com/fwlink/?linkid=2006084
|
||||
|
||||
Go to our [download page](https://aka.ms/sqlopsstudio) for more specific instructions.
|
||||
|
||||
@@ -21,14 +21,6 @@ Try out the latest insiders build from `master` at https://github.com/Microsoft/
|
||||
|
||||
See the [change log](https://github.com/Microsoft/sqlopsstudio/blob/master/CHANGELOG.md) for additional details of what's in this release.
|
||||
|
||||
**Design Discussions**
|
||||
|
||||
The SQL Operations Studio team would like to incorporate community feedback earlier in the development process. To facilitate this, we'd like to share our designs while features are actively being built.
|
||||
|
||||
We're currently collecting input on the **SQL Agent** experience and enhancements to the Manage Dashboard that we're calling **"Command Center"**. We'll add additional design feedback requests below as we start work in new feature areas. Please leave comments on these issues to help us understand your requirements and shape feature development.
|
||||
|
||||
* [#750 Seeking community feedback on SQL Agent UX prototype](https://github.com/Microsoft/sqlopsstudio/issues/750)
|
||||
|
||||
**Feature Highlights**
|
||||
|
||||
- Cross-Platform DB management for Windows, macOS and Linux with simple XCopy deployment
|
||||
@@ -69,6 +61,7 @@ The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.micro
|
||||
## Contributions and "thank you"
|
||||
We would like to thank all our users who raised issues, and in particular the following users who helped contribute fixes:
|
||||
|
||||
* lanceklinger `Fix for double clicking column handle in results table #1504`
|
||||
* westerncj for `Removed duplicate contribution from README.md (#753)`
|
||||
* ntovas for `Fix for duplicate extensions shown in "Save File" dialog. (#779)`
|
||||
* SebastianPfliegel for `Add cursor snippet (#475)`
|
||||
@@ -82,7 +75,18 @@ We would like to thank all our users who raised issues, and in particular the fo
|
||||
* SebastianPfliegel `Remove sqlExtensionHelp (#312)`
|
||||
* olljanat for `Implemented npm version check (#314)`
|
||||
* Adam Mechanic for helping with the `whoisactive` extension
|
||||
* All community localization contributors *(will get list of individuals next month)*
|
||||
* All community localization contributors
|
||||
* French: Adrien Clerbois, ANAS BELABBES, Antoine Griffard, Arian Papillon, Eric Macarez, Eric Van Thorre, Jérémy LANDON, Matthias GROSPERRIN, Maxime COQUEREL, Olivier Guinart, thierry DEMAN-BARCELÒ, Thomas Potier
|
||||
* Italian: Aldo Donetti, Alessandro Alpi, Andrea Dottor, Bruni Luca, Gianluca Hotz, Luca Nardi, Luigi Bruno, Marco Dal Pino, Mirco Vanini, Pasquale Ceglie, Riccardo Cappello, Sergio Govoni, Stefano Demiliani
|
||||
* German: Anna Henke-Gunvaldson, Ben Weissman, David Ullmer, J.M. ., Kai Modo, Konstantin Staschill, Kostja Klein, Lennart Trunk, Markus Ehrenmüller-Jensen, Mascha Kroenlein, Matthias Knoll, Mourad Louha, Thomas Hütter, Wolfgang Straßer
|
||||
* Spanish: Alberto Poblacion, Andy Gonzalez, Carlos Mendible, Christian Araujo, Daniel D, Eickhel Mendoza, Ernesto Cardenas, Ivan Toledo Ivanovic, Fran Diaz, JESUS GIL, Jorge Serrano Pérez, José Saturnino Pimentel Juárez, Mauricio Hidalgo, Pablo Iglesias, Rikhardo Estrada Rdez, Thierry DEMAN, YOLANDA CUESTA ALTIERI
|
||||
* Japanese: Fujio Kojima, Kazushi KAMEGAWA, Masayoshi Yamada, Masayuki Ozawa , Seiji Momoto, Takashi Kanai, Takayoshi Tanaka, Yoshihisa Ozaki, 庄垣内治
|
||||
* Chinese (simplified): DAN YE, Joel Yang, Lynne Dong, Ryan(Yu) Zhang, Sheng Jiang, Wei Zhang, Zhiliang Xu
|
||||
* Chinese (Traditional): Bruce Chen, Chiayi Yen, Kevin Yang, Winnie Lin, 保哥 Will, 謝政廷
|
||||
* Korean: Do-Kyun Kim, Evelyn Kim, Helen Jung, Hong Jmee, jeongwoo choi, Jun Hyoung Lee, Jungsun Kim정선, Justin Yoo, Kavrith mucha, Kiwoong Youm, MinGyu Ju, MVP_JUNO BEA, Sejun Kim, SOONMAN KWON, sung man ko, Yeongrak Choi, younggun kim, Youngjae Kim, 소영 이
|
||||
* Russian: Andrey Veselov, Anton Fontanov, Anton Savin, Elena Ostrovskaia, Igor Babichev, Maxim Zelensky, Rodion Fedechkin, Tasha T, Vladimir Zyryanov
|
||||
* Portuguese Brazil: Daniel de Sousa, Diogo Duarte, Douglas Correa, Douglas Eccker, José Emanuel Mendes, Marcelo Fernandes, Marcondes Alexandre, Roberto Fonseca, Rodrigo Crespi
|
||||
|
||||
|
||||
And of course we'd like to thank the authors of all upstream dependencies. Please see a full list in the [ThirdPartyNotices.txt](https://raw.githubusercontent.com/Microsoft/sqlopsstudio/master/ThirdPartyNotices.txt)
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ install:
|
||||
build_script:
|
||||
- yarn
|
||||
- .\node_modules\.bin\gulp electron
|
||||
- .\node_modules\.bin\tsc -p .\src\tsconfig.monaco.json --noEmit
|
||||
- npm run compile
|
||||
|
||||
test_script:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "ms-vscode.node-debug",
|
||||
"version": "1.21.8",
|
||||
"version": "1.23.3",
|
||||
"repo": "https://github.com/Microsoft/vscode-node-debug"
|
||||
},
|
||||
{
|
||||
"name": "ms-vscode.node-debug2",
|
||||
"version": "1.21.2",
|
||||
"version": "1.23.5",
|
||||
"repo": "https://github.com/Microsoft/vscode-node-debug2"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
var gulp = require('gulp');
|
||||
var path = require('path');
|
||||
var util = require('./lib/util');
|
||||
var common = require('./lib/optimize');
|
||||
var es = require('event-stream');
|
||||
var File = require('vinyl');
|
||||
const gulp = require('gulp');
|
||||
const path = require('path');
|
||||
const util = require('./lib/util');
|
||||
const common = require('./lib/optimize');
|
||||
const es = require('event-stream');
|
||||
const File = require('vinyl');
|
||||
const i18n = require('./lib/i18n');
|
||||
const standalone = require('./lib/standalone');
|
||||
const cp = require('child_process');
|
||||
|
||||
var root = path.dirname(__dirname);
|
||||
var sha1 = util.getVersion(root);
|
||||
@@ -71,6 +74,8 @@ function editorLoaderConfig() {
|
||||
return result;
|
||||
}
|
||||
|
||||
const languages = i18n.defaultLanguages.concat([]); // i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages : []);
|
||||
|
||||
gulp.task('clean-optimized-editor', util.rimraf('out-editor'));
|
||||
gulp.task('optimize-editor', ['clean-optimized-editor', 'compile-client-build'], common.optimizeTask({
|
||||
entryPoints: editorEntryPoints,
|
||||
@@ -81,14 +86,36 @@ gulp.task('optimize-editor', ['clean-optimized-editor', 'compile-client-build'],
|
||||
header: BUNDLED_FILE_HEADER,
|
||||
bundleInfo: true,
|
||||
out: 'out-editor',
|
||||
languages: undefined
|
||||
languages: languages
|
||||
}));
|
||||
|
||||
gulp.task('clean-minified-editor', util.rimraf('out-editor-min'));
|
||||
gulp.task('minify-editor', ['clean-minified-editor', 'optimize-editor'], common.minifyTask('out-editor'));
|
||||
|
||||
gulp.task('clean-editor-esm', util.rimraf('out-editor-esm'));
|
||||
gulp.task('extract-editor-esm', ['clean-editor-esm', 'clean-editor-distro'], function () {
|
||||
standalone.createESMSourcesAndResources({
|
||||
entryPoints: [
|
||||
'vs/editor/editor.main',
|
||||
'vs/editor/editor.worker'
|
||||
],
|
||||
outFolder: './out-editor-esm/src',
|
||||
outResourcesFolder: './out-monaco-editor-core/esm',
|
||||
redirects: {
|
||||
'vs/base/browser/ui/octiconLabel/octiconLabel': 'vs/base/browser/ui/octiconLabel/octiconLabel.mock',
|
||||
'vs/nls': 'vs/nls.mock',
|
||||
}
|
||||
});
|
||||
});
|
||||
gulp.task('compile-editor-esm', ['extract-editor-esm', 'clean-editor-distro'], function () {
|
||||
const result = cp.spawnSync(`node`, [`../node_modules/.bin/tsc`], {
|
||||
cwd: path.join(__dirname, '../out-editor-esm')
|
||||
});
|
||||
console.log(result.stdout.toString());
|
||||
});
|
||||
|
||||
gulp.task('clean-editor-distro', util.rimraf('out-monaco-editor-core'));
|
||||
gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-editor'], function () {
|
||||
gulp.task('editor-distro', ['clean-editor-distro', 'compile-editor-esm', 'minify-editor', 'optimize-editor'], function () {
|
||||
return es.merge(
|
||||
// other assets
|
||||
es.merge(
|
||||
@@ -97,6 +124,17 @@ gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-ed
|
||||
gulp.src('src/vs/monaco.d.ts')
|
||||
).pipe(gulp.dest('out-monaco-editor-core')),
|
||||
|
||||
// place the .d.ts in the esm folder
|
||||
gulp.src('src/vs/monaco.d.ts')
|
||||
.pipe(es.through(function (data) {
|
||||
this.emit('data', new File({
|
||||
path: data.path.replace(/monaco\.d\.ts/, 'editor.api.d.ts'),
|
||||
base: data.base,
|
||||
contents: data.contents
|
||||
}));
|
||||
}))
|
||||
.pipe(gulp.dest('out-monaco-editor-core/esm/vs/editor')),
|
||||
|
||||
// package.json
|
||||
gulp.src('build/monaco/package.json')
|
||||
.pipe(es.through(function (data) {
|
||||
@@ -208,3 +246,60 @@ function filterStream(testFunc) {
|
||||
this.emit('data', data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//#region monaco type checking
|
||||
|
||||
function createTscCompileTask(watch) {
|
||||
return () => {
|
||||
const createReporter = require('./lib/reporter').createReporter;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const args = ['./node_modules/.bin/tsc', '-p', './src/tsconfig.monaco.json', '--noEmit'];
|
||||
if (watch) {
|
||||
args.push('-w');
|
||||
}
|
||||
const child = cp.spawn(`node`, args, {
|
||||
cwd: path.join(__dirname, '..'),
|
||||
// stdio: [null, 'pipe', 'inherit']
|
||||
});
|
||||
let errors = [];
|
||||
let reporter = createReporter();
|
||||
let report;
|
||||
let magic = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; // https://stackoverflow.com/questions/25245716/remove-all-ansi-colors-styles-from-strings
|
||||
|
||||
child.stdout.on('data', data => {
|
||||
let str = String(data);
|
||||
str = str.replace(magic, '').trim();
|
||||
if (str.indexOf('Starting compilation') >= 0 || str.indexOf('File change detected') >= 0) {
|
||||
errors.length = 0;
|
||||
report = reporter.end(false);
|
||||
|
||||
} else if (str.indexOf('Compilation complete') >= 0) {
|
||||
report.end();
|
||||
|
||||
} else if (str) {
|
||||
let match = /(.*\(\d+,\d+\): )(.*: )(.*)/.exec(str);
|
||||
if (match) {
|
||||
// trying to massage the message so that it matches the gulp-tsb error messages
|
||||
// e.g. src/vs/base/common/strings.ts(663,5): error TS2322: Type '1234' is not assignable to type 'string'.
|
||||
let fullpath = path.join(root, match[1]);
|
||||
let message = match[3];
|
||||
// @ts-ignore
|
||||
reporter(fullpath + message);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
reporter(str);
|
||||
}
|
||||
}
|
||||
});
|
||||
child.on('exit', resolve);
|
||||
child.on('error', reject);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
gulp.task('monaco-typecheck-watch', createTscCompileTask(true));
|
||||
gulp.task('monaco-typecheck', createTscCompileTask(false));
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -21,6 +21,7 @@ const nlsDev = require('vscode-nls-dev');
|
||||
const root = path.dirname(__dirname);
|
||||
const commit = util.getVersion(root);
|
||||
const i18n = require('./lib/i18n');
|
||||
const plumber = require('gulp-plumber');
|
||||
|
||||
const extensionsPath = path.join(path.dirname(__dirname), 'extensions');
|
||||
|
||||
@@ -82,6 +83,13 @@ const tasks = compilations.map(function (tsconfigFile) {
|
||||
const input = es.through();
|
||||
const tsFilter = filter(['**/*.ts', '!**/lib/lib*.d.ts', '!**/node_modules/**'], { restore: true });
|
||||
const output = input
|
||||
.pipe(plumber({
|
||||
errorHandler: function (err) {
|
||||
if (err && !err.__reporter__) {
|
||||
reporter(err);
|
||||
}
|
||||
}
|
||||
}))
|
||||
.pipe(tsFilter)
|
||||
.pipe(util.loadSourcemaps())
|
||||
.pipe(compilation())
|
||||
|
||||
@@ -46,10 +46,9 @@ const indentationFilter = [
|
||||
'!src/vs/nls.js',
|
||||
'!src/vs/css.js',
|
||||
'!src/vs/loader.js',
|
||||
'!src/vs/base/common/marked/raw.marked.js',
|
||||
'!src/vs/base/common/winjs.base.raw.js',
|
||||
'!src/vs/base/common/marked/marked.js',
|
||||
'!src/vs/base/common/winjs.base.js',
|
||||
'!src/vs/base/node/terminateProcess.sh',
|
||||
'!src/vs/base/node/ps-win.ps1',
|
||||
'!test/assert.js',
|
||||
|
||||
// except specific folders
|
||||
@@ -62,6 +61,7 @@ const indentationFilter = [
|
||||
// except multiple specific files
|
||||
'!**/package.json',
|
||||
'!**/yarn.lock',
|
||||
'!**/yarn-error.log',
|
||||
|
||||
// except multiple specific folders
|
||||
'!**/octicons/**',
|
||||
@@ -104,8 +104,9 @@ const copyrightFilter = [
|
||||
'!build/**/*.init',
|
||||
'!resources/linux/snap/snapcraft.yaml',
|
||||
'!resources/win32/bin/code.js',
|
||||
'!extensions/markdown/media/tomorrow.css',
|
||||
'!extensions/html/server/src/modes/typescript/*'
|
||||
'!extensions/markdown-language-features/media/tomorrow.css',
|
||||
'!extensions/html-language-features/server/src/modes/typescript/*',
|
||||
'!extensions/*/server/bin/*'
|
||||
];
|
||||
|
||||
const eslintFilter = [
|
||||
@@ -116,8 +117,8 @@ const eslintFilter = [
|
||||
'!src/vs/nls.js',
|
||||
'!src/vs/css.build.js',
|
||||
'!src/vs/nls.build.js',
|
||||
'!src/**/winjs.base.raw.js',
|
||||
'!src/**/raw.marked.js',
|
||||
'!src/**/winjs.base.js',
|
||||
'!src/**/marked.js',
|
||||
'!**/test/**'
|
||||
];
|
||||
|
||||
@@ -132,15 +133,15 @@ const tslintFilter = [
|
||||
'!extensions/vscode-api-tests/testWorkspace/**',
|
||||
'!extensions/vscode-api-tests/testWorkspace2/**',
|
||||
'!extensions/**/*.test.ts',
|
||||
'!extensions/html/server/lib/jquery.d.ts'
|
||||
'!extensions/html-language-features/server/lib/jquery.d.ts'
|
||||
];
|
||||
|
||||
const copyrightHeader = [
|
||||
const copyrightHeaderLines = [
|
||||
'/*---------------------------------------------------------------------------------------------',
|
||||
' * Copyright (c) Microsoft Corporation. All rights reserved.',
|
||||
' * Licensed under the Source EULA. See License.txt in the project root for license information.',
|
||||
' *--------------------------------------------------------------------------------------------*/'
|
||||
].join('\n');
|
||||
];
|
||||
|
||||
gulp.task('eslint', () => {
|
||||
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
|
||||
@@ -202,12 +203,17 @@ function hygiene(some) {
|
||||
tsfmt.processString(file.path, file.contents.toString('utf8'), {
|
||||
verify: false,
|
||||
tsfmt: true,
|
||||
// verbose: true
|
||||
// verbose: true,
|
||||
// keep checkJS happy
|
||||
editorconfig: undefined,
|
||||
replace: undefined,
|
||||
tsconfig: undefined,
|
||||
tslint: undefined
|
||||
tsconfigFile: undefined,
|
||||
tslint: undefined,
|
||||
tslintFile: undefined,
|
||||
tsfmtFile: undefined,
|
||||
vscode: undefined,
|
||||
vscodeFile: undefined
|
||||
}).then(result => {
|
||||
let original = result.src.replace(/\r\n/gm, '\n');
|
||||
let formatted = result.dest.replace(/\r\n/gm, '\n');
|
||||
|
||||
@@ -37,9 +37,9 @@ gulp.task('mixin', function () {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
let serviceUrl = 'https://raw.githubusercontent.com/Microsoft/sqlopsstudio/release/extensions/extensionsGallery.json';
|
||||
let serviceUrl = 'https://sqlopsextensions.blob.core.windows.net/marketplace/v1/extensionsGallery.json';
|
||||
if (quality === 'insider') {
|
||||
serviceUrl = `https://raw.githubusercontent.com/Microsoft/sqlopsstudio/release/extensions/extensionsGallery-${quality}.json`;
|
||||
serviceUrl = `https://sqlopsextensions.blob.core.windows.net/marketplace/v1/extensionsGallery-${quality}.json`;
|
||||
}
|
||||
let newValues = {
|
||||
"updateUrl": updateUrl,
|
||||
|
||||
@@ -77,7 +77,9 @@ const vsce = require('vsce');
|
||||
const sqlBuiltInExtensions = [
|
||||
// Add SQL built-in extensions here.
|
||||
// the extension will be excluded from SQLOps package and will have separate vsix packages
|
||||
'agent'
|
||||
'agent',
|
||||
'import',
|
||||
'profiler'
|
||||
];
|
||||
|
||||
const vscodeEntryPoints = _.flatten([
|
||||
@@ -90,18 +92,19 @@ const vscodeEntryPoints = _.flatten([
|
||||
const vscodeResources = [
|
||||
'out-build/main.js',
|
||||
'out-build/cli.js',
|
||||
'out-build/driver.js',
|
||||
'out-build/bootstrap.js',
|
||||
'out-build/bootstrap-amd.js',
|
||||
'out-build/paths.js',
|
||||
'out-build/vs/**/*.{svg,png,cur,html}',
|
||||
'out-build/vs/base/common/performance.js',
|
||||
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,ps-win.ps1}',
|
||||
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh}',
|
||||
'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
|
||||
'out-build/vs/workbench/browser/media/*-theme.css',
|
||||
'out-build/vs/workbench/electron-browser/bootstrap/**',
|
||||
'out-build/vs/workbench/parts/debug/**/*.json',
|
||||
'out-build/vs/workbench/parts/execution/**/*.scpt',
|
||||
'out-build/vs/workbench/parts/html/browser/webview-pre.js',
|
||||
'out-build/vs/workbench/parts/webview/electron-browser/webview-pre.js',
|
||||
'out-build/vs/**/markdown.css',
|
||||
'out-build/vs/workbench/parts/tasks/**/*.json',
|
||||
'out-build/vs/workbench/parts/terminal/electron-browser/terminalProcess.js',
|
||||
@@ -110,6 +113,7 @@ const vscodeResources = [
|
||||
'out-build/vs/workbench/services/files/**/*.md',
|
||||
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
||||
'out-build/vs/code/electron-browser/issue/issueReporter.js',
|
||||
'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
|
||||
// {{SQL CARBON EDIT}}
|
||||
'out-build/sql/workbench/electron-browser/splashscreen/*',
|
||||
'out-build/sql/**/*.{svg,png,cur,html}',
|
||||
@@ -270,7 +274,8 @@ function packageBuiltInExtensions() {
|
||||
console.info('Creating vsix for ' + element.path + ' result:' + packagePath);
|
||||
vsce.createVSIX({
|
||||
cwd: element.path,
|
||||
packagePath: packagePath
|
||||
packagePath: packagePath,
|
||||
useYarn: true
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -347,7 +352,7 @@ function packageTask(platform, arch, opts) {
|
||||
const packageJsonStream = gulp.src(['package.json'], { base: '.' })
|
||||
.pipe(json({ name, version }));
|
||||
|
||||
const settingsSearchBuildId = getBuildNumber();
|
||||
const settingsSearchBuildId = getSettingsSearchBuildId(packageJson);
|
||||
const date = new Date().toISOString();
|
||||
const productJsonStream = gulp.src(['product.json'], { base: '.' })
|
||||
.pipe(json({ commit, date, checksums, settingsSearchBuildId }));
|
||||
@@ -389,6 +394,7 @@ function packageTask(platform, arch, opts) {
|
||||
.pipe(util.cleanNodeModule('core-js', ['**/**'], undefined))
|
||||
.pipe(util.cleanNodeModule('slickgrid', ['node_modules/**', 'examples/**'], undefined))
|
||||
.pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a']))
|
||||
.pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a']))
|
||||
.pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']))
|
||||
.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar'));
|
||||
|
||||
@@ -540,9 +546,11 @@ gulp.task('vscode-translations-import', function () {
|
||||
gulp.src(`../vscode-localization/${language.id}/build/*/*.xlf`)
|
||||
.pipe(i18n.prepareI18nFiles())
|
||||
.pipe(vfs.dest(`./i18n/${language.folderName}`));
|
||||
gulp.src(`../vscode-localization/${language.id}/setup/*/*.xlf`)
|
||||
.pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id]))
|
||||
.pipe(vfs.dest(`./build/win32/i18n`));
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// gulp.src(`../vscode-localization/${language.id}/setup/*/*.xlf`)
|
||||
// .pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id]))
|
||||
// .pipe(vfs.dest(`./build/win32/i18n`));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -576,14 +584,12 @@ gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () =
|
||||
}
|
||||
|
||||
if (!fs.existsSync(allConfigDetailsPath)) {
|
||||
console.error(`configuration file at ${allConfigDetailsPath} does not exist`);
|
||||
return;
|
||||
throw new Error(`configuration file at ${allConfigDetailsPath} does not exist`);
|
||||
}
|
||||
|
||||
const settingsSearchBuildId = getBuildNumber();
|
||||
const settingsSearchBuildId = getSettingsSearchBuildId(packageJson);
|
||||
if (!settingsSearchBuildId) {
|
||||
console.error('Failed to compute build number');
|
||||
return;
|
||||
throw new Error('Failed to compute build number');
|
||||
}
|
||||
|
||||
return gulp.src(allConfigDetailsPath)
|
||||
@@ -595,76 +601,18 @@ gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () =
|
||||
}));
|
||||
});
|
||||
|
||||
function getBuildNumber() {
|
||||
const previous = getPreviousVersion(packageJson.version);
|
||||
if (!previous) {
|
||||
return 0;
|
||||
}
|
||||
function getSettingsSearchBuildId(packageJson) {
|
||||
const previous = util.getPreviousVersion(packageJson.version);
|
||||
|
||||
try {
|
||||
const out = cp.execSync(`git rev-list ${previous}..HEAD --count`);
|
||||
const count = parseInt(out.toString());
|
||||
return versionStringToNumber(packageJson.version) * 1e4 + count;
|
||||
return util.versionStringToNumber(packageJson.version) * 1e4 + count;
|
||||
} catch (e) {
|
||||
console.error('Could not determine build number: ' + e.toString());
|
||||
return 0;
|
||||
throw new Error('Could not determine build number: ' + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given 1.17.2, return 1.17.1
|
||||
* 1.18.0 => 1.17.2.
|
||||
* 2.0.0 => 1.18.0 (or the highest 1.x)
|
||||
*/
|
||||
function getPreviousVersion(versionStr) {
|
||||
function tagExists(tagName) {
|
||||
try {
|
||||
cp.execSync(`git rev-parse ${tagName}`, { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getLastTagFromBase(semverArr, componentToTest) {
|
||||
const baseVersion = semverArr.join('.');
|
||||
if (!tagExists(baseVersion)) {
|
||||
console.error('Failed to find tag for base version, ' + baseVersion);
|
||||
return null;
|
||||
}
|
||||
|
||||
let goodTag;
|
||||
do {
|
||||
goodTag = semverArr.join('.');
|
||||
semverArr[componentToTest]++;
|
||||
} while (tagExists(semverArr.join('.')));
|
||||
|
||||
return goodTag;
|
||||
}
|
||||
|
||||
const semverArr = versionStr.split('.');
|
||||
if (semverArr[2] > 0) {
|
||||
semverArr[2]--;
|
||||
return semverArr.join('.');
|
||||
} else if (semverArr[1] > 0) {
|
||||
semverArr[1]--;
|
||||
return getLastTagFromBase(semverArr, 2);
|
||||
} else {
|
||||
semverArr[0]--;
|
||||
return getLastTagFromBase(semverArr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function versionStringToNumber(versionStr) {
|
||||
const semverRegex = /(\d+)\.(\d+)\.(\d+)/;
|
||||
const match = versionStr.match(semverRegex);
|
||||
if (!match) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10);
|
||||
}
|
||||
|
||||
// This task is only run for the MacOS build
|
||||
gulp.task('generate-vscode-configuration', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -696,9 +644,6 @@ gulp.task('generate-vscode-configuration', () => {
|
||||
clearTimeout(timer);
|
||||
reject(err);
|
||||
});
|
||||
}).catch(e => {
|
||||
// Don't fail the build
|
||||
console.error(e.toString());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -21,29 +21,6 @@ const rpmDependencies = require('../resources/linux/rpm/dependencies.json');
|
||||
|
||||
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
const flatpakManifest = {
|
||||
appId: product.darwinBundleIdentifier, // We need a reverse-url style identifier.
|
||||
sdk: 'org.freedesktop.Sdk',
|
||||
runtime: 'org.freedesktop.Sdk',
|
||||
runtimeVersion: '1.4',
|
||||
base: 'io.atom.electron.BaseApp',
|
||||
baseFlatpakref: 'https://s3-us-west-2.amazonaws.com/electron-flatpak.endlessm.com/electron-base-app-master.flatpakref',
|
||||
command: product.applicationName,
|
||||
symlinks: [
|
||||
['/share/' + product.applicationName + '/bin/' + product.applicationName, '/bin/' + product.applicationName],
|
||||
],
|
||||
finishArgs: [
|
||||
'--share=ipc', '--socket=x11', // Allow showing X11 windows.
|
||||
'--share=network', // Network access (e.g. for installing extension).
|
||||
'--filesystem=host', // Allow access to the whole file system.
|
||||
'--device=dri', // Allow OpenGL rendering.
|
||||
'--filesystem=/tmp', // Needed for Chromium's single instance check.
|
||||
'--socket=pulseaudio', // Some extensions may want to play sounds...
|
||||
'--talk-name=org.freedesktop.Notifications', // ...or pop up notifications.
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
function getDebPackageArch(arch) {
|
||||
return { x64: 'amd64', ia32: 'i386', arm: 'armhf' }[arch];
|
||||
}
|
||||
@@ -336,10 +313,3 @@ gulp.task('vscode-linux-arm-prepare-snap', ['clean-vscode-linux-arm-snap'], prep
|
||||
gulp.task('vscode-linux-ia32-build-snap', ['vscode-linux-ia32-prepare-snap'], buildSnapPackage('ia32'));
|
||||
gulp.task('vscode-linux-x64-build-snap', ['vscode-linux-x64-prepare-snap'], buildSnapPackage('x64'));
|
||||
gulp.task('vscode-linux-arm-build-snap', ['vscode-linux-arm-prepare-snap'], buildSnapPackage('arm'));
|
||||
|
||||
gulp.task('vscode-linux-ia32-prepare-flatpak', ['clean-vscode-linux-ia32-flatpak'], prepareFlatpak('ia32'));
|
||||
gulp.task('vscode-linux-x64-prepare-flatpak', ['clean-vscode-linux-x64-flatpak'], prepareFlatpak('x64'));
|
||||
gulp.task('vscode-linux-arm-prepare-flatpak', ['clean-vscode-linux-arm-flatpak'], prepareFlatpak('arm'));
|
||||
gulp.task('vscode-linux-ia32-flatpak', ['vscode-linux-ia32-prepare-flatpak'], buildFlatpak('ia32'));
|
||||
gulp.task('vscode-linux-x64-flatpak', ['vscode-linux-x64-prepare-flatpak'], buildFlatpak('x64'));
|
||||
gulp.task('vscode-linux-arm-flatpak', ['vscode-linux-arm-prepare-flatpak'], buildFlatpak('arm'));
|
||||
|
||||
@@ -22,11 +22,12 @@ var rootDir = path.join(__dirname, '../../src');
|
||||
var options = require('../../src/tsconfig.json').compilerOptions;
|
||||
options.verbose = false;
|
||||
options.sourceMap = true;
|
||||
if (process.env['VSCODE_NO_SOURCEMAP']) {
|
||||
if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry
|
||||
options.sourceMap = false;
|
||||
}
|
||||
options.rootDir = rootDir;
|
||||
options.sourceRoot = util.toFileUri(rootDir);
|
||||
options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF';
|
||||
function createCompile(build, emitError) {
|
||||
var opts = _.clone(options);
|
||||
opts.inlineSources = !!build;
|
||||
|
||||
@@ -30,6 +30,7 @@ if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry
|
||||
}
|
||||
options.rootDir = rootDir;
|
||||
options.sourceRoot = util.toFileUri(rootDir);
|
||||
options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF';
|
||||
|
||||
function createCompile(build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream {
|
||||
const opts = _.clone(options);
|
||||
|
||||
@@ -527,6 +527,7 @@ function getResource(sourceFile) {
|
||||
else if (/^vs\/workbench/.test(sourceFile)) {
|
||||
return { name: 'vs/workbench', project: workbenchProject };
|
||||
}
|
||||
// {{SQL CARBON EDIT}}
|
||||
else if (/^sql/.test(sourceFile)) {
|
||||
return { name: 'sql', project: sqlopsProject };
|
||||
}
|
||||
@@ -1051,7 +1052,10 @@ function createI18nFile(originalFilePath, messages) {
|
||||
var key = _a[_i];
|
||||
result[key] = messages[key];
|
||||
}
|
||||
var content = JSON.stringify(result, null, '\t').replace(/\r\n/g, '\n');
|
||||
var content = JSON.stringify(result, null, '\t');
|
||||
if (process.platform === 'win32') {
|
||||
content = content.replace(/\n/g, '\r\n');
|
||||
}
|
||||
return new File({
|
||||
path: path.join(originalFilePath + '.i18n.json'),
|
||||
contents: Buffer.from(content, 'utf8')
|
||||
@@ -1085,7 +1089,7 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse
|
||||
extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} };
|
||||
}
|
||||
var externalId = externalExtensions[resource];
|
||||
if (!externalId) {
|
||||
if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent
|
||||
var secondSlash = path.indexOf('/', firstSlash + 1);
|
||||
extPack.contents[path.substr(secondSlash + 1)] = file.messages;
|
||||
}
|
||||
|
||||
@@ -130,10 +130,18 @@
|
||||
"name": "vs/workbench/parts/update",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/url",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/watermark",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/webview",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/parts/welcome",
|
||||
"project": "vscode-workbench"
|
||||
@@ -146,6 +154,10 @@
|
||||
"name": "vs/workbench/services/configuration",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/configurationResolver",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/crashReporter",
|
||||
"project": "vscode-workbench"
|
||||
@@ -201,6 +213,10 @@
|
||||
{
|
||||
"name": "vs/workbench/services/decorations",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/preferences",
|
||||
"project": "vscode-preferences"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1179,7 +1179,10 @@ function createI18nFile(originalFilePath: string, messages: any): File {
|
||||
result[key] = messages[key];
|
||||
}
|
||||
|
||||
let content = JSON.stringify(result, null, '\t').replace(/\r\n/g, '\n');
|
||||
let content = JSON.stringify(result, null, '\t');
|
||||
if (process.platform === 'win32') {
|
||||
content = content.replace(/\n/g, '\r\n');
|
||||
}
|
||||
return new File({
|
||||
path: path.join(originalFilePath + '.i18n.json'),
|
||||
contents: Buffer.from(content, 'utf8')
|
||||
|
||||
@@ -150,13 +150,16 @@ function isImportNode(node) {
|
||||
.filter(function (d) { return d.importClause.namedBindings.kind === ts.SyntaxKind.NamespaceImport; })
|
||||
.map(function (d) { return d.importClause.namedBindings.name; })
|
||||
.concat(importEqualsDeclarations.map(function (d) { return d.name; }))
|
||||
// find read-only references to `nls`
|
||||
.map(function (n) { return service.getReferencesAtPosition(filename, n.pos + 1); })
|
||||
.flatten()
|
||||
.filter(function (r) { return !r.isWriteAccess; })
|
||||
// find the deepest call expressions AST nodes that contain those references
|
||||
.map(function (r) { return collect(sourceFile, function (n) { return isCallExpressionWithinTextSpanCollectStep(r.textSpan, n); }); })
|
||||
.map(function (a) { return lazy(a).last(); })
|
||||
.filter(function (n) { return !!n; })
|
||||
.map(function (n) { return n; })
|
||||
// only `localize` calls
|
||||
.filter(function (n) { return n.expression.kind === ts.SyntaxKind.PropertyAccessExpression && n.expression.name.getText() === 'localize'; });
|
||||
// `localize` named imports
|
||||
var allLocalizeImportDeclarations = importDeclarations
|
||||
|
||||
@@ -34,7 +34,13 @@ catch (err) {
|
||||
}
|
||||
function log() {
|
||||
var errors = _.flatten(allErrors);
|
||||
errors.map(function (err) { return util.log(util.colors.red('Error') + ": " + err); });
|
||||
var seen = new Set();
|
||||
errors.map(function (err) {
|
||||
if (!seen.has(err)) {
|
||||
seen.add(err);
|
||||
util.log(util.colors.red('Error') + ": " + err);
|
||||
}
|
||||
});
|
||||
var regex = /^([^(]+)\((\d+),(\d+)\): (.*)$/;
|
||||
var messages = errors
|
||||
.map(function (err) { return regex.exec(err); })
|
||||
@@ -67,8 +73,13 @@ function createReporter() {
|
||||
return es.through(null, function () {
|
||||
onEnd();
|
||||
if (emitError && errors.length > 0) {
|
||||
log();
|
||||
this.emit('error');
|
||||
errors.__logged__ = true;
|
||||
if (!errors.__logged__) {
|
||||
log();
|
||||
}
|
||||
var err = new Error("Found " + errors.length + " errors");
|
||||
err.__reporter__ = true;
|
||||
this.emit('error', err);
|
||||
}
|
||||
else {
|
||||
this.emit('end');
|
||||
@@ -80,4 +91,3 @@ function createReporter() {
|
||||
return ReportFunc;
|
||||
}
|
||||
exports.createReporter = createReporter;
|
||||
;
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as util from 'gulp-util';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const allErrors: Error[][] = [];
|
||||
const allErrors: string[][] = [];
|
||||
let startTime: number = null;
|
||||
let count = 0;
|
||||
|
||||
@@ -42,7 +42,14 @@ try {
|
||||
|
||||
function log(): void {
|
||||
const errors = _.flatten(allErrors);
|
||||
errors.map(err => util.log(`${util.colors.red('Error')}: ${err}`));
|
||||
const seen = new Set<string>();
|
||||
|
||||
errors.map(err => {
|
||||
if (!seen.has(err)) {
|
||||
seen.add(err);
|
||||
util.log(`${util.colors.red('Error')}: ${err}`);
|
||||
}
|
||||
});
|
||||
|
||||
const regex = /^([^(]+)\((\d+),(\d+)\): (.*)$/;
|
||||
const messages = errors
|
||||
@@ -61,17 +68,17 @@ function log(): void {
|
||||
}
|
||||
|
||||
export interface IReporter {
|
||||
(err: Error): void;
|
||||
(err: string): void;
|
||||
hasErrors(): boolean;
|
||||
end(emitError: boolean): NodeJS.ReadWriteStream;
|
||||
}
|
||||
|
||||
export function createReporter(): IReporter {
|
||||
const errors: Error[] = [];
|
||||
const errors: string[] = [];
|
||||
allErrors.push(errors);
|
||||
|
||||
class ReportFunc {
|
||||
constructor(err: Error) {
|
||||
constructor(err: string) {
|
||||
errors.push(err);
|
||||
}
|
||||
|
||||
@@ -87,8 +94,15 @@ export function createReporter(): IReporter {
|
||||
onEnd();
|
||||
|
||||
if (emitError && errors.length > 0) {
|
||||
log();
|
||||
this.emit('error');
|
||||
(errors as any).__logged__ = true;
|
||||
|
||||
if (!(errors as any).__logged__) {
|
||||
log();
|
||||
}
|
||||
|
||||
const err = new Error(`Found ${errors.length} errors`);
|
||||
(err as any).__reporter__ = true;
|
||||
this.emit('error', err);
|
||||
} else {
|
||||
this.emit('end');
|
||||
}
|
||||
@@ -97,4 +111,4 @@ export function createReporter(): IReporter {
|
||||
}
|
||||
|
||||
return <IReporter><any>ReportFunc;
|
||||
};
|
||||
}
|
||||
|
||||
265
build/lib/standalone.js
Normal file
265
build/lib/standalone.js
Normal file
@@ -0,0 +1,265 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var ts = require("typescript");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var REPO_ROOT = path.join(__dirname, '../../');
|
||||
var SRC_DIR = path.join(REPO_ROOT, 'src');
|
||||
var OUT_EDITOR = path.join(REPO_ROOT, 'out-editor');
|
||||
function createESMSourcesAndResources(options) {
|
||||
var OUT_FOLDER = path.join(REPO_ROOT, options.outFolder);
|
||||
var OUT_RESOURCES_FOLDER = path.join(REPO_ROOT, options.outResourcesFolder);
|
||||
var in_queue = Object.create(null);
|
||||
var queue = [];
|
||||
var enqueue = function (module) {
|
||||
if (in_queue[module]) {
|
||||
return;
|
||||
}
|
||||
in_queue[module] = true;
|
||||
queue.push(module);
|
||||
};
|
||||
var seenDir = {};
|
||||
var createDirectoryRecursive = function (dir) {
|
||||
if (seenDir[dir]) {
|
||||
return;
|
||||
}
|
||||
var lastSlash = dir.lastIndexOf('/');
|
||||
if (lastSlash === -1) {
|
||||
lastSlash = dir.lastIndexOf('\\');
|
||||
}
|
||||
if (lastSlash !== -1) {
|
||||
createDirectoryRecursive(dir.substring(0, lastSlash));
|
||||
}
|
||||
seenDir[dir] = true;
|
||||
try {
|
||||
fs.mkdirSync(dir);
|
||||
}
|
||||
catch (err) { }
|
||||
};
|
||||
seenDir[REPO_ROOT] = true;
|
||||
var toggleComments = function (fileContents) {
|
||||
var lines = fileContents.split(/\r\n|\r|\n/);
|
||||
var mode = 0;
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
if (mode === 0) {
|
||||
if (/\/\/ ESM-comment-begin/.test(line)) {
|
||||
mode = 1;
|
||||
continue;
|
||||
}
|
||||
if (/\/\/ ESM-uncomment-begin/.test(line)) {
|
||||
mode = 2;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mode === 1) {
|
||||
if (/\/\/ ESM-comment-end/.test(line)) {
|
||||
mode = 0;
|
||||
continue;
|
||||
}
|
||||
lines[i] = '// ' + line;
|
||||
continue;
|
||||
}
|
||||
if (mode === 2) {
|
||||
if (/\/\/ ESM-uncomment-end/.test(line)) {
|
||||
mode = 0;
|
||||
continue;
|
||||
}
|
||||
lines[i] = line.replace(/^(\s*)\/\/ ?/, function (_, indent) {
|
||||
return indent;
|
||||
});
|
||||
}
|
||||
}
|
||||
return lines.join('\n');
|
||||
};
|
||||
var write = function (filePath, contents) {
|
||||
var absoluteFilePath;
|
||||
if (/\.ts$/.test(filePath)) {
|
||||
absoluteFilePath = path.join(OUT_FOLDER, filePath);
|
||||
}
|
||||
else {
|
||||
absoluteFilePath = path.join(OUT_RESOURCES_FOLDER, filePath);
|
||||
}
|
||||
createDirectoryRecursive(path.dirname(absoluteFilePath));
|
||||
if (/(\.ts$)|(\.js$)/.test(filePath)) {
|
||||
contents = toggleComments(contents.toString());
|
||||
}
|
||||
fs.writeFileSync(absoluteFilePath, contents);
|
||||
};
|
||||
options.entryPoints.forEach(function (entryPoint) { return enqueue(entryPoint); });
|
||||
while (queue.length > 0) {
|
||||
var module_1 = queue.shift();
|
||||
if (transportCSS(options, module_1, enqueue, write)) {
|
||||
continue;
|
||||
}
|
||||
if (transportResource(options, module_1, enqueue, write)) {
|
||||
continue;
|
||||
}
|
||||
if (transportDTS(options, module_1, enqueue, write)) {
|
||||
continue;
|
||||
}
|
||||
var filename = void 0;
|
||||
if (options.redirects[module_1]) {
|
||||
filename = path.join(SRC_DIR, options.redirects[module_1] + '.ts');
|
||||
}
|
||||
else {
|
||||
filename = path.join(SRC_DIR, module_1 + '.ts');
|
||||
}
|
||||
var fileContents = fs.readFileSync(filename).toString();
|
||||
var info = ts.preProcessFile(fileContents);
|
||||
for (var i = info.importedFiles.length - 1; i >= 0; i--) {
|
||||
var importedFilename = info.importedFiles[i].fileName;
|
||||
var pos = info.importedFiles[i].pos;
|
||||
var end = info.importedFiles[i].end;
|
||||
var importedFilepath = void 0;
|
||||
if (/^vs\/css!/.test(importedFilename)) {
|
||||
importedFilepath = importedFilename.substr('vs/css!'.length) + '.css';
|
||||
}
|
||||
else {
|
||||
importedFilepath = importedFilename;
|
||||
}
|
||||
if (/(^\.\/)|(^\.\.\/)/.test(importedFilepath)) {
|
||||
importedFilepath = path.join(path.dirname(module_1), importedFilepath);
|
||||
}
|
||||
enqueue(importedFilepath);
|
||||
var relativePath = void 0;
|
||||
if (importedFilepath === path.dirname(module_1)) {
|
||||
relativePath = '../' + path.basename(path.dirname(module_1));
|
||||
}
|
||||
else if (importedFilepath === path.dirname(path.dirname(module_1))) {
|
||||
relativePath = '../../' + path.basename(path.dirname(path.dirname(module_1)));
|
||||
}
|
||||
else {
|
||||
relativePath = path.relative(path.dirname(module_1), importedFilepath);
|
||||
}
|
||||
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
|
||||
relativePath = './' + relativePath;
|
||||
}
|
||||
fileContents = (fileContents.substring(0, pos + 1)
|
||||
+ relativePath
|
||||
+ fileContents.substring(end + 1));
|
||||
}
|
||||
fileContents = fileContents.replace(/import ([a-zA-z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) {
|
||||
return "import * as " + m1 + " from " + m2 + ";";
|
||||
});
|
||||
fileContents = fileContents.replace(/Thenable/g, 'PromiseLike');
|
||||
write(module_1 + '.ts', fileContents);
|
||||
}
|
||||
var esm_opts = {
|
||||
"compilerOptions": {
|
||||
"outDir": path.relative(path.dirname(OUT_FOLDER), OUT_RESOURCES_FOLDER),
|
||||
"rootDir": "src",
|
||||
"module": "es6",
|
||||
"target": "es5",
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es5",
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
],
|
||||
"types": []
|
||||
}
|
||||
};
|
||||
fs.writeFileSync(path.join(path.dirname(OUT_FOLDER), 'tsconfig.json'), JSON.stringify(esm_opts, null, '\t'));
|
||||
var monacodts = fs.readFileSync(path.join(SRC_DIR, 'vs/monaco.d.ts')).toString();
|
||||
fs.writeFileSync(path.join(OUT_FOLDER, 'vs/monaco.d.ts'), monacodts);
|
||||
}
|
||||
exports.createESMSourcesAndResources = createESMSourcesAndResources;
|
||||
function transportCSS(options, module, enqueue, write) {
|
||||
if (!/\.css/.test(module)) {
|
||||
return false;
|
||||
}
|
||||
var filename = path.join(SRC_DIR, module);
|
||||
var fileContents = fs.readFileSync(filename).toString();
|
||||
var inlineResources = 'base64'; // see https://github.com/Microsoft/monaco-editor/issues/148
|
||||
var inlineResourcesLimit = 300000; //3000; // see https://github.com/Microsoft/monaco-editor/issues/336
|
||||
var newContents = _rewriteOrInlineUrls(filename, fileContents, inlineResources === 'base64', inlineResourcesLimit);
|
||||
write(module, newContents);
|
||||
return true;
|
||||
function _rewriteOrInlineUrls(originalFileFSPath, contents, forceBase64, inlineByteLimit) {
|
||||
return _replaceURL(contents, function (url) {
|
||||
var imagePath = path.join(path.dirname(module), url);
|
||||
var fileContents = fs.readFileSync(path.join(SRC_DIR, imagePath));
|
||||
if (fileContents.length < inlineByteLimit) {
|
||||
var MIME = /\.svg$/.test(url) ? 'image/svg+xml' : 'image/png';
|
||||
var DATA = ';base64,' + fileContents.toString('base64');
|
||||
if (!forceBase64 && /\.svg$/.test(url)) {
|
||||
// .svg => url encode as explained at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
|
||||
var newText = fileContents.toString()
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/</g, '%3C')
|
||||
.replace(/>/g, '%3E')
|
||||
.replace(/&/g, '%26')
|
||||
.replace(/#/g, '%23')
|
||||
.replace(/\s+/g, ' ');
|
||||
var encodedData = ',' + newText;
|
||||
if (encodedData.length < DATA.length) {
|
||||
DATA = encodedData;
|
||||
}
|
||||
}
|
||||
return '"data:' + MIME + DATA + '"';
|
||||
}
|
||||
enqueue(imagePath);
|
||||
return url;
|
||||
});
|
||||
}
|
||||
function _replaceURL(contents, replacer) {
|
||||
// Use ")" as the terminator as quotes are oftentimes not used at all
|
||||
return contents.replace(/url\(\s*([^\)]+)\s*\)?/g, function (_) {
|
||||
var matches = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
matches[_i - 1] = arguments[_i];
|
||||
}
|
||||
var url = matches[0];
|
||||
// Eliminate starting quotes (the initial whitespace is not captured)
|
||||
if (url.charAt(0) === '"' || url.charAt(0) === '\'') {
|
||||
url = url.substring(1);
|
||||
}
|
||||
// The ending whitespace is captured
|
||||
while (url.length > 0 && (url.charAt(url.length - 1) === ' ' || url.charAt(url.length - 1) === '\t')) {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
// Eliminate ending quotes
|
||||
if (url.charAt(url.length - 1) === '"' || url.charAt(url.length - 1) === '\'') {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
if (!_startsWith(url, 'data:') && !_startsWith(url, 'http://') && !_startsWith(url, 'https://')) {
|
||||
url = replacer(url);
|
||||
}
|
||||
return 'url(' + url + ')';
|
||||
});
|
||||
}
|
||||
function _startsWith(haystack, needle) {
|
||||
return haystack.length >= needle.length && haystack.substr(0, needle.length) === needle;
|
||||
}
|
||||
}
|
||||
function transportResource(options, module, enqueue, write) {
|
||||
if (!/\.svg/.test(module)) {
|
||||
return false;
|
||||
}
|
||||
write(module, fs.readFileSync(path.join(SRC_DIR, module)));
|
||||
return true;
|
||||
}
|
||||
function transportDTS(options, module, enqueue, write) {
|
||||
if (options.redirects[module] && fs.existsSync(path.join(SRC_DIR, options.redirects[module] + '.ts'))) {
|
||||
return false;
|
||||
}
|
||||
if (!fs.existsSync(path.join(SRC_DIR, module + '.d.ts'))) {
|
||||
return false;
|
||||
}
|
||||
write(module + '.d.ts', fs.readFileSync(path.join(SRC_DIR, module + '.d.ts')));
|
||||
var filename;
|
||||
if (options.redirects[module]) {
|
||||
write(module + '.js', fs.readFileSync(path.join(SRC_DIR, options.redirects[module] + '.js')));
|
||||
}
|
||||
else {
|
||||
write(module + '.js', fs.readFileSync(path.join(SRC_DIR, module + '.js')));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
305
build/lib/standalone.ts
Normal file
305
build/lib/standalone.ts
Normal file
@@ -0,0 +1,305 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, '../../');
|
||||
const SRC_DIR = path.join(REPO_ROOT, 'src');
|
||||
const OUT_EDITOR = path.join(REPO_ROOT, 'out-editor');
|
||||
|
||||
export interface IOptions {
|
||||
entryPoints: string[];
|
||||
outFolder: string;
|
||||
outResourcesFolder: string;
|
||||
redirects: { [module: string]: string; };
|
||||
}
|
||||
|
||||
export function createESMSourcesAndResources(options: IOptions): void {
|
||||
const OUT_FOLDER = path.join(REPO_ROOT, options.outFolder);
|
||||
const OUT_RESOURCES_FOLDER = path.join(REPO_ROOT, options.outResourcesFolder);
|
||||
|
||||
let in_queue: { [module: string]: boolean; } = Object.create(null);
|
||||
let queue: string[] = [];
|
||||
|
||||
const enqueue = (module: string) => {
|
||||
if (in_queue[module]) {
|
||||
return;
|
||||
}
|
||||
in_queue[module] = true;
|
||||
queue.push(module);
|
||||
};
|
||||
|
||||
const seenDir: { [key: string]: boolean; } = {};
|
||||
const createDirectoryRecursive = (dir: string) => {
|
||||
if (seenDir[dir]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lastSlash = dir.lastIndexOf('/');
|
||||
if (lastSlash === -1) {
|
||||
lastSlash = dir.lastIndexOf('\\');
|
||||
}
|
||||
if (lastSlash !== -1) {
|
||||
createDirectoryRecursive(dir.substring(0, lastSlash));
|
||||
}
|
||||
seenDir[dir] = true;
|
||||
try { fs.mkdirSync(dir); } catch (err) { }
|
||||
};
|
||||
|
||||
seenDir[REPO_ROOT] = true;
|
||||
|
||||
const toggleComments = (fileContents: string) => {
|
||||
let lines = fileContents.split(/\r\n|\r|\n/);
|
||||
let mode = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
|
||||
if (mode === 0) {
|
||||
if (/\/\/ ESM-comment-begin/.test(line)) {
|
||||
mode = 1;
|
||||
continue;
|
||||
}
|
||||
if (/\/\/ ESM-uncomment-begin/.test(line)) {
|
||||
mode = 2;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode === 1) {
|
||||
if (/\/\/ ESM-comment-end/.test(line)) {
|
||||
mode = 0;
|
||||
continue;
|
||||
}
|
||||
lines[i] = '// ' + line;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode === 2) {
|
||||
if (/\/\/ ESM-uncomment-end/.test(line)) {
|
||||
mode = 0;
|
||||
continue;
|
||||
}
|
||||
lines[i] = line.replace(/^(\s*)\/\/ ?/, function (_, indent) {
|
||||
return indent;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
const write = (filePath: string, contents: string | Buffer) => {
|
||||
let absoluteFilePath: string;
|
||||
if (/\.ts$/.test(filePath)) {
|
||||
absoluteFilePath = path.join(OUT_FOLDER, filePath);
|
||||
} else {
|
||||
absoluteFilePath = path.join(OUT_RESOURCES_FOLDER, filePath);
|
||||
}
|
||||
createDirectoryRecursive(path.dirname(absoluteFilePath));
|
||||
if (/(\.ts$)|(\.js$)/.test(filePath)) {
|
||||
contents = toggleComments(contents.toString());
|
||||
}
|
||||
fs.writeFileSync(absoluteFilePath, contents);
|
||||
};
|
||||
|
||||
options.entryPoints.forEach((entryPoint) => enqueue(entryPoint));
|
||||
|
||||
while (queue.length > 0) {
|
||||
const module = queue.shift();
|
||||
if (transportCSS(options, module, enqueue, write)) {
|
||||
continue;
|
||||
}
|
||||
if (transportResource(options, module, enqueue, write)) {
|
||||
continue;
|
||||
}
|
||||
if (transportDTS(options, module, enqueue, write)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let filename: string;
|
||||
if (options.redirects[module]) {
|
||||
filename = path.join(SRC_DIR, options.redirects[module] + '.ts');
|
||||
} else {
|
||||
filename = path.join(SRC_DIR, module + '.ts');
|
||||
}
|
||||
let fileContents = fs.readFileSync(filename).toString();
|
||||
|
||||
const info = ts.preProcessFile(fileContents);
|
||||
|
||||
for (let i = info.importedFiles.length - 1; i >= 0; i--) {
|
||||
const importedFilename = info.importedFiles[i].fileName;
|
||||
const pos = info.importedFiles[i].pos;
|
||||
const end = info.importedFiles[i].end;
|
||||
|
||||
let importedFilepath: string;
|
||||
if (/^vs\/css!/.test(importedFilename)) {
|
||||
importedFilepath = importedFilename.substr('vs/css!'.length) + '.css';
|
||||
} else {
|
||||
importedFilepath = importedFilename;
|
||||
}
|
||||
if (/(^\.\/)|(^\.\.\/)/.test(importedFilepath)) {
|
||||
importedFilepath = path.join(path.dirname(module), importedFilepath);
|
||||
}
|
||||
|
||||
enqueue(importedFilepath);
|
||||
|
||||
let relativePath: string;
|
||||
if (importedFilepath === path.dirname(module)) {
|
||||
relativePath = '../' + path.basename(path.dirname(module));
|
||||
} else if (importedFilepath === path.dirname(path.dirname(module))) {
|
||||
relativePath = '../../' + path.basename(path.dirname(path.dirname(module)));
|
||||
} else {
|
||||
relativePath = path.relative(path.dirname(module), importedFilepath);
|
||||
}
|
||||
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
|
||||
relativePath = './' + relativePath;
|
||||
}
|
||||
fileContents = (
|
||||
fileContents.substring(0, pos + 1)
|
||||
+ relativePath
|
||||
+ fileContents.substring(end + 1)
|
||||
);
|
||||
}
|
||||
|
||||
fileContents = fileContents.replace(/import ([a-zA-z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) {
|
||||
return `import * as ${m1} from ${m2};`;
|
||||
});
|
||||
fileContents = fileContents.replace(/Thenable/g, 'PromiseLike');
|
||||
|
||||
write(module + '.ts', fileContents);
|
||||
}
|
||||
|
||||
const esm_opts = {
|
||||
"compilerOptions": {
|
||||
"outDir": path.relative(path.dirname(OUT_FOLDER), OUT_RESOURCES_FOLDER),
|
||||
"rootDir": "src",
|
||||
"module": "es6",
|
||||
"target": "es5",
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es5",
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
],
|
||||
"types": [
|
||||
]
|
||||
}
|
||||
};
|
||||
fs.writeFileSync(path.join(path.dirname(OUT_FOLDER), 'tsconfig.json'), JSON.stringify(esm_opts, null, '\t'));
|
||||
|
||||
const monacodts = fs.readFileSync(path.join(SRC_DIR, 'vs/monaco.d.ts')).toString();
|
||||
fs.writeFileSync(path.join(OUT_FOLDER, 'vs/monaco.d.ts'), monacodts);
|
||||
|
||||
}
|
||||
|
||||
function transportCSS(options: IOptions, module: string, enqueue: (module: string) => void, write: (path: string, contents: string | Buffer) => void): boolean {
|
||||
|
||||
if (!/\.css/.test(module)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const filename = path.join(SRC_DIR, module);
|
||||
const fileContents = fs.readFileSync(filename).toString();
|
||||
const inlineResources = 'base64'; // see https://github.com/Microsoft/monaco-editor/issues/148
|
||||
const inlineResourcesLimit = 300000;//3000; // see https://github.com/Microsoft/monaco-editor/issues/336
|
||||
|
||||
const newContents = _rewriteOrInlineUrls(filename, fileContents, inlineResources === 'base64', inlineResourcesLimit);
|
||||
write(module, newContents);
|
||||
return true;
|
||||
|
||||
function _rewriteOrInlineUrls(originalFileFSPath: string, contents: string, forceBase64: boolean, inlineByteLimit: number): string {
|
||||
return _replaceURL(contents, (url) => {
|
||||
let imagePath = path.join(path.dirname(module), url);
|
||||
let fileContents = fs.readFileSync(path.join(SRC_DIR, imagePath));
|
||||
|
||||
if (fileContents.length < inlineByteLimit) {
|
||||
const MIME = /\.svg$/.test(url) ? 'image/svg+xml' : 'image/png';
|
||||
let DATA = ';base64,' + fileContents.toString('base64');
|
||||
|
||||
if (!forceBase64 && /\.svg$/.test(url)) {
|
||||
// .svg => url encode as explained at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
|
||||
let newText = fileContents.toString()
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/</g, '%3C')
|
||||
.replace(/>/g, '%3E')
|
||||
.replace(/&/g, '%26')
|
||||
.replace(/#/g, '%23')
|
||||
.replace(/\s+/g, ' ');
|
||||
let encodedData = ',' + newText;
|
||||
if (encodedData.length < DATA.length) {
|
||||
DATA = encodedData;
|
||||
}
|
||||
}
|
||||
return '"data:' + MIME + DATA + '"';
|
||||
}
|
||||
|
||||
enqueue(imagePath);
|
||||
return url;
|
||||
});
|
||||
}
|
||||
|
||||
function _replaceURL(contents: string, replacer: (url: string) => string): string {
|
||||
// Use ")" as the terminator as quotes are oftentimes not used at all
|
||||
return contents.replace(/url\(\s*([^\)]+)\s*\)?/g, (_: string, ...matches: string[]) => {
|
||||
var url = matches[0];
|
||||
// Eliminate starting quotes (the initial whitespace is not captured)
|
||||
if (url.charAt(0) === '"' || url.charAt(0) === '\'') {
|
||||
url = url.substring(1);
|
||||
}
|
||||
// The ending whitespace is captured
|
||||
while (url.length > 0 && (url.charAt(url.length - 1) === ' ' || url.charAt(url.length - 1) === '\t')) {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
// Eliminate ending quotes
|
||||
if (url.charAt(url.length - 1) === '"' || url.charAt(url.length - 1) === '\'') {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
|
||||
if (!_startsWith(url, 'data:') && !_startsWith(url, 'http://') && !_startsWith(url, 'https://')) {
|
||||
url = replacer(url);
|
||||
}
|
||||
|
||||
return 'url(' + url + ')';
|
||||
});
|
||||
}
|
||||
|
||||
function _startsWith(haystack: string, needle: string): boolean {
|
||||
return haystack.length >= needle.length && haystack.substr(0, needle.length) === needle;
|
||||
}
|
||||
}
|
||||
|
||||
function transportResource(options: IOptions, module: string, enqueue: (module: string) => void, write: (path: string, contents: string | Buffer) => void): boolean {
|
||||
|
||||
if (!/\.svg/.test(module)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
write(module, fs.readFileSync(path.join(SRC_DIR, module)));
|
||||
return true;
|
||||
}
|
||||
|
||||
function transportDTS(options: IOptions, module: string, enqueue: (module: string) => void, write: (path: string, contents: string | Buffer) => void): boolean {
|
||||
|
||||
if (options.redirects[module] && fs.existsSync(path.join(SRC_DIR, options.redirects[module] + '.ts'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(path.join(SRC_DIR, module + '.d.ts'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
write(module + '.d.ts', fs.readFileSync(path.join(SRC_DIR, module + '.d.ts')));
|
||||
let filename: string;
|
||||
if (options.redirects[module]) {
|
||||
write(module + '.js', fs.readFileSync(path.join(SRC_DIR, options.redirects[module] + '.js')));
|
||||
} else {
|
||||
write(module + '.js', fs.readFileSync(path.join(SRC_DIR, module + '.js')));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
56
build/lib/test/util.test.js
Normal file
56
build/lib/test/util.test.js
Normal file
@@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var assert = require("assert");
|
||||
var util = require("../util");
|
||||
function getMockTagExists(tags) {
|
||||
return function (tag) { return tags.indexOf(tag) >= 0; };
|
||||
}
|
||||
suite('util tests', function () {
|
||||
test('getPreviousVersion - patch', function () {
|
||||
assert.equal(util.getPreviousVersion('1.2.3', getMockTagExists(['1.2.2', '1.2.1', '1.2.0', '1.1.0'])), '1.2.2');
|
||||
});
|
||||
test('getPreviousVersion - patch invalid', function () {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.2', getMockTagExists(['1.2.0', '1.1.0']));
|
||||
}
|
||||
catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
test('getPreviousVersion - minor', function () {
|
||||
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.2', '1.1.3'])), '1.1.3');
|
||||
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.0.0'])), '1.1.0');
|
||||
});
|
||||
test('getPreviousVersion - minor gap', function () {
|
||||
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.3'])), '1.1.1');
|
||||
});
|
||||
test('getPreviousVersion - minor invalid', function () {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.0.0']));
|
||||
}
|
||||
catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
test('getPreviousVersion - major', function () {
|
||||
assert.equal(util.getPreviousVersion('2.0.0', getMockTagExists(['1.0.0', '1.1.0', '1.2.0', '1.2.1', '1.2.2'])), '1.2.2');
|
||||
});
|
||||
test('getPreviousVersion - major invalid', function () {
|
||||
try {
|
||||
util.getPreviousVersion('3.0.0', getMockTagExists(['1.0.0']));
|
||||
}
|
||||
catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
});
|
||||
79
build/lib/test/util.test.ts
Normal file
79
build/lib/test/util.test.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import assert = require('assert');
|
||||
import util = require('../util');
|
||||
|
||||
function getMockTagExists(tags: string[]) {
|
||||
return (tag: string) => tags.indexOf(tag) >= 0;
|
||||
}
|
||||
|
||||
suite('util tests', () => {
|
||||
test('getPreviousVersion - patch', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.3', getMockTagExists(['1.2.2', '1.2.1', '1.2.0', '1.1.0'])),
|
||||
'1.2.2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - patch invalid', () => {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.2', getMockTagExists(['1.2.0', '1.1.0']));
|
||||
} catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
|
||||
test('getPreviousVersion - minor', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.2', '1.1.3'])),
|
||||
'1.1.3'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.0.0'])),
|
||||
'1.1.0'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - minor gap', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.3'])),
|
||||
'1.1.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - minor invalid', () => {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.0.0']));
|
||||
} catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
|
||||
test('getPreviousVersion - major', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('2.0.0', getMockTagExists(['1.0.0', '1.1.0', '1.2.0', '1.2.1', '1.2.2'])),
|
||||
'1.2.2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - major invalid', () => {
|
||||
try {
|
||||
util.getPreviousVersion('3.0.0', getMockTagExists(['1.0.0']));
|
||||
} catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
});
|
||||
@@ -71,7 +71,7 @@ var TranslationRemindRuleWalker = /** @class */ (function (_super) {
|
||||
}
|
||||
});
|
||||
if (!resourceDefined) {
|
||||
this.addFailureAtNode(node, "Please add '" + resource + "' to ./builds/lib/i18n.resources.json file to use translations here.");
|
||||
this.addFailureAtNode(node, "Please add '" + resource + "' to ./build/lib/i18n.resources.json file to use translations here.");
|
||||
}
|
||||
};
|
||||
TranslationRemindRuleWalker.NLS_MODULE = 'vs/nls';
|
||||
|
||||
@@ -67,7 +67,7 @@ class TranslationRemindRuleWalker extends Lint.RuleWalker {
|
||||
});
|
||||
|
||||
if (!resourceDefined) {
|
||||
this.addFailureAtNode(node, `Please add '${resource}' to ./builds/lib/i18n.resources.json file to use translations here.`);
|
||||
this.addFailureAtNode(node, `Please add '${resource}' to ./build/lib/i18n.resources.json file to use translations here.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ var fs = require("fs");
|
||||
var _rimraf = require("rimraf");
|
||||
var git = require("./git");
|
||||
var VinylFile = require("vinyl");
|
||||
var cp = require("child_process");
|
||||
var NoCancellationToken = { isCancellationRequested: function () { return false; } };
|
||||
function incremental(streamProvider, initial, supportsCancellation) {
|
||||
var input = es.through();
|
||||
@@ -210,3 +211,68 @@ function filter(fn) {
|
||||
return result;
|
||||
}
|
||||
exports.filter = filter;
|
||||
function tagExists(tagName) {
|
||||
try {
|
||||
cp.execSync("git rev-parse " + tagName, { stdio: 'ignore' });
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the version previous to the given version. Throws if a git tag for that version doesn't exist.
|
||||
* Given 1.17.2, return 1.17.1
|
||||
* 1.18.0 => 1.17.2. (or the highest 1.17.x)
|
||||
* 2.0.0 => 1.18.0 (or the highest 1.x)
|
||||
*/
|
||||
function getPreviousVersion(versionStr, _tagExists) {
|
||||
if (_tagExists === void 0) { _tagExists = tagExists; }
|
||||
function getLatestTagFromBase(semverArr, componentToTest) {
|
||||
var baseVersion = semverArr.join('.');
|
||||
if (!_tagExists(baseVersion)) {
|
||||
throw new Error('Failed to find git tag for base version, ' + baseVersion);
|
||||
}
|
||||
var goodTag;
|
||||
do {
|
||||
goodTag = semverArr.join('.');
|
||||
semverArr[componentToTest]++;
|
||||
} while (_tagExists(semverArr.join('.')));
|
||||
return goodTag;
|
||||
}
|
||||
var semverArr = versionStringToNumberArray(versionStr);
|
||||
if (semverArr[2] > 0) {
|
||||
semverArr[2]--;
|
||||
var previous = semverArr.join('.');
|
||||
if (!_tagExists(previous)) {
|
||||
throw new Error('Failed to find git tag for previous version, ' + previous);
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
else if (semverArr[1] > 0) {
|
||||
semverArr[1]--;
|
||||
return getLatestTagFromBase(semverArr, 2);
|
||||
}
|
||||
else {
|
||||
semverArr[0]--;
|
||||
// Find 1.x.0 for latest x
|
||||
var latestMinorVersion = getLatestTagFromBase(semverArr, 1);
|
||||
// Find 1.x.y for latest y
|
||||
return getLatestTagFromBase(versionStringToNumberArray(latestMinorVersion), 2);
|
||||
}
|
||||
}
|
||||
exports.getPreviousVersion = getPreviousVersion;
|
||||
function versionStringToNumberArray(versionStr) {
|
||||
return versionStr
|
||||
.split('.')
|
||||
.map(function (s) { return parseInt(s); });
|
||||
}
|
||||
function versionStringToNumber(versionStr) {
|
||||
var semverRegex = /(\d+)\.(\d+)\.(\d+)/;
|
||||
var match = versionStr.match(semverRegex);
|
||||
if (!match) {
|
||||
throw new Error('Version string is not properly formatted: ' + versionStr);
|
||||
}
|
||||
return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10);
|
||||
}
|
||||
exports.versionStringToNumber = versionStringToNumber;
|
||||
|
||||
@@ -17,6 +17,7 @@ import * as git from './git';
|
||||
import * as VinylFile from 'vinyl';
|
||||
import { ThroughStream } from 'through';
|
||||
import * as sm from 'source-map';
|
||||
import * as cp from 'child_process';
|
||||
|
||||
export interface ICancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
@@ -268,4 +269,74 @@ export function filter(fn: (data: any) => boolean): FilterStream {
|
||||
|
||||
result.restore = es.through();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function tagExists(tagName: string): boolean {
|
||||
try {
|
||||
cp.execSync(`git rev-parse ${tagName}`, { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version previous to the given version. Throws if a git tag for that version doesn't exist.
|
||||
* Given 1.17.2, return 1.17.1
|
||||
* 1.18.0 => 1.17.2. (or the highest 1.17.x)
|
||||
* 2.0.0 => 1.18.0 (or the highest 1.x)
|
||||
*/
|
||||
export function getPreviousVersion(versionStr: string, _tagExists = tagExists) {
|
||||
function getLatestTagFromBase(semverArr: number[], componentToTest: number): string {
|
||||
const baseVersion = semverArr.join('.');
|
||||
if (!_tagExists(baseVersion)) {
|
||||
throw new Error('Failed to find git tag for base version, ' + baseVersion);
|
||||
}
|
||||
|
||||
let goodTag;
|
||||
do {
|
||||
goodTag = semverArr.join('.');
|
||||
semverArr[componentToTest]++;
|
||||
} while (_tagExists(semverArr.join('.')));
|
||||
|
||||
return goodTag;
|
||||
}
|
||||
|
||||
const semverArr = versionStringToNumberArray(versionStr);
|
||||
if (semverArr[2] > 0) {
|
||||
semverArr[2]--;
|
||||
const previous = semverArr.join('.');
|
||||
if (!_tagExists(previous)) {
|
||||
throw new Error('Failed to find git tag for previous version, ' + previous);
|
||||
}
|
||||
|
||||
return previous;
|
||||
} else if (semverArr[1] > 0) {
|
||||
semverArr[1]--;
|
||||
return getLatestTagFromBase(semverArr, 2);
|
||||
} else {
|
||||
semverArr[0]--;
|
||||
|
||||
// Find 1.x.0 for latest x
|
||||
const latestMinorVersion = getLatestTagFromBase(semverArr, 1);
|
||||
|
||||
// Find 1.x.y for latest y
|
||||
return getLatestTagFromBase(versionStringToNumberArray(latestMinorVersion), 2);
|
||||
}
|
||||
}
|
||||
|
||||
function versionStringToNumberArray(versionStr: string): number[] {
|
||||
return versionStr
|
||||
.split('.')
|
||||
.map(s => parseInt(s));
|
||||
}
|
||||
|
||||
export function versionStringToNumber(versionStr: string) {
|
||||
const semverRegex = /(\d+)\.(\d+)\.(\d+)/;
|
||||
const match = versionStr.match(semverRegex);
|
||||
if (!match) {
|
||||
throw new Error('Version string is not properly formatted: ' + versionStr);
|
||||
}
|
||||
|
||||
return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The Source EULA
|
||||
|
||||
Copyright (c) 2016 Microsoft Corporation
|
||||
Copyright (c) 2016 - present Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -32,7 +32,7 @@ END OF winjs NOTICES AND INFORMATION
|
||||
|
||||
%% string_scorer version 0.1.20 (https://github.com/joshaven/string_score)
|
||||
=========================================
|
||||
This software is released under the Source EULA:
|
||||
This software is released under the MIT license:
|
||||
|
||||
Copyright (c) Joshaven Potter
|
||||
|
||||
@@ -60,7 +60,7 @@ END OF string_scorer NOTICES AND INFORMATION
|
||||
|
||||
%% chjj-marked NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
The Source EULA
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/)
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@ function format(text) {
|
||||
function getRuleProvider(options) {
|
||||
// Share this between multiple formatters using the same options.
|
||||
// This represents the bulk of the space the formatter uses.
|
||||
var ruleProvider = new ts.formatting.RulesProvider();
|
||||
ruleProvider.ensureUpToDate(options);
|
||||
return ruleProvider;
|
||||
return ts.formatting.getFormatContext(options);
|
||||
}
|
||||
function applyEdits(text, edits) {
|
||||
// Apply edits in reverse on the existing text
|
||||
@@ -210,7 +208,8 @@ function createReplacer(data) {
|
||||
};
|
||||
}
|
||||
function generateDeclarationFile(out, inputFiles, recipe) {
|
||||
var lines = recipe.split(/\r\n|\n|\r/);
|
||||
var endl = /\r\n/.test(recipe) ? '\r\n' : '\n';
|
||||
var lines = recipe.split(endl);
|
||||
var result = [];
|
||||
lines.forEach(function (line) {
|
||||
var m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/);
|
||||
@@ -278,12 +277,11 @@ function generateDeclarationFile(out, inputFiles, recipe) {
|
||||
}
|
||||
result.push(line);
|
||||
});
|
||||
var resultTxt = result.join('\n');
|
||||
var resultTxt = result.join(endl);
|
||||
resultTxt = resultTxt.replace(/\bURI\b/g, 'Uri');
|
||||
resultTxt = resultTxt.replace(/\bEvent</g, 'IEvent<');
|
||||
resultTxt = resultTxt.replace(/\bTPromise</g, 'Promise<');
|
||||
resultTxt = format(resultTxt);
|
||||
resultTxt = resultTxt.replace(/\r\n/g, '\n');
|
||||
return resultTxt;
|
||||
}
|
||||
function getFilesToWatch(out) {
|
||||
@@ -314,10 +312,13 @@ function run(out, inputFiles) {
|
||||
var result = generateDeclarationFile(out, inputFiles, recipe);
|
||||
var currentContent = fs.readFileSync(DECLARATION_PATH).toString();
|
||||
log('Finished monaco.d.ts generation');
|
||||
var one = currentContent.replace(/\r\n/gm, '\n');
|
||||
var other = result.replace(/\r\n/gm, '\n');
|
||||
var isTheSame = one === other;
|
||||
return {
|
||||
content: result,
|
||||
filePath: DECLARATION_PATH,
|
||||
isTheSame: currentContent === result
|
||||
isTheSame: isTheSame
|
||||
};
|
||||
}
|
||||
exports.run = run;
|
||||
|
||||
@@ -24,15 +24,15 @@ function logErr(message: any, ...rest: any[]): void {
|
||||
util.log(util.colors.red('[monaco.d.ts]'), message, ...rest);
|
||||
}
|
||||
|
||||
function moduleIdToPath(out:string, moduleId:string): string {
|
||||
function moduleIdToPath(out: string, moduleId: string): string {
|
||||
if (/\.d\.ts/.test(moduleId)) {
|
||||
return path.join(SRC, moduleId);
|
||||
}
|
||||
return path.join(OUT_ROOT, out, moduleId) + '.d.ts';
|
||||
}
|
||||
|
||||
let SOURCE_FILE_MAP: {[moduleId:string]:ts.SourceFile;} = {};
|
||||
function getSourceFile(out:string, inputFiles: { [file: string]: string; }, moduleId:string): ts.SourceFile {
|
||||
let SOURCE_FILE_MAP: { [moduleId: string]: ts.SourceFile; } = {};
|
||||
function getSourceFile(out: string, inputFiles: { [file: string]: string; }, moduleId: string): ts.SourceFile {
|
||||
if (!SOURCE_FILE_MAP[moduleId]) {
|
||||
let filePath = path.normalize(moduleIdToPath(out, moduleId));
|
||||
|
||||
@@ -53,7 +53,7 @@ function getSourceFile(out:string, inputFiles: { [file: string]: string; }, modu
|
||||
type TSTopLevelDeclaration = ts.InterfaceDeclaration | ts.EnumDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration | ts.FunctionDeclaration | ts.ModuleDeclaration;
|
||||
type TSTopLevelDeclare = TSTopLevelDeclaration | ts.VariableStatement;
|
||||
|
||||
function isDeclaration(a:TSTopLevelDeclare): a is TSTopLevelDeclaration {
|
||||
function isDeclaration(a: TSTopLevelDeclare): a is TSTopLevelDeclaration {
|
||||
return (
|
||||
a.kind === ts.SyntaxKind.InterfaceDeclaration
|
||||
|| a.kind === ts.SyntaxKind.EnumDeclaration
|
||||
@@ -64,7 +64,7 @@ function isDeclaration(a:TSTopLevelDeclare): a is TSTopLevelDeclaration {
|
||||
);
|
||||
}
|
||||
|
||||
function visitTopLevelDeclarations(sourceFile:ts.SourceFile, visitor:(node:TSTopLevelDeclare)=>boolean): void {
|
||||
function visitTopLevelDeclarations(sourceFile: ts.SourceFile, visitor: (node: TSTopLevelDeclare) => boolean): void {
|
||||
let stop = false;
|
||||
|
||||
let visit = (node: ts.Node): void => {
|
||||
@@ -100,8 +100,8 @@ function visitTopLevelDeclarations(sourceFile:ts.SourceFile, visitor:(node:TSTop
|
||||
}
|
||||
|
||||
|
||||
function getAllTopLevelDeclarations(sourceFile:ts.SourceFile): TSTopLevelDeclare[] {
|
||||
let all:TSTopLevelDeclare[] = [];
|
||||
function getAllTopLevelDeclarations(sourceFile: ts.SourceFile): TSTopLevelDeclare[] {
|
||||
let all: TSTopLevelDeclare[] = [];
|
||||
visitTopLevelDeclarations(sourceFile, (node) => {
|
||||
if (node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ModuleDeclaration) {
|
||||
let interfaceDeclaration = <ts.InterfaceDeclaration>node;
|
||||
@@ -128,8 +128,8 @@ function getAllTopLevelDeclarations(sourceFile:ts.SourceFile): TSTopLevelDeclare
|
||||
}
|
||||
|
||||
|
||||
function getTopLevelDeclaration(sourceFile:ts.SourceFile, typeName:string): TSTopLevelDeclare {
|
||||
let result:TSTopLevelDeclare = null;
|
||||
function getTopLevelDeclaration(sourceFile: ts.SourceFile, typeName: string): TSTopLevelDeclare {
|
||||
let result: TSTopLevelDeclare = null;
|
||||
visitTopLevelDeclarations(sourceFile, (node) => {
|
||||
if (isDeclaration(node)) {
|
||||
if (node.name.text === typeName) {
|
||||
@@ -149,12 +149,12 @@ function getTopLevelDeclaration(sourceFile:ts.SourceFile, typeName:string): TSTo
|
||||
}
|
||||
|
||||
|
||||
function getNodeText(sourceFile:ts.SourceFile, node:{pos:number; end:number;}): string {
|
||||
function getNodeText(sourceFile: ts.SourceFile, node: { pos: number; end: number; }): string {
|
||||
return sourceFile.getFullText().substring(node.pos, node.end);
|
||||
}
|
||||
|
||||
|
||||
function getMassagedTopLevelDeclarationText(sourceFile:ts.SourceFile, declaration: TSTopLevelDeclare): string {
|
||||
function getMassagedTopLevelDeclarationText(sourceFile: ts.SourceFile, declaration: TSTopLevelDeclare): string {
|
||||
let result = getNodeText(sourceFile, declaration);
|
||||
// if (result.indexOf('MonacoWorker') >= 0) {
|
||||
// console.log('here!');
|
||||
@@ -163,7 +163,7 @@ function getMassagedTopLevelDeclarationText(sourceFile:ts.SourceFile, declaratio
|
||||
if (declaration.kind === ts.SyntaxKind.InterfaceDeclaration || declaration.kind === ts.SyntaxKind.ClassDeclaration) {
|
||||
let interfaceDeclaration = <ts.InterfaceDeclaration | ts.ClassDeclaration>declaration;
|
||||
|
||||
let members:ts.NodeArray<ts.Node> = interfaceDeclaration.members;
|
||||
let members: ts.NodeArray<ts.Node> = interfaceDeclaration.members;
|
||||
members.forEach((member) => {
|
||||
try {
|
||||
let memberText = getNodeText(sourceFile, member);
|
||||
@@ -182,7 +182,7 @@ function getMassagedTopLevelDeclarationText(sourceFile:ts.SourceFile, declaratio
|
||||
return result;
|
||||
}
|
||||
|
||||
function format(text:string): string {
|
||||
function format(text: string): string {
|
||||
|
||||
// Parse the source text
|
||||
let sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true);
|
||||
@@ -196,9 +196,7 @@ function format(text:string): string {
|
||||
function getRuleProvider(options: ts.FormatCodeSettings) {
|
||||
// Share this between multiple formatters using the same options.
|
||||
// This represents the bulk of the space the formatter uses.
|
||||
let ruleProvider = new (<any>ts).formatting.RulesProvider();
|
||||
ruleProvider.ensureUpToDate(options);
|
||||
return ruleProvider;
|
||||
return (ts as any).formatting.getFormatContext(options);
|
||||
}
|
||||
|
||||
function applyEdits(text: string, edits: ts.TextChange[]): string {
|
||||
@@ -214,10 +212,10 @@ function format(text:string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function createReplacer(data:string): (str:string)=>string {
|
||||
function createReplacer(data: string): (str: string) => string {
|
||||
data = data || '';
|
||||
let rawDirectives = data.split(';');
|
||||
let directives: [RegExp,string][] = [];
|
||||
let directives: [RegExp, string][] = [];
|
||||
rawDirectives.forEach((rawDirective) => {
|
||||
if (rawDirective.length === 0) {
|
||||
return;
|
||||
@@ -231,7 +229,7 @@ function createReplacer(data:string): (str:string)=>string {
|
||||
directives.push([new RegExp(findStr, 'g'), replaceStr]);
|
||||
});
|
||||
|
||||
return (str:string)=> {
|
||||
return (str: string) => {
|
||||
for (let i = 0; i < directives.length; i++) {
|
||||
str = str.replace(directives[i][0], directives[i][1]);
|
||||
}
|
||||
@@ -239,10 +237,11 @@ function createReplacer(data:string): (str:string)=>string {
|
||||
};
|
||||
}
|
||||
|
||||
function generateDeclarationFile(out: string, inputFiles: { [file: string]: string; }, recipe:string): string {
|
||||
let lines = recipe.split(/\r\n|\n|\r/);
|
||||
let result = [];
|
||||
function generateDeclarationFile(out: string, inputFiles: { [file: string]: string; }, recipe: string): string {
|
||||
const endl = /\r\n/.test(recipe) ? '\r\n' : '\n';
|
||||
|
||||
let lines = recipe.split(endl);
|
||||
let result = [];
|
||||
|
||||
lines.forEach(line => {
|
||||
|
||||
@@ -285,7 +284,7 @@ function generateDeclarationFile(out: string, inputFiles: { [file: string]: stri
|
||||
let replacer = createReplacer(m2[2]);
|
||||
|
||||
let typeNames = m2[3].split(/,/);
|
||||
let typesToExcludeMap: {[typeName:string]:boolean;} = {};
|
||||
let typesToExcludeMap: { [typeName: string]: boolean; } = {};
|
||||
let typesToExcludeArr: string[] = [];
|
||||
typeNames.forEach((typeName) => {
|
||||
typeName = typeName.trim();
|
||||
@@ -318,18 +317,17 @@ function generateDeclarationFile(out: string, inputFiles: { [file: string]: stri
|
||||
result.push(line);
|
||||
});
|
||||
|
||||
let resultTxt = result.join('\n');
|
||||
let resultTxt = result.join(endl);
|
||||
resultTxt = resultTxt.replace(/\bURI\b/g, 'Uri');
|
||||
resultTxt = resultTxt.replace(/\bEvent</g, 'IEvent<');
|
||||
resultTxt = resultTxt.replace(/\bTPromise</g, 'Promise<');
|
||||
|
||||
resultTxt = format(resultTxt);
|
||||
|
||||
resultTxt = resultTxt.replace(/\r\n/g, '\n');
|
||||
return resultTxt;
|
||||
}
|
||||
|
||||
export function getFilesToWatch(out:string): string[] {
|
||||
export function getFilesToWatch(out: string): string[] {
|
||||
let recipe = fs.readFileSync(RECIPE_PATH).toString();
|
||||
let lines = recipe.split(/\r\n|\n|\r/);
|
||||
let result = [];
|
||||
@@ -370,10 +368,14 @@ export function run(out: string, inputFiles: { [file: string]: string; }): IMona
|
||||
let currentContent = fs.readFileSync(DECLARATION_PATH).toString();
|
||||
log('Finished monaco.d.ts generation');
|
||||
|
||||
const one = currentContent.replace(/\r\n/gm, '\n');
|
||||
const other = result.replace(/\r\n/gm, '\n');
|
||||
const isTheSame = one === other;
|
||||
|
||||
return {
|
||||
content: result,
|
||||
filePath: DECLARATION_PATH,
|
||||
isTheSame: currentContent === result
|
||||
isTheSame
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module monaco {
|
||||
declare namespace monaco {
|
||||
|
||||
type Thenable<T> = PromiseLike<T>;
|
||||
export type Thenable<T> = PromiseLike<T>;
|
||||
|
||||
export interface IDisposable {
|
||||
dispose(): void;
|
||||
@@ -32,6 +32,14 @@ declare module monaco {
|
||||
Error = 3,
|
||||
}
|
||||
|
||||
export enum MarkerSeverity {
|
||||
Hint = 1,
|
||||
Info = 2,
|
||||
Warning = 4,
|
||||
Error = 8,
|
||||
}
|
||||
|
||||
|
||||
#include(vs/base/common/winjs.base.d.ts): TValueCallback, ProgressCallback, Promise
|
||||
#include(vs/base/common/cancellation): CancellationTokenSource, CancellationToken
|
||||
#include(vs/base/common/uri): URI, UriComponents
|
||||
@@ -46,7 +54,7 @@ declare module monaco {
|
||||
#include(vs/editor/common/core/token): Token
|
||||
}
|
||||
|
||||
declare module monaco.editor {
|
||||
declare namespace monaco.editor {
|
||||
|
||||
#includeAll(vs/editor/standalone/browser/standaloneEditor;modes.=>languages.;editorCommon.=>):
|
||||
#include(vs/editor/standalone/common/standaloneThemeService): BuiltinTheme, IStandaloneThemeData, IColors
|
||||
@@ -58,7 +66,7 @@ export interface ICommandHandler {
|
||||
}
|
||||
#include(vs/platform/contextkey/common/contextkey): IContextKey
|
||||
#include(vs/editor/standalone/browser/standaloneServices): IEditorOverrideServices
|
||||
#include(vs/platform/markers/common/markers): IMarker, IMarkerData
|
||||
#include(vs/platform/markers/common/markers): IMarker, IMarkerData, IRelatedInformation
|
||||
#include(vs/editor/standalone/browser/colorizer): IColorizerOptions, IColorizerElementOptions
|
||||
#include(vs/base/common/scrollable): ScrollbarVisibility
|
||||
#include(vs/platform/theme/common/themeService): ThemeColor
|
||||
@@ -75,7 +83,7 @@ export type IReadOnlyModel = ITextModel;
|
||||
export type IModel = ITextModel;
|
||||
}
|
||||
|
||||
declare module monaco.languages {
|
||||
declare namespace monaco.languages {
|
||||
|
||||
#includeAll(vs/editor/standalone/browser/standaloneLanguages;modes.=>;editorCommon.=>editor.;model.=>editor.;IMarkerData=>editor.IMarkerData):
|
||||
#includeAll(vs/editor/common/modes/languageConfiguration):
|
||||
@@ -85,7 +93,7 @@ declare module monaco.languages {
|
||||
|
||||
}
|
||||
|
||||
declare module monaco.worker {
|
||||
declare namespace monaco.worker {
|
||||
|
||||
#includeAll(vs/editor/common/services/editorSimpleWorker;):
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
{
|
||||
"name": "monaco-editor-core",
|
||||
"private": true,
|
||||
"version": "0.9.0",
|
||||
"version": "0.12.0",
|
||||
"description": "A browser based code editor",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"typings": "./esm/vs/editor/editor.api.d.ts",
|
||||
"module": "./esm/vs/editor/editor.main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vscode"
|
||||
},
|
||||
"bugs": {
|
||||
"bugs": {
|
||||
"url": "https://github.com/Microsoft/vscode/issues"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,20 +23,15 @@ function yarnInstall(location, opts) {
|
||||
// {{SQL CARBON EDIT}}
|
||||
yarnInstall('extensions'); // node modules shared by all extensions
|
||||
|
||||
const extensions = [
|
||||
'vscode-colorize-tests',
|
||||
'json',
|
||||
'mssql',
|
||||
'configuration-editing',
|
||||
'extension-editing',
|
||||
'markdown',
|
||||
'markdown-basics',
|
||||
'git',
|
||||
'merge-conflict',
|
||||
'insights-default',
|
||||
'account-provider-azure',
|
||||
'agent'
|
||||
];
|
||||
const allExtensionFolders = fs.readdirSync('extensions');
|
||||
const extensions = allExtensionFolders.filter(e => {
|
||||
try {
|
||||
let packageJSON = JSON.parse(fs.readFileSync(path.join('extensions', e, 'package.json')).toString());
|
||||
return packageJSON && (packageJSON.dependencies || packageJSON.devDependencies);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
extensions.forEach(extension => yarnInstall(`extensions/${extension}`));
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"@types/mime": "0.0.29",
|
||||
"@types/node": "8.0.33",
|
||||
"@types/xml2js": "0.0.33",
|
||||
"@types/request": "^2.47.0",
|
||||
"azure-storage": "^2.1.0",
|
||||
"decompress": "^4.2.0",
|
||||
"documentdb": "1.13.0",
|
||||
@@ -16,9 +17,11 @@
|
||||
"fs-extra-promise": "^1.0.1",
|
||||
"mime": "^1.3.4",
|
||||
"minimist": "^1.2.0",
|
||||
"typescript": "2.6.1",
|
||||
"typescript": "2.8.1",
|
||||
"vscode": "^1.0.1",
|
||||
"xml2js": "^0.4.17"
|
||||
"xml2js": "^0.4.17",
|
||||
"github-releases": "^0.4.1",
|
||||
"request": "^2.85.0"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc -p tsconfig.build.json",
|
||||
|
||||
219
build/tfs/common/symbols.ts
Normal file
219
build/tfs/common/symbols.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as request from 'request';
|
||||
import { createReadStream, createWriteStream, unlink, mkdir } from 'fs';
|
||||
import * as github from 'github-releases';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const BASE_URL = 'https://rink.hockeyapp.net/api/2/';
|
||||
const HOCKEY_APP_TOKEN_HEADER = 'X-HockeyAppToken';
|
||||
|
||||
export interface IVersions {
|
||||
app_versions: IVersion[];
|
||||
}
|
||||
|
||||
export interface IVersion {
|
||||
id: number;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface IApplicationAccessor {
|
||||
accessToken: string;
|
||||
appId: string;
|
||||
}
|
||||
|
||||
export interface IVersionAccessor extends IApplicationAccessor {
|
||||
id: string;
|
||||
}
|
||||
|
||||
enum Platform {
|
||||
WIN_32 = 'win32-ia32',
|
||||
WIN_64 = 'win32-x64',
|
||||
LINUX_32 = 'linux-ia32',
|
||||
LINUX_64 = 'linux-x64',
|
||||
MAC_OS = 'darwin-x64'
|
||||
}
|
||||
|
||||
function symbolsZipName(platform: Platform, electronVersion: string, insiders: boolean): string {
|
||||
return `${insiders ? 'insiders' : 'stable'}-symbols-v${electronVersion}-${platform}.zip`;
|
||||
}
|
||||
|
||||
const SEED = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
async function tmpFile(name: string): Promise<string> {
|
||||
let res = '';
|
||||
for (let i = 0; i < 8; i++) {
|
||||
res += SEED.charAt(Math.floor(Math.random() * SEED.length));
|
||||
}
|
||||
|
||||
const tmpParent = join(tmpdir(), res);
|
||||
|
||||
await promisify(mkdir)(tmpParent);
|
||||
|
||||
return join(tmpParent, name);
|
||||
}
|
||||
|
||||
function getVersions(accessor: IApplicationAccessor): Promise<IVersions> {
|
||||
return asyncRequest<IVersions>({
|
||||
url: `${BASE_URL}/apps/${accessor.appId}/app_versions`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
[HOCKEY_APP_TOKEN_HEADER]: accessor.accessToken
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createVersion(accessor: IApplicationAccessor, version: string): Promise<IVersion> {
|
||||
return asyncRequest<IVersion>({
|
||||
url: `${BASE_URL}/apps/${accessor.appId}/app_versions/new`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
[HOCKEY_APP_TOKEN_HEADER]: accessor.accessToken
|
||||
},
|
||||
formData: {
|
||||
bundle_version: version
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateVersion(accessor: IVersionAccessor, symbolsPath: string) {
|
||||
return asyncRequest<IVersions>({
|
||||
url: `${BASE_URL}/apps/${accessor.appId}/app_versions/${accessor.id}`,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
[HOCKEY_APP_TOKEN_HEADER]: accessor.accessToken
|
||||
},
|
||||
formData: {
|
||||
dsym: createReadStream(symbolsPath)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function asyncRequest<T>(options: request.UrlOptions & request.CoreOptions): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
request(options, (error, response, body) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(JSON.parse(body));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function downloadAsset(repository, assetName: string, targetPath: string, electronVersion: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
repository.getReleases({ tag_name: `v${electronVersion}` }, (err, releases) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const asset = releases[0].assets.filter(asset => asset.name === assetName)[0];
|
||||
if (!asset) {
|
||||
reject(new Error(`Asset with name ${assetName} not found`));
|
||||
} else {
|
||||
repository.downloadAsset(asset, (err, reader) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const writer = createWriteStream(targetPath);
|
||||
writer.on('error', reject);
|
||||
writer.on('close', resolve);
|
||||
reader.on('error', reject);
|
||||
|
||||
reader.pipe(writer);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
interface IOptions {
|
||||
repository: string;
|
||||
platform: Platform;
|
||||
versions: { code: string; insiders: boolean; electron: string; };
|
||||
access: { hockeyAppToken: string; hockeyAppId: string; githubToken: string };
|
||||
}
|
||||
|
||||
async function ensureVersionAndSymbols(options: IOptions) {
|
||||
|
||||
// Check version does not exist
|
||||
console.log(`HockeyApp: checking for existing version ${options.versions.code} (${options.platform})`);
|
||||
const versions = await getVersions({ accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId });
|
||||
if (versions.app_versions.some(v => v.version === options.versions.code)) {
|
||||
console.log(`HockeyApp: Returning without uploading symbols because version ${options.versions.code} (${options.platform}) was already found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Download symbols for platform and electron version
|
||||
const symbolsName = symbolsZipName(options.platform, options.versions.electron, options.versions.insiders);
|
||||
const symbolsPath = await tmpFile('symbols.zip');
|
||||
console.log(`HockeyApp: downloading symbols ${symbolsName} for electron ${options.versions.electron} (${options.platform}) into ${symbolsPath}`);
|
||||
await downloadAsset(new github({ repo: options.repository, token: options.access.githubToken }), symbolsName, symbolsPath, options.versions.electron);
|
||||
|
||||
// Create version
|
||||
console.log(`HockeyApp: creating new version ${options.versions.code} (${options.platform})`);
|
||||
const version = await createVersion({ accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId }, options.versions.code);
|
||||
|
||||
// Upload symbols
|
||||
console.log(`HockeyApp: uploading symbols for version ${options.versions.code} (${options.platform})`);
|
||||
await updateVersion({ id: String(version.id), accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId }, symbolsPath);
|
||||
|
||||
// Cleanup
|
||||
await promisify(unlink)(symbolsPath);
|
||||
}
|
||||
|
||||
// Environment
|
||||
const pakage = require('../../../package.json');
|
||||
const product = require('../../../product.json');
|
||||
const repository = product.electronRepository;
|
||||
const electronVersion = require('../../lib/electron').getElectronVersion();
|
||||
const insiders = product.quality !== 'stable';
|
||||
let codeVersion = pakage.version;
|
||||
if (insiders) {
|
||||
codeVersion = `${codeVersion}-insider`;
|
||||
}
|
||||
const githubToken = process.argv[2];
|
||||
const hockeyAppToken = process.argv[3];
|
||||
const is64 = process.argv[4] === 'x64';
|
||||
const hockeyAppId = process.argv[5];
|
||||
|
||||
let platform: Platform;
|
||||
if (process.platform === 'darwin') {
|
||||
platform = Platform.MAC_OS;
|
||||
} else if (process.platform === 'win32') {
|
||||
platform = is64 ? Platform.WIN_64 : Platform.WIN_32;
|
||||
} else {
|
||||
platform = is64 ? Platform.LINUX_64 : Platform.LINUX_32;
|
||||
}
|
||||
|
||||
// Create version and upload symbols in HockeyApp
|
||||
if (repository && codeVersion && electronVersion && (product.quality === 'stable' || product.quality === 'insider')) {
|
||||
ensureVersionAndSymbols({
|
||||
repository,
|
||||
platform,
|
||||
versions: {
|
||||
code: codeVersion,
|
||||
insiders,
|
||||
electron: electronVersion
|
||||
},
|
||||
access: {
|
||||
githubToken,
|
||||
hockeyAppToken,
|
||||
hockeyAppId
|
||||
}
|
||||
}).then(() => {
|
||||
console.log('HockeyApp: done');
|
||||
}).catch(error => {
|
||||
console.error(`HockeyApp: error (${error})`);
|
||||
});
|
||||
} else {
|
||||
console.log(`HockeyApp: skipping due to unexpected context (repository: ${repository}, codeVersion: ${codeVersion}, electronVersion: ${electronVersion}, quality: ${product.quality})`);
|
||||
}
|
||||
100
build/tfs/continuous-build.yml
Normal file
100
build/tfs/continuous-build.yml
Normal file
@@ -0,0 +1,100 @@
|
||||
phases:
|
||||
- phase: Windows
|
||||
queue: Hosted VS2017
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
yarn
|
||||
.\node_modules\.bin\gulp electron
|
||||
npm run gulp -- hygiene
|
||||
.\node_modules\.bin\tsc -p .\src\tsconfig.monaco.json --noEmit
|
||||
npm run compile
|
||||
node build/lib/builtInExtensions.js
|
||||
name: build
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
.\scripts\test.bat --tfs
|
||||
.\scripts\test-integration.bat
|
||||
yarn smoketest --screenshots "$(Build.ArtifactStagingDirectory)\artifacts" --log "$(Build.ArtifactStagingDirectory)\artifacts\smoketest.log"
|
||||
name: test
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts'
|
||||
ArtifactName: build-artifacts-win32
|
||||
publishLocation: Container
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: Linux
|
||||
queue: Hosted Linux Preview
|
||||
steps:
|
||||
- script: |
|
||||
set -e
|
||||
apt-get update
|
||||
apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 libgconf-2-4 dbus xvfb libgtk-3-0
|
||||
cp build/tfs/linux/x64/xvfb.init /etc/init.d/xvfb
|
||||
chmod +x /etc/init.d/xvfb
|
||||
update-rc.d xvfb defaults
|
||||
ln -sf /bin/dbus-daemon /usr/bin/dbus-daemon
|
||||
service xvfb start
|
||||
service dbus start
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
- script: |
|
||||
set -e
|
||||
yarn
|
||||
npm run gulp -- electron-x64
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- hygiene
|
||||
./node_modules/.bin/tsc -p ./src/tsconfig.monaco.json --noEmit
|
||||
npm run compile
|
||||
node build/lib/builtInExtensions.js
|
||||
name: build
|
||||
- script: |
|
||||
set -e
|
||||
DISPLAY=:10 ./scripts/test.sh --tfs
|
||||
# DISPLAY=:10 ./scripts/test-integration.sh
|
||||
name: test
|
||||
|
||||
- phase: macOS
|
||||
queue: Hosted macOS Preview
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
- script: |
|
||||
set -e
|
||||
yarn
|
||||
npm run gulp -- electron-x64
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- hygiene
|
||||
./node_modules/.bin/tsc -p ./src/tsconfig.monaco.json --noEmit
|
||||
npm run compile
|
||||
node build/lib/builtInExtensions.js
|
||||
name: build
|
||||
- script: |
|
||||
set -e
|
||||
./scripts/test.sh --tfs
|
||||
./scripts/test-integration.sh
|
||||
yarn smoketest --screenshots "$(Build.ArtifactStagingDirectory)/artifacts" --log "$(Build.ArtifactStagingDirectory)/artifacts/smoketest.log"
|
||||
name: test
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts'
|
||||
ArtifactName: build-artifacts-darwin
|
||||
publishLocation: Container
|
||||
condition: succeededOrFailed()
|
||||
51
build/tfs/darwin/build.yml
Normal file
51
build/tfs/darwin/build.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
steps:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
|
||||
- script: |
|
||||
echo "machine monacotools.visualstudio.com password $(VSO_PAT)" > ~/.netrc
|
||||
yarn
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin electron
|
||||
node build/tfs/common/installDistro.js
|
||||
|
||||
- script: |
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-darwin-min
|
||||
name: build
|
||||
|
||||
- script: |
|
||||
./scripts/test.sh --build --tfs
|
||||
name: test
|
||||
|
||||
- script: |
|
||||
# archive the unsigned build
|
||||
pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin-unsigned.zip * && popd
|
||||
|
||||
# publish the unsigned build
|
||||
PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json`
|
||||
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
||||
node build/tfs/common/publish.js \
|
||||
"$(VSCODE_QUALITY)" \
|
||||
darwin \
|
||||
archive-unsigned \
|
||||
"VSCode-darwin-$(VSCODE_QUALITY)-unsigned.zip" \
|
||||
$VERSION \
|
||||
false \
|
||||
../VSCode-darwin-unsigned.zip
|
||||
|
||||
# enqueue the unsigned build
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
node build/tfs/common/enqueue.js "$(VSCODE_QUALITY)"
|
||||
|
||||
npm run gulp -- upload-vscode-configuration
|
||||
103
build/tfs/linux/build.yml
Normal file
103
build/tfs/linux/build.yml
Normal file
@@ -0,0 +1,103 @@
|
||||
steps:
|
||||
|
||||
- script: |
|
||||
# dependencies
|
||||
dpkg --add-architecture i386
|
||||
apt-get update
|
||||
|
||||
DEPS=" \
|
||||
gcc-multilib g++-multilib \
|
||||
pkg-config \
|
||||
dbus \
|
||||
xvfb \
|
||||
fakeroot \
|
||||
bc \
|
||||
bsdmainutils \
|
||||
rpm \
|
||||
"
|
||||
|
||||
if [[ "$(VSCODE_ARCH)" == "x64" ]]; then
|
||||
DEPS="$DEPS \
|
||||
dpkg-dev \
|
||||
libgconf-2-4 \
|
||||
libnss3 \
|
||||
libasound2 \
|
||||
libxtst6 \
|
||||
libx11-dev \
|
||||
libxkbfile-dev \
|
||||
libxss1 \
|
||||
libx11-xcb-dev \
|
||||
libsecret-1-dev \
|
||||
"
|
||||
else
|
||||
DEPS="$DEPS \
|
||||
dpkg-dev:i386 \
|
||||
libgconf-2-4:i386 \
|
||||
libnss3:i386 \
|
||||
libasound2:i386 \
|
||||
libxtst6:i386 \
|
||||
libnotify4:i386 \
|
||||
libx11-dev:i386 \
|
||||
libxkbfile-dev:i386 \
|
||||
libxss1:i386 \
|
||||
libx11-xcb-dev:i386 \
|
||||
libgl1-mesa-glx:i386 libgl1-mesa-dri:i386 \
|
||||
libgirepository-1.0-1:i386 \
|
||||
gir1.2-glib-2.0:i386 \
|
||||
gir1.2-secret-1:i386 \
|
||||
libsecret-1-dev:i386 \
|
||||
libgtk2.0-0:i386 \
|
||||
"
|
||||
fi
|
||||
|
||||
apt-get install -y $DEPS
|
||||
|
||||
# setup xvfb
|
||||
cp build/tfs/linux/$(VSCODE_ARCH)/xvfb.init /etc/init.d/xvfb
|
||||
chmod +x /etc/init.d/xvfb
|
||||
update-rc.d xvfb defaults
|
||||
service xvfb start
|
||||
|
||||
# setup dbus
|
||||
ln -sf /bin/dbus-daemon /usr/bin/dbus-daemon
|
||||
service dbus start
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
|
||||
- script: |
|
||||
export npm_config_arch="$(VSCODE_ARCH)"
|
||||
if [[ "$(VSCODE_ARCH)" == "ia32" ]]; then
|
||||
export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig"
|
||||
fi
|
||||
|
||||
echo "machine monacotools.visualstudio.com password $(VSO_PAT)" > ~/.netrc
|
||||
yarn
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
|
||||
node build/tfs/common/installDistro.js
|
||||
|
||||
- script: |
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min
|
||||
name: build
|
||||
|
||||
- script: |
|
||||
npm run gulp -- "electron-$(VSCODE_ARCH)"
|
||||
DISPLAY=:10 ./scripts/test.sh --build --tfs
|
||||
name: test
|
||||
|
||||
- script: |
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-deb"
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-rpm"
|
||||
#npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-snap"
|
||||
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
||||
./build/tfs/linux/release2.sh "$(VSCODE_ARCH)" "$(LINUX_REPO_PASSWORD)"
|
||||
67
build/tfs/linux/release2.sh
Executable file
67
build/tfs/linux/release2.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Arguments
|
||||
ARCH="$1"
|
||||
LINUX_REPO_PASSWORD="$2"
|
||||
|
||||
# Variables
|
||||
PLATFORM_LINUX="linux-$ARCH"
|
||||
PLATFORM_DEB="linux-deb-$ARCH"
|
||||
PLATFORM_RPM="linux-rpm-$ARCH"
|
||||
[[ "$ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
|
||||
[[ "$ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64"
|
||||
REPO="`pwd`"
|
||||
ROOT="$REPO/.."
|
||||
BUILDNAME="VSCode-$PLATFORM_LINUX"
|
||||
BUILD="$ROOT/$BUILDNAME"
|
||||
BUILD_VERSION="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/ | sed -e 's/code-[a-z]*_//g' -e 's/\.deb$//g')"
|
||||
[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz"
|
||||
TARBALL_PATH="$ROOT/$TARBALL_FILENAME"
|
||||
PACKAGEJSON="$BUILD/resources/app/package.json"
|
||||
VERSION=$(node -p "require(\"$PACKAGEJSON\").version")
|
||||
|
||||
rm -rf $ROOT/code-*.tar.*
|
||||
(cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME)
|
||||
|
||||
node build/tfs/common/publish.js $VSCODE_QUALITY $PLATFORM_LINUX archive-unsigned $TARBALL_FILENAME $VERSION true $TARBALL_PATH
|
||||
|
||||
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
|
||||
DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
|
||||
|
||||
node build/tfs/common/publish.js $VSCODE_QUALITY $PLATFORM_DEB package $DEB_FILENAME $VERSION true $DEB_PATH
|
||||
|
||||
RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)"
|
||||
RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
|
||||
|
||||
node build/tfs/common/publish.js $VSCODE_QUALITY $PLATFORM_RPM package $RPM_FILENAME $VERSION true $RPM_PATH
|
||||
|
||||
# SNAP_FILENAME="$(ls $REPO/.build/linux/snap/$ARCH/ | grep .snap)"
|
||||
# SNAP_PATH="$REPO/.build/linux/snap/$ARCH/$SNAP_FILENAME"
|
||||
|
||||
IS_FROZEN="$(node build/tfs/linux/frozen-check.js $VSCODE_QUALITY)"
|
||||
|
||||
if [ -z "$VSCODE_QUALITY" ]; then
|
||||
echo "VSCODE_QUALITY is not set, skipping repo package publish"
|
||||
elif [ "$IS_FROZEN" = "true" ]; then
|
||||
echo "$VSCODE_QUALITY is frozen, skipping repo package publish"
|
||||
else
|
||||
if [ "$BUILD_SOURCEBRANCH" = "master" ] || [ "$BUILD_SOURCEBRANCH" = "refs/heads/master" ]; then
|
||||
if [[ $BUILD_QUEUEDBY = *"Project Collection Service Accounts"* || $BUILD_QUEUEDBY = *"Microsoft.VisualStudio.Services.TFS"* ]]; then
|
||||
# Write config files needed by API, use eval to force environment variable expansion
|
||||
pushd build/tfs/linux
|
||||
# Submit to apt repo
|
||||
if [ "$DEB_ARCH" = "amd64" ]; then
|
||||
eval echo '{ \"server\": \"azure-apt-cat.cloudapp.net\", \"protocol\": \"https\", \"port\": \"443\", \"repositoryId\": \"58a4adf642421134a1a48d1a\", \"username\": \"vscode\", \"password\": \"$LINUX_REPO_PASSWORD\" }' > apt-config.json
|
||||
|
||||
./repoapi_client.sh -config apt-config.json -addfile $DEB_PATH
|
||||
fi
|
||||
# Submit to yum repo (disabled as it's manual until signing is automated)
|
||||
# eval echo '{ \"server\": \"azure-apt-cat.cloudapp.net\", \"protocol\": \"https\", \"port\": \"443\", \"repositoryId\": \"58a4ae3542421134a1a48d1b\", \"username\": \"vscode\", \"password\": \"$LINUX_REPO_PASSWORD\" }' > yum-config.json
|
||||
|
||||
# ./repoapi_client.sh -config yum-config.json -addfile $RPM_PATH
|
||||
popd
|
||||
echo "To check repo publish status run ./repoapi_client.sh -config config.json -check <id>"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
413
build/tfs/product-build.yml
Normal file
413
build/tfs/product-build.yml
Normal file
@@ -0,0 +1,413 @@
|
||||
phases:
|
||||
- phase: Windows
|
||||
condition: eq(variables['VSCODE_BUILD_WIN32'], 'true')
|
||||
queue:
|
||||
name: Hosted VS2017
|
||||
parallel: 2
|
||||
matrix:
|
||||
x64:
|
||||
VSCODE_ARCH: x64
|
||||
ia32:
|
||||
VSCODE_ARCH: ia32
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
"machine monacotools.visualstudio.com password $(VSO_PAT)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII
|
||||
$env:npm_config_arch="$(VSCODE_ARCH)"
|
||||
$env:CHILD_CONCURRENCY="1"
|
||||
yarn
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
|
||||
npm run gulp -- mixin
|
||||
node build/tfs/common/installDistro.js
|
||||
node build/lib/builtInExtensions.js
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
|
||||
npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-min"
|
||||
npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-copy-inno-updater"
|
||||
name: build
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
npm run gulp -- "electron-$(VSCODE_ARCH)"
|
||||
.\scripts\test.bat --build --tfs
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)"
|
||||
name: test
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)'
|
||||
Pattern: '*.dll,*.exe,*.node'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
[
|
||||
{
|
||||
"keyCode": "CP-229803",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "VS Code"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "https://code.visualstudio.com/"
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/t \"http://ts4096.gtm.microsoft.com/TSS/AuthenticodeTS\""
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "VS Code"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "https://code.visualstudio.com/"
|
||||
},
|
||||
{
|
||||
"parameterName": "Append",
|
||||
"parameterValue": "/as"
|
||||
},
|
||||
{
|
||||
"parameterName": "FileDigest",
|
||||
"parameterValue": "/fd \"SHA256\""
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolVerify",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "VerifyAll",
|
||||
"parameterValue": "/all"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 120
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-archive" "vscode-win32-$(VSCODE_ARCH)-setup"
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)'
|
||||
Pattern: VSCodeSetup.exe
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
[
|
||||
{
|
||||
"keyCode": "CP-229803",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "VS Code"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "https://code.visualstudio.com/"
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/t \"http://ts4096.gtm.microsoft.com/TSS/AuthenticodeTS\""
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "VS Code"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "https://code.visualstudio.com/"
|
||||
},
|
||||
{
|
||||
"parameterName": "Append",
|
||||
"parameterValue": "/as"
|
||||
},
|
||||
{
|
||||
"parameterName": "FileDigest",
|
||||
"parameterValue": "/fd \"SHA256\""
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolVerify",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "VerifyAll",
|
||||
"parameterValue": "/all"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 120
|
||||
|
||||
- powershell: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Repo = "$(pwd)"
|
||||
$Root = "$Repo\.."
|
||||
$Exe = "$Repo\.build\win32-$(VSCODE_ARCH)\setup\VSCodeSetup.exe"
|
||||
$Zip = "$Repo\.build\win32-$(VSCODE_ARCH)\archive\VSCode-win32-$(VSCODE_ARCH).zip"
|
||||
$Build = "$Root\VSCode-win32-$(VSCODE_ARCH)"
|
||||
|
||||
# get version
|
||||
$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json
|
||||
$Version = $PackageJson.version
|
||||
$Quality = "$env:VSCODE_QUALITY"
|
||||
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)"
|
||||
$env:MOONCAKE_STORAGE_ACCESS_KEY = "$(MOONCAKE_STORAGE_ACCESS_KEY)"
|
||||
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)"
|
||||
|
||||
$assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" }
|
||||
|
||||
node build/tfs/common/publish.js $Quality "$global:assetPlatform-archive" archive "VSCode-win32-$(VSCODE_ARCH)-$Version.zip" $Version true $Zip
|
||||
node build/tfs/common/publish.js $Quality "$global:assetPlatform" setup "VSCodeSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $Exe
|
||||
|
||||
# publish hockeyapp symbols
|
||||
$hockeyAppId = if ("$(VSCODE_ARCH)" -eq "ia32") { "$(VSCODE_HOCKEYAPP_ID_WIN32)" } else { "$(VSCODE_HOCKEYAPP_ID_WIN64)" }
|
||||
node build/tfs/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" $hockeyAppId
|
||||
|
||||
- phase: Linux
|
||||
condition: eq(variables['VSCODE_BUILD_LINUX'], 'true')
|
||||
queue: linux-x64
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
export npm_config_arch="$(VSCODE_ARCH)"
|
||||
if [[ "$(VSCODE_ARCH)" == "ia32" ]]; then
|
||||
export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig"
|
||||
fi
|
||||
|
||||
echo "machine monacotools.visualstudio.com password $(VSO_PAT)" > ~/.netrc
|
||||
yarn
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
|
||||
node build/tfs/common/installDistro.js
|
||||
node build/lib/builtInExtensions.js
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min
|
||||
name: build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- "electron-$(VSCODE_ARCH)"
|
||||
DISPLAY=:10 ./scripts/test.sh --build --tfs
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)"
|
||||
name: test
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-deb"
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-rpm"
|
||||
#npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-snap"
|
||||
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
||||
./build/tfs/linux/release2.sh "$(VSCODE_ARCH)" "$(LINUX_REPO_PASSWORD)"
|
||||
|
||||
# publish hockeyapp symbols
|
||||
node build/tfs/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_LINUX64)"
|
||||
|
||||
- phase: Linux32
|
||||
condition: eq(variables['VSCODE_BUILD_LINUX'], 'true')
|
||||
queue: linux-ia32
|
||||
variables:
|
||||
VSCODE_ARCH: ia32
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
export npm_config_arch="$(VSCODE_ARCH)"
|
||||
if [[ "$(VSCODE_ARCH)" == "ia32" ]]; then
|
||||
export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig"
|
||||
fi
|
||||
|
||||
echo "machine monacotools.visualstudio.com password $(VSO_PAT)" > ~/.netrc
|
||||
yarn
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
|
||||
node build/tfs/common/installDistro.js
|
||||
node build/lib/builtInExtensions.js
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min
|
||||
name: build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- "electron-$(VSCODE_ARCH)"
|
||||
DISPLAY=:10 ./scripts/test.sh --build --tfs
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)"
|
||||
name: test
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-deb"
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-rpm"
|
||||
#npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-snap"
|
||||
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
||||
./build/tfs/linux/release2.sh "$(VSCODE_ARCH)" "$(LINUX_REPO_PASSWORD)"
|
||||
|
||||
# publish hockeyapp symbols
|
||||
node build/tfs/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_LINUX32)"
|
||||
|
||||
- phase: macOS
|
||||
condition: eq(variables['VSCODE_BUILD_MACOS'], 'true')
|
||||
queue: Hosted macOS Preview
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
echo "machine monacotools.visualstudio.com password $(VSO_PAT)" > ~/.netrc
|
||||
yarn
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
|
||||
node build/tfs/common/installDistro.js
|
||||
node build/lib/builtInExtensions.js
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
|
||||
npm run gulp -- vscode-darwin-min upload-vscode-sourcemaps
|
||||
name: build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
./scripts/test.sh --build --tfs
|
||||
APP_NAME="`ls $(agent.builddirectory)/VSCode-darwin | head -n 1`"
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-darwin/$APP_NAME"
|
||||
name: test
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
# archive the unsigned build
|
||||
pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin-unsigned.zip * && popd
|
||||
|
||||
# publish the unsigned build
|
||||
PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json`
|
||||
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \
|
||||
node build/tfs/common/publish.js \
|
||||
"$(VSCODE_QUALITY)" \
|
||||
darwin \
|
||||
archive-unsigned \
|
||||
"VSCode-darwin-$(VSCODE_QUALITY)-unsigned.zip" \
|
||||
$VERSION \
|
||||
false \
|
||||
../VSCode-darwin-unsigned.zip
|
||||
|
||||
# publish hockeyapp symbols
|
||||
node build/tfs/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_MACOS)"
|
||||
|
||||
# enqueue the unsigned build
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
node build/tfs/common/enqueue.js "$(VSCODE_QUALITY)"
|
||||
|
||||
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
|
||||
npm run gulp -- upload-vscode-configuration
|
||||
212
build/tfs/win32/build.yml
Normal file
212
build/tfs/win32/build.yml
Normal file
@@ -0,0 +1,212 @@
|
||||
steps:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.9.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.3.2"
|
||||
|
||||
- powershell: |
|
||||
"machine monacotools.visualstudio.com password $(VSO_PAT)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII
|
||||
$env:npm_config_arch="$(VSCODE_ARCH)"
|
||||
$env:CHILD_CONCURRENCY="1"
|
||||
yarn
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
|
||||
npm run gulp -- mixin
|
||||
node build/tfs/common/installDistro.js
|
||||
|
||||
- powershell: |
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
|
||||
npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-min"
|
||||
npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-copy-inno-updater"
|
||||
name: build
|
||||
|
||||
- powershell: |
|
||||
npm run gulp -- "electron-$(VSCODE_ARCH)"
|
||||
.\scripts\test.bat --build --tfs
|
||||
name: test
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)'
|
||||
Pattern: '*.dll,*.exe,*.node'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
[
|
||||
{
|
||||
"keyCode": "CP-229803",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "Microsoft"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "http://www.microsoft.com"
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/t \"http://ts4096.gtm.microsoft.com/TSS/AuthenticodeTS\""
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "Microsoft"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "http://www.microsoft.com"
|
||||
},
|
||||
{
|
||||
"parameterName": "Append",
|
||||
"parameterValue": "/as"
|
||||
},
|
||||
{
|
||||
"parameterName": "FileDigest",
|
||||
"parameterValue": "/fd \"SHA256\""
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolVerify",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "VerifyAll",
|
||||
"parameterValue": "/all"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 120
|
||||
|
||||
- powershell: |
|
||||
npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-archive" "vscode-win32-$(VSCODE_ARCH)-setup"
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)'
|
||||
Pattern: VSCodeSetup.exe
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
[
|
||||
{
|
||||
"keyCode": "CP-229803",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "Microsoft"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "http://www.microsoft.com"
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/t \"http://ts4096.gtm.microsoft.com/TSS/AuthenticodeTS\""
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolSign",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "Microsoft"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "http://www.microsoft.com"
|
||||
},
|
||||
{
|
||||
"parameterName": "Append",
|
||||
"parameterValue": "/as"
|
||||
},
|
||||
{
|
||||
"parameterName": "FileDigest",
|
||||
"parameterValue": "/fd \"SHA256\""
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"keyCode": "CP-230012",
|
||||
"operationSetCode": "SigntoolVerify",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "VerifyAll",
|
||||
"parameterValue": "/all"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 120
|
||||
|
||||
- powershell: |
|
||||
$Repo = "$(pwd)"
|
||||
$Root = "$Repo\.."
|
||||
$Exe = "$Repo\.build\win32-$(VSCODE_ARCH)\setup\VSCodeSetup.exe"
|
||||
$Zip = "$Repo\.build\win32-$(VSCODE_ARCH)\archive\VSCode-win32-$(VSCODE_ARCH).zip"
|
||||
$Build = "$Root\VSCode-win32-$(VSCODE_ARCH)"
|
||||
|
||||
# get version
|
||||
$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json
|
||||
$Version = $PackageJson.version
|
||||
$Quality = "$env:VSCODE_QUALITY"
|
||||
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)"
|
||||
$env:MOONCAKE_STORAGE_ACCESS_KEY = "$(MOONCAKE_STORAGE_ACCESS_KEY)"
|
||||
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)"
|
||||
|
||||
$assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" }
|
||||
|
||||
node build/tfs/common/publish.js $Quality "$global:assetPlatform-archive" archive "VSCode-win32-$(VSCODE_ARCH)-$Version.zip" $Version true $Zip
|
||||
node build/tfs/common/publish.js $Quality "$global:assetPlatform" setup "VSCodeSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $Exe
|
||||
@@ -7,7 +7,6 @@
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": false,
|
||||
"experimentalDecorators": true,
|
||||
"newLine": "LF",
|
||||
// enable JavaScript type checking for the language service
|
||||
// use the tsconfig.build.json for compiling wich disable JavaScript
|
||||
// type checking so that JavaScript file are not transpiled
|
||||
|
||||
814
build/win32/OSSREADME.json
Normal file → Executable file
814
build/win32/OSSREADME.json
Normal file → Executable file
@@ -1,198 +1,10 @@
|
||||
[
|
||||
{
|
||||
"name": "dtolnay/isatty",
|
||||
"version": "0.1.6",
|
||||
"repositoryUrl": "https://github.com/dtolnay/isatty",
|
||||
"name": "Amanieu/thread_local-rs",
|
||||
"version": "0.3.5",
|
||||
"repositoryUrl": "https://github.com/Amanieu/thread_local-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2016",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num-integer",
|
||||
"version": "0.1.35",
|
||||
"repositoryUrl": "https://github.com/rust-num/num-integer",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-lang-nursery/lazy-static.rs",
|
||||
"version": "1.0.0",
|
||||
"repositoryUrl": "https://github.com/rust-lang-nursery/lazy-static.rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2010 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-lang/libc",
|
||||
"version": "0.2.36",
|
||||
"repositoryUrl": "https://github.com/rust-lang/libc",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.2.2",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "mrhooray/crc-rs",
|
||||
"version": "1.7.0",
|
||||
"repositoryUrl": "https://github.com/mrhooray/crc-rs.git",
|
||||
"licenseDetail": [
|
||||
"MIT License",
|
||||
"",
|
||||
"Copyright (c) 2017 crc-rs Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num",
|
||||
"version": "0.1.41",
|
||||
"repositoryUrl": "https://github.com/rust-num/num",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"Copyright (c) 2016 The Rust Project Developers",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any",
|
||||
"person obtaining a copy of this software and associated",
|
||||
@@ -250,141 +62,13 @@
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num-traits",
|
||||
"version": "0.1.42",
|
||||
"repositoryUrl": "https://github.com/rust-num/num-traits",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "slog-rs/slog",
|
||||
"version": "2.1.1",
|
||||
"repositoryUrl": "https://github.com/slog-rs/slog",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num-iter",
|
||||
"version": "0.1.34",
|
||||
"repositoryUrl": "https://github.com/rust-num/num-iter",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "vitiral/build_const",
|
||||
"name": "Sgeo/take_mut",
|
||||
"version": "0.2.0",
|
||||
"repositoryUrl": "https://github.com/vitiral/build_const",
|
||||
"repositoryUrl": "https://github.com/Sgeo/take_mut",
|
||||
"licenseDetail": [
|
||||
"The Source EULA",
|
||||
"",
|
||||
"Copyright (c) 2017 Garrett Berg, vitiral@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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "redox-os/termios",
|
||||
"version": "0.1.1",
|
||||
"repositoryUrl": "https://github.com/redox-os/termios",
|
||||
"licenseDetail": [
|
||||
"MIT License",
|
||||
"",
|
||||
"Copyright (c) 2017 Redox OS",
|
||||
"Copyright (c) 2016 Sgeo",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy",
|
||||
"of this software and associated documentation files (the \"Software\"), to deal",
|
||||
@@ -406,36 +90,6 @@
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "redox-os/syscall",
|
||||
"version": "0.1.37",
|
||||
"repositoryUrl": "https://github.com/redox-os/syscall",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2017 Redox OS Developers",
|
||||
"",
|
||||
"MIT License",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "Stebalien/term",
|
||||
"version": "0.4.6",
|
||||
@@ -717,11 +371,11 @@
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "Amanieu/thread_local-rs",
|
||||
"version": "0.3.5",
|
||||
"repositoryUrl": "https://github.com/Amanieu/thread_local-rs",
|
||||
"name": "dtolnay/isatty",
|
||||
"version": "0.1.6",
|
||||
"repositoryUrl": "https://github.com/dtolnay/isatty",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2016 The Rust Project Developers",
|
||||
"Copyright (c) 2016",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any",
|
||||
"person obtaining a copy of this software and associated",
|
||||
@@ -750,13 +404,13 @@
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "Sgeo/take_mut",
|
||||
"version": "0.2.0",
|
||||
"repositoryUrl": "https://github.com/Sgeo/take_mut",
|
||||
"name": "mrhooray/crc-rs",
|
||||
"version": "1.7.0",
|
||||
"repositoryUrl": "https://github.com/mrhooray/crc-rs.git",
|
||||
"licenseDetail": [
|
||||
"The Source EULA",
|
||||
"MIT License",
|
||||
"",
|
||||
"Copyright (c) 2016 Sgeo",
|
||||
"Copyright (c) 2017 crc-rs Developers",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy",
|
||||
"of this software and associated documentation files (the \"Software\"), to deal",
|
||||
@@ -779,11 +433,43 @@
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "reem/rust-void",
|
||||
"version": "1.0.2",
|
||||
"repositoryUrl": "https://github.com/reem/rust-void.git",
|
||||
"name": "redox-os/syscall",
|
||||
"version": "0.1.37",
|
||||
"repositoryUrl": "https://github.com/redox-os/syscall",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The rust-void Developers",
|
||||
"Copyright (c) 2017 Redox OS Developers",
|
||||
"",
|
||||
"MIT License",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "redox-os/termios",
|
||||
"version": "0.1.1",
|
||||
"repositoryUrl": "https://github.com/redox-os/termios",
|
||||
"licenseDetail": [
|
||||
"MIT License",
|
||||
"",
|
||||
"Copyright (c) 2017 Redox OS",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy",
|
||||
"of this software and associated documentation files (the \"Software\"), to deal",
|
||||
@@ -833,46 +519,11 @@
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-lang/time",
|
||||
"version": "0.1.39",
|
||||
"repositoryUrl": "https://github.com/rust-lang/time",
|
||||
"name": "reem/rust-void",
|
||||
"version": "1.0.2",
|
||||
"repositoryUrl": "https://github.com/reem/rust-void.git",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "ticki/termion",
|
||||
"version": "1.5.1",
|
||||
"repositoryUrl": "https://github.com/ticki/termion",
|
||||
"licenseDetail": [
|
||||
"The Source EULA",
|
||||
"",
|
||||
"Copyright (c) 2016 Ticki",
|
||||
"Copyright (c) 2015 The rust-void Developers",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy",
|
||||
"of this software and associated documentation files (the \"Software\"), to deal",
|
||||
@@ -896,7 +547,7 @@
|
||||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.2.8",
|
||||
"version": "0.3.4",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
@@ -923,7 +574,7 @@
|
||||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.3.4",
|
||||
"version": "0.2.8",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
@@ -1029,6 +680,264 @@
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.2.2",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-lang-nursery/lazy-static.rs",
|
||||
"version": "1.0.0",
|
||||
"repositoryUrl": "https://github.com/rust-lang-nursery/lazy-static.rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2010 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-lang/libc",
|
||||
"version": "0.2.36",
|
||||
"repositoryUrl": "https://github.com/rust-lang/libc",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-lang/time",
|
||||
"version": "0.1.39",
|
||||
"repositoryUrl": "https://github.com/rust-lang/time",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num",
|
||||
"version": "0.1.41",
|
||||
"repositoryUrl": "https://github.com/rust-num/num",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num-integer",
|
||||
"version": "0.1.35",
|
||||
"repositoryUrl": "https://github.com/rust-num/num-integer",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num-iter",
|
||||
"version": "0.1.34",
|
||||
"repositoryUrl": "https://github.com/rust-num/num-iter",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "rust-num/num-traits",
|
||||
"version": "0.1.42",
|
||||
"repositoryUrl": "https://github.com/rust-num/num-traits",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "slog-rs/async",
|
||||
"version": "2.2.0",
|
||||
@@ -1410,6 +1319,39 @@
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "slog-rs/slog",
|
||||
"version": "2.1.1",
|
||||
"repositoryUrl": "https://github.com/slog-rs/slog",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2014 The Rust Project Developers",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "slog-rs/term",
|
||||
"version": "2.3.0",
|
||||
@@ -1790,5 +1732,63 @@
|
||||
" defined by the Mozilla Public License, v. 2.0."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "ticki/termion",
|
||||
"version": "1.5.1",
|
||||
"repositoryUrl": "https://github.com/ticki/termion",
|
||||
"licenseDetail": [
|
||||
"The MIT License (MIT)",
|
||||
"",
|
||||
"Copyright (c) 2016 Ticki",
|
||||
"",
|
||||
"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."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "vitiral/build_const",
|
||||
"version": "0.2.0",
|
||||
"repositoryUrl": "https://github.com/vitiral/build_const",
|
||||
"licenseDetail": [
|
||||
"The MIT License (MIT)",
|
||||
"",
|
||||
"Copyright (c) 2017 Garrett Berg, vitiral@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."
|
||||
],
|
||||
"isProd": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -60,7 +60,9 @@ Type: files; Name: "{app}\resources\app\Credits_45.0.2454.85.html"; Check: IsNot
|
||||
Type: filesandordirs; Name: "{app}\_"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
|
||||
Name: "associatewithfiles"; Description: "{cm:AssociateWithFiles,{#NameShort}}"; GroupDescription: "{cm:Other}"; Flags: unchecked
|
||||
Name: "addtopath"; Description: "{cm:AddToPath}"; GroupDescription: "{cm:Other}"
|
||||
Name: "runcode"; Description: "{cm:RunAfter,{#NameShort}}"; GroupDescription: "{cm:Other}"; Check: WizardSilent
|
||||
|
||||
@@ -82,6 +84,13 @@ Root: HKCR; Subkey: "{#RegValueName}SourceFile\DefaultIcon"; ValueType: string;
|
||||
Root: HKCR; Subkey: "{#RegValueName}SourceFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""
|
||||
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\bin"; Tasks: addtopath; Check: NeedsAddPath(ExpandConstant('{app}\bin'))
|
||||
|
||||
Root: HKCU; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\.sql\OpenWithProgids"; ValueType: string; ValueName: "{#RegValueName}.sql"; ValueData: ""; Flags: uninsdeletevalue; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,SQL}"; Flags: uninsdeletekey; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql"; ValueType: string; ValueName: "AppUserModelID"; ValueData: "{#AppUserId}"; Flags: uninsdeletekey; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"; Tasks: associatewithfiles
|
||||
Root: HKCU; Subkey: "Software\Classes\{#RegValueName}.sql\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles
|
||||
|
||||
[Code]
|
||||
// Don't allow installing conflicting architectures
|
||||
function InitializeSetup(): Boolean;
|
||||
|
||||
Binary file not shown.
145
build/yarn.lock
145
build/yarn.lock
@@ -8,6 +8,10 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/caseless@*":
|
||||
version "0.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.1.tgz#9794c69c8385d0192acc471a540d1f8e0d16218a"
|
||||
|
||||
"@types/documentdb@1.10.2":
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/documentdb/-/documentdb-1.10.2.tgz#6795025cdc51577af5ed531b6f03bd44404f5350"
|
||||
@@ -22,6 +26,12 @@
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/es6-promise/-/es6-promise-0.0.33.tgz#280a707e62b1b6bef1a86cc0861ec63cd06c7ff3"
|
||||
|
||||
"@types/form-data@*":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e"
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/mime@0.0.29":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-0.0.29.tgz#fbcfd330573b912ef59eeee14602bface630754b"
|
||||
@@ -34,6 +44,19 @@
|
||||
version "8.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd"
|
||||
|
||||
"@types/request@^2.47.0":
|
||||
version "2.47.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/request/-/request-2.47.0.tgz#76a666cee4cb85dcffea6cd4645227926d9e114e"
|
||||
dependencies:
|
||||
"@types/caseless" "*"
|
||||
"@types/form-data" "*"
|
||||
"@types/node" "*"
|
||||
"@types/tough-cookie" "*"
|
||||
|
||||
"@types/tough-cookie@*":
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.3.tgz#7f226d67d654ec9070e755f46daebf014628e9d9"
|
||||
|
||||
"@types/xml2js@0.0.33":
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.0.33.tgz#20c5dd6460245284d64a55690015b95e409fb7de"
|
||||
@@ -331,6 +354,10 @@ color-support@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
|
||||
|
||||
colors@^1.1.2:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e"
|
||||
|
||||
combined-stream@1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
|
||||
@@ -707,6 +734,15 @@ getpass@^0.1.1:
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
github-releases@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/github-releases/-/github-releases-0.4.1.tgz#4a13bdf85c4161344271db3d81db08e7379102ff"
|
||||
dependencies:
|
||||
minimatch "3.0.4"
|
||||
optimist "0.6.1"
|
||||
prettyjson "1.2.1"
|
||||
request "2.81.0"
|
||||
|
||||
glob-base@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
|
||||
@@ -1362,7 +1398,7 @@ mime@^1.3.4:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||
|
||||
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.4:
|
||||
"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
dependencies:
|
||||
@@ -1376,6 +1412,10 @@ minimist@^1.1.0, minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
|
||||
minimist@~0.0.1:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
|
||||
|
||||
mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
@@ -1453,6 +1493,13 @@ once@^1.3.0, once@^1.4.0:
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
optimist@0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
|
||||
dependencies:
|
||||
minimist "~0.0.1"
|
||||
wordwrap "~0.0.2"
|
||||
|
||||
ordered-read-streams@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
|
||||
@@ -1531,6 +1578,13 @@ preserve@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||
|
||||
prettyjson@1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289"
|
||||
dependencies:
|
||||
colors "^1.1.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
priorityqueuejs@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/priorityqueuejs/-/priorityqueuejs-1.0.0.tgz#2ee4f23c2560913e08c07ce5ccdd6de3df2c5af8"
|
||||
@@ -1649,6 +1703,33 @@ replace-ext@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
|
||||
|
||||
request@2.81.0, request@~2.81.0:
|
||||
version "2.81.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
||||
dependencies:
|
||||
aws-sign2 "~0.6.0"
|
||||
aws4 "^1.2.1"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.5"
|
||||
extend "~3.0.0"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.1.1"
|
||||
har-validator "~4.2.1"
|
||||
hawk "~3.1.3"
|
||||
http-signature "~1.1.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.7"
|
||||
oauth-sign "~0.8.1"
|
||||
performance-now "^0.2.0"
|
||||
qs "~6.4.0"
|
||||
safe-buffer "^5.0.1"
|
||||
stringstream "~0.0.4"
|
||||
tough-cookie "~2.3.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.0.0"
|
||||
|
||||
request@^2.83.0:
|
||||
version "2.85.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa"
|
||||
@@ -1676,6 +1757,31 @@ request@^2.83.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
|
||||
request@^2.85.0:
|
||||
version "2.87.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e"
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.6.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.5"
|
||||
extend "~3.0.1"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.1"
|
||||
har-validator "~5.0.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.17"
|
||||
oauth-sign "~0.8.2"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.1"
|
||||
safe-buffer "^5.1.1"
|
||||
tough-cookie "~2.3.3"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
|
||||
request@~2.79.0:
|
||||
version "2.79.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
|
||||
@@ -1701,33 +1807,6 @@ request@~2.79.0:
|
||||
tunnel-agent "~0.4.1"
|
||||
uuid "^3.0.0"
|
||||
|
||||
request@~2.81.0:
|
||||
version "2.81.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
||||
dependencies:
|
||||
aws-sign2 "~0.6.0"
|
||||
aws4 "^1.2.1"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.5"
|
||||
extend "~3.0.0"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.1.1"
|
||||
har-validator "~4.2.1"
|
||||
hawk "~3.1.3"
|
||||
http-signature "~1.1.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.7"
|
||||
oauth-sign "~0.8.1"
|
||||
performance-now "^0.2.0"
|
||||
qs "~6.4.0"
|
||||
safe-buffer "^5.0.1"
|
||||
stringstream "~0.0.4"
|
||||
tough-cookie "~2.3.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.0.0"
|
||||
|
||||
requires-port@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||
@@ -1978,9 +2057,9 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
|
||||
typescript@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631"
|
||||
typescript@2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624"
|
||||
|
||||
unbzip2-stream@^1.0.9:
|
||||
version "1.2.5"
|
||||
@@ -2129,6 +2208,10 @@ vscode@^1.0.1:
|
||||
url-parse "^1.1.9"
|
||||
vinyl-source-stream "^1.1.0"
|
||||
|
||||
wordwrap@~0.0.2:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
# Microsoft SQL Server Agent for SQL Operations Studio
|
||||
|
||||
Welcome to Microsoft SQL Server Agent for SQL Operations Studio! An extension for managing and troubleshooting
|
||||
SQL Server Agent jobs and configuration. The current is a very early release of this extension that provides
|
||||
SQL Server Agent jobs and configuration. The current is an early release of this extension that provides
|
||||
basic functionality for the following.
|
||||
|
||||
* List SQL Server Agent Jobs configured on a SQL Server
|
||||
* View Job History with job execution results
|
||||
* Basic Job Control to start and stop jobs
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/599935/39215738-d3a52580-47cd-11e8-9788-b290048c270e.png" alt="SQL Agent" style="width:800px;"/>
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as data from 'sqlops';
|
||||
import { ApiWrapper } from './apiWrapper';
|
||||
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
*/
|
||||
export class MainController {
|
||||
protected _apiWrapper: ApiWrapper;
|
||||
protected _context: vscode.ExtensionContext;
|
||||
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
public constructor(context: vscode.ExtensionContext, apiWrapper?: ApiWrapper) {
|
||||
this._apiWrapper = apiWrapper || new ApiWrapper();
|
||||
this._context = context;
|
||||
|
||||
console.log('Got: ' + apiWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the extension
|
||||
*/
|
||||
public deactivate(): void {
|
||||
}
|
||||
|
||||
public activate(): void {
|
||||
|
||||
this._apiWrapper.registerWebviewProvider('data-management-agent', webview => {
|
||||
webview.html = '<div><h1>SQL Agent</h1></div>';
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,57 @@
|
||||
{
|
||||
"name": "agent",
|
||||
"displayName": "SQL Server Agent",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs (early preview)",
|
||||
"version": "0.28.0",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs",
|
||||
"version": "0.32.4",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/sqlopsstudio/master/LICENSE.txt",
|
||||
"icon": "images/sqlserver.png",
|
||||
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
|
||||
"engines": {
|
||||
"vscode": "0.10.x"
|
||||
"vscode": "0.10.x"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./client/out/main",
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:agent-client"
|
||||
},
|
||||
"main": "./out/main",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/sqlopsstudio.git"
|
||||
},
|
||||
"extensionDependencies": [
|
||||
"Microsoft.mssql"
|
||||
],
|
||||
"contributes": {
|
||||
"outputChannels": [
|
||||
"sqlagent"
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "agent.openNewStepDialog",
|
||||
"title": "agent.openNewStepDialog"
|
||||
}
|
||||
],
|
||||
"dashboard.tabs": [
|
||||
{
|
||||
"id": "data-management-agent",
|
||||
"description": "Manage and troubleshoot SQL Agent jobs",
|
||||
"provider": "MSSQL",
|
||||
"title": "SQL Agent",
|
||||
"container": {
|
||||
"controlhost-container": {
|
||||
"type": "agent"
|
||||
}
|
||||
}
|
||||
{
|
||||
"id": "data-management-agent",
|
||||
"description": "Manage and troubleshoot SQL Agent jobs",
|
||||
"provider": "MSSQL",
|
||||
"title": "SQL Agent",
|
||||
"when": "connectionProvider == 'MSSQL' && !mssql:iscloud",
|
||||
"container": {
|
||||
"controlhost-container": {
|
||||
"type": "agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vscode": "1.0.1"
|
||||
}
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
"mocha-multi-reporters": "^1.1.7"
|
||||
}
|
||||
}
|
||||
|
||||
38
extensions/agent/src/agentUtils.ts
Normal file
38
extensions/agent/src/agentUtils.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
export class AgentUtils {
|
||||
|
||||
private static _agentService: sqlops.AgentServicesProvider;
|
||||
private static _connectionService: sqlops.ConnectionProvider;
|
||||
private static _queryProvider: sqlops.QueryProvider;
|
||||
|
||||
public static async getAgentService(): Promise<sqlops.AgentServicesProvider> {
|
||||
if (!AgentUtils._agentService) {
|
||||
let currentConnection = await sqlops.connection.getCurrentConnection();
|
||||
this._agentService = sqlops.dataprotocol.getProvider<sqlops.AgentServicesProvider>(currentConnection.providerName, sqlops.DataProviderType.AgentServicesProvider);
|
||||
}
|
||||
return AgentUtils._agentService;
|
||||
}
|
||||
|
||||
public static async getDatabases(ownerUri: string): Promise<string[]> {
|
||||
if (!AgentUtils._connectionService) {
|
||||
let currentConnection = await sqlops.connection.getCurrentConnection();
|
||||
this._connectionService = sqlops.dataprotocol.getProvider<sqlops.ConnectionProvider>(currentConnection.providerName, sqlops.DataProviderType.ConnectionProvider);
|
||||
}
|
||||
return AgentUtils._connectionService.listDatabases(ownerUri).then(result => {
|
||||
if (result && result.databaseNames && result.databaseNames.length > 0) {
|
||||
return result.databaseNames;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static async getQueryProvider(): Promise<sqlops.QueryProvider> {
|
||||
if (!AgentUtils._queryProvider) {
|
||||
let currentConnection = await sqlops.connection.getCurrentConnection();
|
||||
this._queryProvider = sqlops.dataprotocol.getProvider<sqlops.QueryProvider>(currentConnection.providerName, sqlops.DataProviderType.QueryProvider);
|
||||
}
|
||||
return this._queryProvider;
|
||||
}
|
||||
}
|
||||
132
extensions/agent/src/data/alertData.ts
Normal file
132
extensions/agent/src/data/alertData.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as vscode from 'vscode';
|
||||
import * as sqlops from 'sqlops';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AlertData implements IAgentDialogData {
|
||||
public static readonly AlertTypeSqlServerEventString: string = localize('alertData.DefaultAlertTypString', 'SQL Server event alert');
|
||||
public static readonly AlertTypePerformanceConditionString: string = localize('alertDialog.PerformanceCondition', 'SQL Server performance condition alert');
|
||||
public static readonly AlertTypeWmiEventString: string = localize('alertDialog.WmiEvent', 'WMI event alert');
|
||||
public static readonly DefaultAlertTypeString: string = AlertData.AlertTypeSqlServerEventString;
|
||||
|
||||
ownerUri: string;
|
||||
dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
id: number;
|
||||
name: string;
|
||||
originalName: string;
|
||||
delayBetweenResponses: number;
|
||||
eventDescriptionKeyword: string;
|
||||
eventSource: string;
|
||||
hasNotification: number;
|
||||
includeEventDescription: string;
|
||||
isEnabled: boolean = true;
|
||||
jobId: string;
|
||||
jobName: string;
|
||||
lastOccurrenceDate: string;
|
||||
lastResponseDate: string;
|
||||
messageId: number;
|
||||
notificationMessage: string;
|
||||
occurrenceCount: number;
|
||||
performanceCondition: string;
|
||||
severity: number;
|
||||
databaseName: string;
|
||||
countResetDate: string;
|
||||
categoryName: string;
|
||||
alertType: string = AlertData.DefaultAlertTypeString;
|
||||
wmiEventNamespace: string;
|
||||
wmiEventQuery: string;
|
||||
|
||||
constructor(ownerUri:string, alertInfo: sqlops.AgentAlertInfo) {
|
||||
this.ownerUri = ownerUri;
|
||||
|
||||
if (alertInfo) {
|
||||
this.dialogMode = AgentDialogMode.EDIT;
|
||||
this.id = alertInfo.id;
|
||||
this.name = alertInfo.name;
|
||||
this.originalName = alertInfo.name;
|
||||
this.delayBetweenResponses = alertInfo.delayBetweenResponses;
|
||||
this.eventDescriptionKeyword = alertInfo.eventDescriptionKeyword;
|
||||
this.eventSource = alertInfo.eventSource;
|
||||
this.hasNotification = alertInfo.hasNotification;
|
||||
this.includeEventDescription = alertInfo.includeEventDescription.toString();
|
||||
this.isEnabled = alertInfo.isEnabled;
|
||||
this.jobId = alertInfo.jobId;
|
||||
this.jobName = alertInfo.jobName;
|
||||
this.lastOccurrenceDate = alertInfo.lastOccurrenceDate;
|
||||
this.lastResponseDate = alertInfo.lastResponseDate;
|
||||
this.messageId = alertInfo.messageId;
|
||||
this.notificationMessage = alertInfo.notificationMessage;
|
||||
this.occurrenceCount = alertInfo.occurrenceCount;
|
||||
this.performanceCondition = alertInfo.performanceCondition;
|
||||
this.severity = alertInfo.severity;
|
||||
this.databaseName = alertInfo.databaseName;
|
||||
this.countResetDate = alertInfo.countResetDate;
|
||||
this.categoryName = alertInfo.categoryName;
|
||||
this.alertType = alertInfo.alertType.toString();
|
||||
this.wmiEventNamespace = alertInfo.wmiEventNamespace;
|
||||
this.wmiEventQuery = alertInfo.wmiEventQuery;
|
||||
}
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
}
|
||||
|
||||
public async save() {
|
||||
let agentService = await AgentUtils.getAgentService();
|
||||
let result = this.dialogMode === AgentDialogMode.CREATE
|
||||
? await agentService.createAlert(this.ownerUri, this.toAgentAlertInfo())
|
||||
: await agentService.updateAlert(this.ownerUri, this.originalName, this.toAgentAlertInfo());
|
||||
|
||||
if (!result || !result.success) {
|
||||
vscode.window.showErrorMessage(
|
||||
localize('alertData.saveErrorMessage', "Alert update failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
|
||||
}
|
||||
}
|
||||
|
||||
public toAgentAlertInfo(): sqlops.AgentAlertInfo {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
delayBetweenResponses: this.delayBetweenResponses,
|
||||
eventDescriptionKeyword: this.eventDescriptionKeyword,
|
||||
eventSource: this.eventSource,
|
||||
hasNotification: this.hasNotification,
|
||||
includeEventDescription: sqlops.NotifyMethods.none, // this.includeEventDescription,
|
||||
isEnabled: this.isEnabled,
|
||||
jobId: this.jobId,
|
||||
jobName: this.jobName,
|
||||
lastOccurrenceDate: this.lastOccurrenceDate,
|
||||
lastResponseDate: this.lastResponseDate,
|
||||
messageId: this.messageId,
|
||||
notificationMessage: this.notificationMessage,
|
||||
occurrenceCount: this.occurrenceCount,
|
||||
performanceCondition: this.performanceCondition,
|
||||
severity: this.severity,
|
||||
databaseName: this.databaseName,
|
||||
countResetDate: this.countResetDate,
|
||||
categoryName: this.categoryName,
|
||||
alertType: AlertData.getAlertTypeFromString(this.alertType),
|
||||
wmiEventNamespace: this.wmiEventNamespace,
|
||||
wmiEventQuery: this.wmiEventQuery
|
||||
};
|
||||
}
|
||||
|
||||
private static getAlertTypeFromString(alertTypeString: string): sqlops.AlertType {
|
||||
if (alertTypeString === AlertData.AlertTypePerformanceConditionString) {
|
||||
return sqlops.AlertType.sqlServerPerformanceCondition;
|
||||
} else if (alertTypeString === AlertData.AlertTypeWmiEventString) {
|
||||
return sqlops.AlertType.wmiEvent;
|
||||
} else {
|
||||
return sqlops.AlertType.sqlServerEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
177
extensions/agent/src/data/jobData.ts
Normal file
177
extensions/agent/src/data/jobData.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class JobData implements IAgentDialogData {
|
||||
|
||||
private readonly JobCompletionActionCondition_Always: string = localize('jobData.whenJobCompletes', 'When the job completes');
|
||||
private readonly JobCompletionActionCondition_OnFailure: string = localize('jobData.whenJobFails', 'When the job fails');
|
||||
private readonly JobCompletionActionCondition_OnSuccess: string = localize('jobData.whenJobSucceeds', 'When the job succeeds');
|
||||
|
||||
// Error Messages
|
||||
private readonly CreateJobErrorMessage_NameIsEmpty = localize('jobData.jobNameRequired', 'Job name must be provided');
|
||||
|
||||
private _ownerUri: string;
|
||||
private _jobCategories: string[];
|
||||
private _operators: string[];
|
||||
private _defaultOwner: string;
|
||||
private _jobCompletionActionConditions: sqlops.CategoryValue[];
|
||||
|
||||
public dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
public name: string;
|
||||
public originalName: string;
|
||||
public enabled: boolean = true;
|
||||
public description: string;
|
||||
public category: string;
|
||||
public categoryId: number;
|
||||
public owner: string;
|
||||
public emailLevel: sqlops.JobCompletionActionCondition = sqlops.JobCompletionActionCondition.OnFailure;
|
||||
public pageLevel: sqlops.JobCompletionActionCondition = sqlops.JobCompletionActionCondition.OnFailure;
|
||||
public eventLogLevel: sqlops.JobCompletionActionCondition = sqlops.JobCompletionActionCondition.OnFailure;
|
||||
public deleteLevel: sqlops.JobCompletionActionCondition = sqlops.JobCompletionActionCondition.OnSuccess;
|
||||
public operatorToEmail: string;
|
||||
public operatorToPage: string;
|
||||
public jobSteps: sqlops.AgentJobStepInfo[];
|
||||
public jobSchedules: sqlops.AgentJobScheduleInfo[];
|
||||
public alerts: sqlops.AgentAlertInfo[];
|
||||
|
||||
constructor(
|
||||
ownerUri: string,
|
||||
jobInfo: sqlops.AgentJobInfo = undefined,
|
||||
private _agentService: sqlops.AgentServicesProvider = undefined) {
|
||||
|
||||
this._ownerUri = ownerUri;
|
||||
if (jobInfo) {
|
||||
this.dialogMode = AgentDialogMode.EDIT;
|
||||
this.name = jobInfo.name;
|
||||
this.originalName = jobInfo.name;
|
||||
this.owner = jobInfo.owner;
|
||||
this.category = jobInfo.category;
|
||||
this.description = jobInfo.description;
|
||||
this.enabled = jobInfo.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public get jobCategories(): string[] {
|
||||
return this._jobCategories;
|
||||
}
|
||||
|
||||
public get operators(): string[] {
|
||||
return this._operators;
|
||||
}
|
||||
|
||||
public get ownerUri(): string {
|
||||
return this._ownerUri;
|
||||
}
|
||||
|
||||
public get defaultOwner(): string {
|
||||
return this._defaultOwner;
|
||||
}
|
||||
|
||||
public get JobCompletionActionConditions(): sqlops.CategoryValue[] {
|
||||
return this._jobCompletionActionConditions;
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
this._agentService = await AgentUtils.getAgentService();
|
||||
let jobDefaults = await this._agentService.getJobDefaults(this.ownerUri);
|
||||
if (jobDefaults && jobDefaults.success) {
|
||||
this._jobCategories = jobDefaults.categories.map((cat) => {
|
||||
return cat.name;
|
||||
});
|
||||
|
||||
this._defaultOwner = jobDefaults.owner;
|
||||
|
||||
this._operators = ['', this._defaultOwner];
|
||||
}
|
||||
|
||||
this._jobCompletionActionConditions = [{
|
||||
displayName: this.JobCompletionActionCondition_OnSuccess,
|
||||
name: sqlops.JobCompletionActionCondition.OnSuccess.toString()
|
||||
}, {
|
||||
displayName: this.JobCompletionActionCondition_OnFailure,
|
||||
name: sqlops.JobCompletionActionCondition.OnFailure.toString()
|
||||
}, {
|
||||
displayName: this.JobCompletionActionCondition_Always,
|
||||
name: sqlops.JobCompletionActionCondition.Always.toString()
|
||||
}];
|
||||
|
||||
this.jobSchedules = [];
|
||||
}
|
||||
|
||||
public async save() {
|
||||
let jobInfo: sqlops.AgentJobInfo = this.toAgentJobInfo();
|
||||
let result = this.dialogMode === AgentDialogMode.CREATE
|
||||
? await this._agentService.createJob(this.ownerUri, jobInfo)
|
||||
: await this._agentService.updateJob(this.ownerUri, this.originalName, jobInfo);
|
||||
|
||||
if (!result || !result.success) {
|
||||
vscode.window.showErrorMessage(
|
||||
localize('jobData.saveErrorMessage', "Job update failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
|
||||
}
|
||||
}
|
||||
|
||||
public validate(): { valid: boolean, errorMessages: string[] } {
|
||||
let validationErrors: string[] = [];
|
||||
|
||||
if (!(this.name && this.name.trim())) {
|
||||
validationErrors.push(this.CreateJobErrorMessage_NameIsEmpty);
|
||||
}
|
||||
|
||||
return {
|
||||
valid: validationErrors.length === 0,
|
||||
errorMessages: validationErrors
|
||||
};
|
||||
}
|
||||
|
||||
public addJobSchedule(schedule: sqlops.AgentJobScheduleInfo) {
|
||||
let existingSchedule = this.jobSchedules.find(item => item.name === schedule.name);
|
||||
if (!existingSchedule) {
|
||||
this.jobSchedules.push(schedule);
|
||||
}
|
||||
}
|
||||
|
||||
public toAgentJobInfo(): sqlops.AgentJobInfo {
|
||||
return {
|
||||
name: this.name,
|
||||
owner: this.owner,
|
||||
description: this.description,
|
||||
EmailLevel: this.emailLevel,
|
||||
PageLevel: this.pageLevel,
|
||||
EventLogLevel: this.eventLogLevel,
|
||||
DeleteLevel: this.deleteLevel,
|
||||
OperatorToEmail: this.operatorToEmail,
|
||||
OperatorToPage: this.operatorToPage,
|
||||
enabled: this.enabled,
|
||||
category: this.category,
|
||||
Alerts: this.alerts,
|
||||
JobSchedules: this.jobSchedules,
|
||||
JobSteps: this.jobSteps,
|
||||
// The properties below are not collected from UI
|
||||
// We could consider using a seperate class for create job request
|
||||
//
|
||||
currentExecutionStatus: 0,
|
||||
lastRunOutcome: 0,
|
||||
currentExecutionStep: '',
|
||||
hasTarget: true,
|
||||
hasSchedule: false,
|
||||
hasStep: false,
|
||||
runnable: true,
|
||||
categoryId: 0,
|
||||
categoryType: 1, // LocalJob, hard-coding the value, corresponds to the target tab in SSMS
|
||||
lastRun: '',
|
||||
nextRun: '',
|
||||
jobId: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
76
extensions/agent/src/data/jobStepData.ts
Normal file
76
extensions/agent/src/data/jobStepData.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
export class JobStepData implements IAgentDialogData {
|
||||
public dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
public ownerUri: string;
|
||||
public jobId: string; //
|
||||
public jobName: string;
|
||||
public script: string; //
|
||||
public scriptName: string;
|
||||
public stepName: string; //
|
||||
public subSystem: string; //
|
||||
public id: number;
|
||||
public failureAction: string; //
|
||||
public successAction: string; //
|
||||
public failStepId: number;
|
||||
public successStepId: number;
|
||||
public command: string;
|
||||
public commandExecutionSuccessCode: number;
|
||||
public databaseName: string; //
|
||||
public databaseUserName: string;
|
||||
public server: string;
|
||||
public outputFileName: string; //
|
||||
public appendToLogFile: boolean;
|
||||
public appendToStepHist: boolean;
|
||||
public writeLogToTable: boolean;
|
||||
public appendLogToTable: boolean;
|
||||
public retryAttempts: number; //
|
||||
public retryInterval: number; //
|
||||
public proxyName: string;
|
||||
|
||||
constructor(ownerUri:string) {
|
||||
this.ownerUri = ownerUri;
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
}
|
||||
|
||||
public async save() {
|
||||
let agentService = await AgentUtils.getAgentService();
|
||||
agentService.createJobStep(this.ownerUri, {
|
||||
jobId: this.jobId,
|
||||
jobName: this.jobName,
|
||||
script: this.script,
|
||||
scriptName: this.scriptName,
|
||||
stepName: this.stepName,
|
||||
subSystem: this.subSystem,
|
||||
id: 1,
|
||||
failureAction: this.failureAction,
|
||||
successAction: this.successAction,
|
||||
failStepId: this.failStepId,
|
||||
successStepId: this.successStepId,
|
||||
command: this.command,
|
||||
commandExecutionSuccessCode: this.commandExecutionSuccessCode,
|
||||
databaseName: this.databaseName,
|
||||
databaseUserName: this.databaseUserName,
|
||||
server: this.server,
|
||||
outputFileName: this.outputFileName,
|
||||
appendToLogFile: this.appendToLogFile,
|
||||
appendToStepHist: this.appendToStepHist,
|
||||
writeLogToTable: this.writeLogToTable,
|
||||
appendLogToTable: this.appendLogToTable,
|
||||
retryAttempts: this.retryAttempts,
|
||||
retryInterval: this.retryInterval,
|
||||
proxyName: this.proxyName
|
||||
}).then(result => {
|
||||
console.info(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
74
extensions/agent/src/data/operatorData.ts
Normal file
74
extensions/agent/src/data/operatorData.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
export class OperatorData implements IAgentDialogData {
|
||||
public dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
ownerUri: string;
|
||||
name: string;
|
||||
id: number;
|
||||
emailAddress: string;
|
||||
enabled: boolean;
|
||||
lastEmailDate: string;
|
||||
lastNetSendDate: string;
|
||||
lastPagerDate: string;
|
||||
pagerAddress: string;
|
||||
categoryName: string;
|
||||
pagerDays: string;
|
||||
saturdayPagerEndTime: string;
|
||||
saturdayPagerStartTime: string;
|
||||
sundayPagerEndTime: string;
|
||||
sundayPagerStartTime: string;
|
||||
netSendAddress: string;
|
||||
weekdayPagerStartTime: string;
|
||||
weekdayPagerEndTime: string;
|
||||
|
||||
constructor(ownerUri:string, operatorInfo: sqlops.AgentOperatorInfo) {
|
||||
this.ownerUri = ownerUri;
|
||||
|
||||
if (operatorInfo) {
|
||||
this.dialogMode = AgentDialogMode.EDIT;
|
||||
this.name = operatorInfo.name;
|
||||
this.enabled = operatorInfo.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
}
|
||||
|
||||
public async save() {
|
||||
let agentService = await AgentUtils.getAgentService();
|
||||
let result = await agentService.createOperator(this.ownerUri, this.toAgentOperatorInfo());
|
||||
if (!result || !result.success) {
|
||||
// TODO handle error here
|
||||
}
|
||||
}
|
||||
|
||||
public toAgentOperatorInfo(): sqlops.AgentOperatorInfo {
|
||||
return {
|
||||
name: this.name,
|
||||
id: this.id,
|
||||
emailAddress: this.emailAddress,
|
||||
enabled: this.enabled,
|
||||
lastEmailDate: this.lastEmailDate,
|
||||
lastNetSendDate: this.lastNetSendDate,
|
||||
lastPagerDate: this.lastPagerDate,
|
||||
pagerAddress: this.pagerAddress,
|
||||
categoryName: this.categoryName,
|
||||
pagerDays: sqlops.WeekDays.weekDays, //this.pagerDays,
|
||||
saturdayPagerEndTime: this.saturdayPagerEndTime,
|
||||
saturdayPagerStartTime: this.saturdayPagerStartTime,
|
||||
sundayPagerEndTime: this.sundayPagerEndTime,
|
||||
sundayPagerStartTime: this.sundayPagerStartTime,
|
||||
netSendAddress: this.netSendAddress,
|
||||
weekdayPagerStartTime: this.weekdayPagerStartTime,
|
||||
weekdayPagerEndTime: this.weekdayPagerEndTime
|
||||
};
|
||||
}
|
||||
}
|
||||
31
extensions/agent/src/data/pickScheduleData.ts
Normal file
31
extensions/agent/src/data/pickScheduleData.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
export class PickScheduleData implements IAgentDialogData {
|
||||
public dialogMode: AgentDialogMode = AgentDialogMode.VIEW;
|
||||
public ownerUri: string;
|
||||
public schedules: sqlops.AgentJobScheduleInfo[];
|
||||
public selectedSchedule: sqlops.AgentJobScheduleInfo;
|
||||
|
||||
constructor(ownerUri:string) {
|
||||
this.ownerUri = ownerUri;
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
let agentService = await AgentUtils.getAgentService();
|
||||
let result = await agentService.getJobSchedules(this.ownerUri);
|
||||
if (result && result.success) {
|
||||
this.schedules = result.schedules;
|
||||
}
|
||||
}
|
||||
|
||||
public async save() {
|
||||
}
|
||||
}
|
||||
54
extensions/agent/src/data/proxyData.ts
Normal file
54
extensions/agent/src/data/proxyData.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
export class ProxyData implements IAgentDialogData {
|
||||
public dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
ownerUri: string;
|
||||
id: number;
|
||||
accountName: string;
|
||||
description: string;
|
||||
credentialName: string;
|
||||
credentialIdentity: string;
|
||||
credentialId: number;
|
||||
isEnabled: boolean;
|
||||
|
||||
constructor(ownerUri:string, proxyInfo: sqlops.AgentProxyInfo) {
|
||||
this.ownerUri = ownerUri;
|
||||
|
||||
if (proxyInfo) {
|
||||
this.accountName = proxyInfo.accountName;
|
||||
this.credentialName = proxyInfo.credentialName;
|
||||
this.description = proxyInfo.description;
|
||||
}
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
}
|
||||
|
||||
public async save() {
|
||||
let agentService = await AgentUtils.getAgentService();
|
||||
let result = await agentService.createProxy(this.ownerUri, this.toAgentProxyInfo());
|
||||
if (!result || !result.success) {
|
||||
// TODO handle error here
|
||||
}
|
||||
}
|
||||
|
||||
public toAgentProxyInfo(): sqlops.AgentProxyInfo {
|
||||
return {
|
||||
id: this.id,
|
||||
accountName: this.accountName,
|
||||
description: this.description,
|
||||
credentialName: this.credentialName,
|
||||
credentialIdentity: this.credentialIdentity,
|
||||
credentialId: this.credentialId,
|
||||
isEnabled: this.isEnabled
|
||||
};
|
||||
}
|
||||
}
|
||||
31
extensions/agent/src/data/scheduleData.ts
Normal file
31
extensions/agent/src/data/scheduleData.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
export class ScheduleData implements IAgentDialogData {
|
||||
public dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
public ownerUri: string;
|
||||
public schedules: sqlops.AgentJobScheduleInfo[];
|
||||
public selectedSchedule: sqlops.AgentJobScheduleInfo;
|
||||
|
||||
constructor(ownerUri:string) {
|
||||
this.ownerUri = ownerUri;
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
let agentService = await AgentUtils.getAgentService();
|
||||
let result = await agentService.getJobSchedules(this.ownerUri);
|
||||
if (result && result.success) {
|
||||
this.schedules = result.schedules;
|
||||
}
|
||||
}
|
||||
|
||||
public async save() {
|
||||
}
|
||||
}
|
||||
78
extensions/agent/src/dialogs/agentDialog.ts
Normal file
78
extensions/agent/src/dialogs/agentDialog.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export abstract class AgentDialog<T extends IAgentDialogData> {
|
||||
|
||||
private static readonly OkButtonText: string = localize('agentDialog.OK', 'OK');
|
||||
private static readonly CancelButtonText: string = localize('agentDialog.Cancel', 'Cancel');
|
||||
|
||||
protected _onSuccess: vscode.EventEmitter<T> = new vscode.EventEmitter<T>();
|
||||
public readonly onSuccess: vscode.Event<T> = this._onSuccess.event;
|
||||
public dialog: sqlops.window.modelviewdialog.Dialog;
|
||||
|
||||
constructor(public ownerUri: string, public model: T, public title: string) {
|
||||
}
|
||||
|
||||
public get dialogMode(): AgentDialogMode {
|
||||
return this.model.dialogMode;
|
||||
}
|
||||
|
||||
protected abstract async updateModel();
|
||||
|
||||
protected abstract async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog);
|
||||
|
||||
public async openDialog() {
|
||||
this.dialog = sqlops.window.modelviewdialog.createDialog(this.title);
|
||||
|
||||
await this.model.initialize();
|
||||
|
||||
await this.initializeDialog(this.dialog);
|
||||
|
||||
this.dialog.okButton.label = AgentDialog.OkButtonText;
|
||||
this.dialog.okButton.onClick(async () => await this.execute());
|
||||
|
||||
this.dialog.cancelButton.label = AgentDialog.CancelButtonText;
|
||||
this.dialog.cancelButton.onClick(async () => await this.cancel());
|
||||
|
||||
sqlops.window.modelviewdialog.openDialog(this.dialog);
|
||||
}
|
||||
|
||||
protected async execute() {
|
||||
this.updateModel();
|
||||
let success = await this.model.save();
|
||||
if (success) {
|
||||
this._onSuccess.fire(this.model);
|
||||
}
|
||||
}
|
||||
|
||||
protected async cancel() {
|
||||
}
|
||||
|
||||
protected getActualConditionValue(checkbox: sqlops.CheckBoxComponent, dropdown: sqlops.DropDownComponent): sqlops.JobCompletionActionCondition {
|
||||
return checkbox.checked ? Number(this.getDropdownValue(dropdown)) : sqlops.JobCompletionActionCondition.Never;
|
||||
}
|
||||
|
||||
protected getDropdownValue(dropdown: sqlops.DropDownComponent): string {
|
||||
return (typeof dropdown.value === 'string') ? dropdown.value : dropdown.value.name;
|
||||
}
|
||||
|
||||
protected setConditionDropdownSelectedValue(dropdown: sqlops.DropDownComponent, selectedValue: number) {
|
||||
let idx: number = 0;
|
||||
for (idx = 0; idx < dropdown.values.length; idx++) {
|
||||
if (Number((<sqlops.CategoryValue>dropdown.values[idx]).name) === selectedValue) {
|
||||
dropdown.value = dropdown.values[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
528
extensions/agent/src/dialogs/alertDialog.ts
Normal file
528
extensions/agent/src/dialogs/alertDialog.ts
Normal file
@@ -0,0 +1,528 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import { AgentDialog } from './agentDialog';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { AlertData } from '../data/alertData';
|
||||
import { OperatorDialog } from './operatorDialog';
|
||||
import { JobDialog } from './jobDialog';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AlertDialog extends AgentDialog<AlertData> {
|
||||
|
||||
// Top level
|
||||
private static readonly CreateDialogTitle: string = localize('alertDialog.createAlert', 'Create Alert');
|
||||
private static readonly EditDialogTitle: string = localize('alertDialog.editAlert', 'Edit Alert');
|
||||
private static readonly GeneralTabText: string = localize('alertDialog.General', 'General');
|
||||
private static readonly ResponseTabText: string = localize('alertDialog.Response', 'Response');
|
||||
private static readonly OptionsTabText: string = localize('alertDialog.Options', 'Options');
|
||||
private static readonly EventAlertText: string = localize('alertDialog.eventAlert', 'Event alert definition');
|
||||
|
||||
// General tab strings
|
||||
private static readonly NameLabel: string = localize('alertDialog.Name', 'Name');
|
||||
private static readonly TypeLabel: string = localize('alertDialog.Type', 'Type');
|
||||
private static readonly EnabledCheckboxLabel: string = localize('alertDialog.Enabled', 'Enabled');
|
||||
private static readonly DatabaseLabel: string = localize('alertDialog.DatabaseName', 'Database name');
|
||||
private static readonly ErrorNumberLabel: string = localize('alertDialog.ErrorNumber', 'Error number');
|
||||
private static readonly SeverityLabel: string = localize('alertDialog.Severity', 'Severity');
|
||||
private static readonly RaiseIfMessageContainsLabel: string = localize('alertDialog.RaiseAlertContains', 'Raise alert when message contains');
|
||||
private static readonly MessageTextLabel: string = localize('alertDialog.MessageText', 'Message text');
|
||||
private static readonly AlertSeverity001Label: string = localize('alertDialog.Severity001', '001 - Miscellaneous System Information');
|
||||
private static readonly AlertSeverity002Label: string = localize('alertDialog.Severity002', '002 - Reserved');
|
||||
private static readonly AlertSeverity003Label: string = localize('alertDialog.Severity003', '003 - Reserved');
|
||||
private static readonly AlertSeverity004Label: string = localize('alertDialog.Severity004', '004 - Reserved');
|
||||
private static readonly AlertSeverity005Label: string = localize('alertDialog.Severity005', '005 - Reserved');
|
||||
private static readonly AlertSeverity006Label: string = localize('alertDialog.Severity006', '006 - Reserved');
|
||||
private static readonly AlertSeverity007Label: string = localize('alertDialog.Severity007', '007 - Notification: Status Information');
|
||||
private static readonly AlertSeverity008Label: string = localize('alertDialog.Severity008', '008 - Notification: User Intervention Required');
|
||||
private static readonly AlertSeverity009Label: string = localize('alertDialog.Severity009', '009 - User Defined');
|
||||
private static readonly AlertSeverity010Label: string = localize('alertDialog.Severity010', '010 - Information');
|
||||
private static readonly AlertSeverity011Label: string = localize('alertDialog.Severity011', '011 - Specified Database Object Not Found');
|
||||
private static readonly AlertSeverity012Label: string = localize('alertDialog.Severity012', '012 - Unused');
|
||||
private static readonly AlertSeverity013Label: string = localize('alertDialog.Severity013', '013 - User Transaction Syntax Error');
|
||||
private static readonly AlertSeverity014Label: string = localize('alertDialog.Severity014', '014 - Insufficient Permission');
|
||||
private static readonly AlertSeverity015Label: string = localize('alertDialog.Severity015', '015 - Syntax Error in SQL Statements');
|
||||
private static readonly AlertSeverity016Label: string = localize('alertDialog.Severity016', '016 - Miscellaneous User Error');
|
||||
private static readonly AlertSeverity017Label: string = localize('alertDialog.Severity017', '017 - Insufficient Resources');
|
||||
private static readonly AlertSeverity018Label: string = localize('alertDialog.Severity018', '018 - Nonfatal Internal Error');
|
||||
private static readonly AlertSeverity019Label: string = localize('alertDialog.Severity019', '019 - Fatal Error in Resource');
|
||||
private static readonly AlertSeverity020Label: string = localize('alertDialog.Severity020', '020 - Fatal Error in Current Process');
|
||||
private static readonly AlertSeverity021Label: string = localize('alertDialog.Severity021', '021 - Fatal Error in Database Processes');
|
||||
private static readonly AlertSeverity022Label: string = localize('alertDialog.Severity022', '022 - Fatal Error: Table Integrity Suspect');
|
||||
private static readonly AlertSeverity023Label: string = localize('alertDialog.Severity023', '023 - Fatal Error: Database Integrity Suspect');
|
||||
private static readonly AlertSeverity024Label: string = localize('alertDialog.Severity024', '024 - Fatal Error: Hardware Error');
|
||||
private static readonly AlertSeverity025Label: string = localize('alertDialog.Severity025', '025 - Fatal Error');
|
||||
private static readonly AllDatabases: string = localize('alertDialog.AllDatabases', '<all databases>');
|
||||
|
||||
private static readonly AlertTypes: string[] = [
|
||||
AlertData.AlertTypeSqlServerEventString,
|
||||
// Disabled until next release
|
||||
// AlertData.AlertTypePerformanceConditionString,
|
||||
// AlertData.AlertTypeWmiEventString
|
||||
];
|
||||
|
||||
private static readonly AlertSeverities: string[] = [
|
||||
AlertDialog.AlertSeverity001Label,
|
||||
AlertDialog.AlertSeverity002Label,
|
||||
AlertDialog.AlertSeverity003Label,
|
||||
AlertDialog.AlertSeverity004Label,
|
||||
AlertDialog.AlertSeverity005Label,
|
||||
AlertDialog.AlertSeverity006Label,
|
||||
AlertDialog.AlertSeverity007Label,
|
||||
AlertDialog.AlertSeverity008Label,
|
||||
AlertDialog.AlertSeverity009Label,
|
||||
AlertDialog.AlertSeverity010Label,
|
||||
AlertDialog.AlertSeverity011Label,
|
||||
AlertDialog.AlertSeverity012Label,
|
||||
AlertDialog.AlertSeverity013Label,
|
||||
AlertDialog.AlertSeverity014Label,
|
||||
AlertDialog.AlertSeverity015Label,
|
||||
AlertDialog.AlertSeverity016Label,
|
||||
AlertDialog.AlertSeverity017Label,
|
||||
AlertDialog.AlertSeverity018Label,
|
||||
AlertDialog.AlertSeverity019Label,
|
||||
AlertDialog.AlertSeverity020Label,
|
||||
AlertDialog.AlertSeverity021Label,
|
||||
AlertDialog.AlertSeverity022Label,
|
||||
AlertDialog.AlertSeverity023Label,
|
||||
AlertDialog.AlertSeverity024Label,
|
||||
AlertDialog.AlertSeverity025Label
|
||||
];
|
||||
|
||||
// Response tab strings
|
||||
private static readonly ExecuteJobCheckBoxLabel: string = localize('alertDialog.ExecuteJob', 'Execute Job');
|
||||
private static readonly ExecuteJobTextBoxLabel: string = localize('alertDialog.ExecuteJobName', 'Job Name');
|
||||
private static readonly NotifyOperatorsTextBoxLabel: string = localize('alertDialog.NotifyOperators', 'Notify Operators');
|
||||
private static readonly NewJobButtonLabel: string = localize('alertDialog.NewJob', 'New Job');
|
||||
private static readonly OperatorListLabel: string = localize('alertDialog.OperatorList', 'Operator List');
|
||||
private static readonly OperatorNameColumnLabel: string = localize('alertDialog.OperatorName', 'Operator');
|
||||
private static readonly OperatorEmailColumnLabel: string = localize('alertDialog.OperatorEmail', 'E-mail');
|
||||
private static readonly OperatorPagerColumnLabel: string = localize('alertDialog.OperatorPager', 'Pager');
|
||||
private static readonly NewOperatorButtonLabel: string = localize('alertDialog.NewOperator', 'New Operator');
|
||||
|
||||
// Options tab strings
|
||||
private static readonly IncludeErrorInEmailCheckBoxLabel: string = localize('alertDialog.IncludeErrorInEmail', 'Include alert error text in e-mail');
|
||||
private static readonly IncludeErrorInPagerCheckBoxLabel: string = localize('alertDialog.IncludeErrorInPager', 'Include alert error text in pager');
|
||||
private static readonly AdditionalMessageTextBoxLabel: string = localize('alertDialog.AdditionalNotification', 'Additional notification message to send');
|
||||
private static readonly DelayBetweenResponsesTextBoxLabel: string = localize('alertDialog.DelayBetweenResponse', 'Delay between responses');
|
||||
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
|
||||
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
|
||||
|
||||
// UI Components
|
||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private responseTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private optionsTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
|
||||
// General tab controls
|
||||
private nameTextBox: sqlops.InputBoxComponent;
|
||||
private typeDropDown: sqlops.DropDownComponent;
|
||||
private severityDropDown: sqlops.DropDownComponent;
|
||||
private databaseDropDown: sqlops.DropDownComponent;
|
||||
private enabledCheckBox: sqlops.CheckBoxComponent;
|
||||
private errorNumberRadioButton: sqlops.RadioButtonComponent;
|
||||
private severityRadioButton: sqlops.RadioButtonComponent;
|
||||
private errorNumberTextBox: sqlops.InputBoxComponent;
|
||||
|
||||
private raiseAlertMessageCheckBox: sqlops.CheckBoxComponent;
|
||||
private raiseAlertMessageTextBox: sqlops.InputBoxComponent;
|
||||
|
||||
// Response tab controls
|
||||
private executeJobTextBox: sqlops.InputBoxComponent;
|
||||
private executeJobCheckBox: sqlops.CheckBoxComponent;
|
||||
private newJobButton: sqlops.ButtonComponent;
|
||||
private notifyOperatorsCheckBox: sqlops.CheckBoxComponent;
|
||||
private operatorsTable: sqlops.TableComponent;
|
||||
private newOperatorButton: sqlops.ButtonComponent;
|
||||
|
||||
// Options tab controls
|
||||
private additionalMessageTextBox: sqlops.InputBoxComponent;
|
||||
private includeErrorInEmailTextBox: sqlops.CheckBoxComponent;
|
||||
private includeErrorInPagerTextBox: sqlops.CheckBoxComponent;
|
||||
private delayMinutesTextBox: sqlops.InputBoxComponent;
|
||||
private delaySecondsTextBox: sqlops.InputBoxComponent;
|
||||
|
||||
private jobs: string[];
|
||||
private databases: string[];
|
||||
|
||||
constructor(ownerUri: string, alertInfo: sqlops.AgentAlertInfo = undefined, jobs: string[]) {
|
||||
super(ownerUri,
|
||||
new AlertData(ownerUri, alertInfo),
|
||||
alertInfo ? AlertDialog.EditDialogTitle : AlertDialog.CreateDialogTitle);
|
||||
this.jobs = jobs;
|
||||
}
|
||||
|
||||
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
this.databases = await AgentUtils.getDatabases(this.ownerUri);
|
||||
this.databases.unshift(AlertDialog.AllDatabases);
|
||||
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(AlertDialog.GeneralTabText);
|
||||
this.responseTab = sqlops.window.modelviewdialog.createTab(AlertDialog.ResponseTabText);
|
||||
this.optionsTab = sqlops.window.modelviewdialog.createTab(AlertDialog.OptionsTabText);
|
||||
|
||||
this.initializeGeneralTab(this.databases, dialog);
|
||||
this.initializeResponseTab();
|
||||
this.initializeOptionsTab();
|
||||
|
||||
dialog.content = [this.generalTab, this.responseTab, this.optionsTab];
|
||||
}
|
||||
|
||||
private initializeGeneralTab(databases: string[], dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
this.generalTab.registerContent(async view => {
|
||||
// create controls
|
||||
this.nameTextBox = view.modelBuilder.inputBox().component();
|
||||
this.nameTextBox.required = true;
|
||||
this.nameTextBox.onTextChanged(() => {
|
||||
if (this.nameTextBox.value.length > 0) {
|
||||
dialog.okButton.enabled = true;
|
||||
} else {
|
||||
dialog.okButton.enabled = false;
|
||||
}
|
||||
});
|
||||
this.enabledCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.EnabledCheckboxLabel
|
||||
}).component();
|
||||
|
||||
this.enabledCheckBox.checked = true;
|
||||
|
||||
this.databaseDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: databases[0],
|
||||
values: databases,
|
||||
width: '100%'
|
||||
}).component();
|
||||
|
||||
this.typeDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: '',
|
||||
values: AlertDialog.AlertTypes,
|
||||
width: '100%'
|
||||
}).component();
|
||||
|
||||
this.severityRadioButton = view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
value: 'serverity',
|
||||
name: 'alertTypeOptions',
|
||||
label: AlertDialog.SeverityLabel,
|
||||
checked: true
|
||||
}).component();
|
||||
this.severityRadioButton.checked = true;
|
||||
|
||||
this.severityDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: AlertDialog.AlertSeverities[0],
|
||||
values: AlertDialog.AlertSeverities,
|
||||
width: '100%'
|
||||
}).component();
|
||||
|
||||
this.errorNumberRadioButton = view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
value: 'errorNumber',
|
||||
name: 'alertTypeOptions',
|
||||
label: AlertDialog.ErrorNumberLabel
|
||||
}).component();
|
||||
|
||||
this.errorNumberTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
width: '100%'
|
||||
})
|
||||
.component();
|
||||
this.errorNumberTextBox.enabled = false;
|
||||
|
||||
this.errorNumberRadioButton.onDidClick(() => {
|
||||
this.errorNumberTextBox.enabled = true;
|
||||
this.severityDropDown.enabled = false;
|
||||
});
|
||||
|
||||
this.severityRadioButton.onDidClick(() => {
|
||||
this.errorNumberTextBox.enabled = false;
|
||||
this.severityDropDown.enabled = true;
|
||||
});
|
||||
|
||||
this.raiseAlertMessageCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.RaiseIfMessageContainsLabel
|
||||
}).component();
|
||||
|
||||
this.raiseAlertMessageTextBox = view.modelBuilder.inputBox().component();
|
||||
this.raiseAlertMessageTextBox.enabled = false;
|
||||
|
||||
this.raiseAlertMessageCheckBox.onChanged(() => {
|
||||
this.raiseAlertMessageTextBox.enabled = this.raiseAlertMessageCheckBox.checked;
|
||||
});
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.nameTextBox,
|
||||
title: AlertDialog.NameLabel
|
||||
}, {
|
||||
component: this.enabledCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.typeDropDown,
|
||||
title: AlertDialog.TypeLabel
|
||||
}, {
|
||||
components: [{
|
||||
component: this.databaseDropDown,
|
||||
title: AlertDialog.DatabaseLabel
|
||||
},
|
||||
{
|
||||
component: this.severityRadioButton,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.severityDropDown,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.errorNumberRadioButton,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.errorNumberTextBox,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.raiseAlertMessageCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.raiseAlertMessageTextBox,
|
||||
title: AlertDialog.MessageTextLabel
|
||||
}],
|
||||
title: AlertDialog.EventAlertText
|
||||
}
|
||||
]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
// initialize control values
|
||||
this.nameTextBox.value = this.model.name;
|
||||
this.raiseAlertMessageTextBox.value = this.model.eventDescriptionKeyword;
|
||||
this.typeDropDown.value = this.model.alertType;
|
||||
this.enabledCheckBox.checked = this.model.isEnabled;
|
||||
|
||||
if (this.model.messageId > 0) {
|
||||
this.errorNumberRadioButton.checked = true;
|
||||
this.errorNumberTextBox.value = this.model.messageId.toString();
|
||||
}
|
||||
|
||||
if (this.model.severity > 0) {
|
||||
this.severityRadioButton.checked = true;
|
||||
this.severityDropDown.value = this.severityDropDown.values[this.model.severity-1];
|
||||
}
|
||||
|
||||
if (this.model.databaseName) {
|
||||
let idx = this.databases.indexOf(this.model.databaseName);
|
||||
if (idx >= 0) {
|
||||
this.databaseDropDown.value = this.databases[idx];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initializeResponseTab() {
|
||||
this.responseTab.registerContent(async view => {
|
||||
this.executeJobCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.ExecuteJobCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
this.executeJobTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({ width: 375 })
|
||||
.component();
|
||||
this.executeJobTextBox.enabled = false;
|
||||
this.newJobButton = view.modelBuilder.button().withProperties({
|
||||
label: AlertDialog.NewJobButtonLabel,
|
||||
width: 80
|
||||
}).component();
|
||||
this.newJobButton.enabled = false;
|
||||
this.newJobButton.onDidClick(() => {
|
||||
let jobDialog = new JobDialog(this.ownerUri);
|
||||
jobDialog.openDialog();
|
||||
});
|
||||
|
||||
this.executeJobCheckBox.onChanged(() => {
|
||||
if (this.executeJobCheckBox.checked) {
|
||||
this.executeJobTextBox.enabled = true;
|
||||
this.newJobButton.enabled = true;
|
||||
} else {
|
||||
this.executeJobTextBox.enabled = false;
|
||||
this.newJobButton.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
let executeJobContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.executeJobTextBox,
|
||||
title: AlertDialog.ExecuteJobTextBoxLabel
|
||||
}, {
|
||||
component: this.newJobButton,
|
||||
title: AlertDialog.NewJobButtonLabel
|
||||
}], { componentWidth: '100%'}).component();
|
||||
|
||||
this.notifyOperatorsCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.NotifyOperatorsTextBoxLabel
|
||||
}).component();
|
||||
|
||||
this.operatorsTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
AlertDialog.OperatorNameColumnLabel,
|
||||
AlertDialog.OperatorEmailColumnLabel,
|
||||
AlertDialog.OperatorPagerColumnLabel
|
||||
],
|
||||
data: [],
|
||||
height: 500,
|
||||
width: 375
|
||||
}).component();
|
||||
|
||||
this.newOperatorButton = view.modelBuilder.button().withProperties({
|
||||
label: AlertDialog.NewOperatorButtonLabel,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.operatorsTable.enabled = false;
|
||||
this.newOperatorButton.enabled = false;
|
||||
|
||||
this.newOperatorButton.onDidClick(() => {
|
||||
let operatorDialog = new OperatorDialog(this.ownerUri);
|
||||
operatorDialog.openDialog();
|
||||
});
|
||||
|
||||
this.notifyOperatorsCheckBox.onChanged(() => {
|
||||
if (this.notifyOperatorsCheckBox.checked) {
|
||||
this.operatorsTable.enabled = true;
|
||||
this.newOperatorButton.enabled = true;
|
||||
} else {
|
||||
this.operatorsTable.enabled = false;
|
||||
this.newOperatorButton.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
let notifyOperatorContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.operatorsTable,
|
||||
title: AlertDialog.OperatorListLabel
|
||||
}, {
|
||||
component: this.newOperatorButton,
|
||||
title: ''
|
||||
}], { componentWidth: '100%'}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.executeJobCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: executeJobContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.notifyOperatorsCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: notifyOperatorContainer,
|
||||
title: ''
|
||||
}])
|
||||
.withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
}
|
||||
|
||||
private initializeOptionsTab() {
|
||||
this.optionsTab.registerContent(async view => {
|
||||
|
||||
this.includeErrorInEmailTextBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.IncludeErrorInEmailCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
this.includeErrorInPagerTextBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.IncludeErrorInPagerCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
this.additionalMessageTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.delayMinutesTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'number',
|
||||
placeHolder: 0
|
||||
})
|
||||
.component();
|
||||
|
||||
this.delaySecondsTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'number',
|
||||
placeHolder: 0
|
||||
})
|
||||
.component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.includeErrorInEmailTextBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.includeErrorInPagerTextBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.additionalMessageTextBox,
|
||||
title: AlertDialog.AdditionalMessageTextBoxLabel
|
||||
}, {
|
||||
component: this.delayMinutesTextBox,
|
||||
title: AlertDialog.DelayMinutesTextBoxLabel
|
||||
}, {
|
||||
component: this.delaySecondsTextBox,
|
||||
title: AlertDialog.DelaySecondsTextBoxLabel
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
}
|
||||
|
||||
private getSeverityNumber(): number {
|
||||
let selected = this.getDropdownValue(this.severityDropDown);
|
||||
let severityNumber: number = 0;
|
||||
if (selected) {
|
||||
let index = AlertDialog.AlertSeverities.indexOf(selected);
|
||||
if (index >= 0) {
|
||||
severityNumber = index + 1;
|
||||
}
|
||||
}
|
||||
return severityNumber;
|
||||
}
|
||||
|
||||
protected updateModel() {
|
||||
this.model.name = this.nameTextBox.value;
|
||||
this.model.isEnabled = this.enabledCheckBox.checked;
|
||||
|
||||
this.model.alertType = this.getDropdownValue(this.typeDropDown);
|
||||
let databaseName = this.getDropdownValue(this.databaseDropDown);
|
||||
this.model.databaseName = (databaseName !== AlertDialog.AllDatabases) ? databaseName : undefined;
|
||||
|
||||
if (this.severityRadioButton.checked) {
|
||||
this.model.severity = this.getSeverityNumber();
|
||||
this.model.messageId = 0;
|
||||
} else {
|
||||
this.model.severity = 0;
|
||||
this.model.messageId = +this.errorNumberTextBox.value;
|
||||
}
|
||||
|
||||
if (this.raiseAlertMessageCheckBox.checked) {
|
||||
this.model.eventDescriptionKeyword = this.raiseAlertMessageTextBox.value;
|
||||
} else {
|
||||
this.model.eventDescriptionKeyword = '';
|
||||
}
|
||||
let minutes = this.delayMinutesTextBox.value ? +this.delayMinutesTextBox.value : 0;
|
||||
let seconds = this.delaySecondsTextBox.value ? +this.delaySecondsTextBox : 0;
|
||||
this.model.delayBetweenResponses = minutes + seconds;
|
||||
|
||||
}
|
||||
}
|
||||
466
extensions/agent/src/dialogs/jobDialog.ts
Normal file
466
extensions/agent/src/dialogs/jobDialog.ts
Normal file
@@ -0,0 +1,466 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import { JobData } from '../data/jobData';
|
||||
import { JobStepDialog } from './jobStepDialog';
|
||||
import { PickScheduleDialog } from './pickScheduleDialog';
|
||||
import { AlertDialog } from './alertDialog';
|
||||
import { AgentDialog } from './agentDialog';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class JobDialog extends AgentDialog<JobData> {
|
||||
|
||||
// TODO: localize
|
||||
// Top level
|
||||
private static readonly CreateDialogTitle: string = localize('jobDialog.newJob', 'New Job');
|
||||
private static readonly EditDialogTitle: string = localize('jobDialog.editJob', 'Edit Job');
|
||||
private readonly GeneralTabText: string = localize('jobDialog.general', 'General');
|
||||
private readonly StepsTabText: string = localize('jobDialog.steps', 'Steps');
|
||||
private readonly SchedulesTabText: string = localize('jobDialog.schedules', 'Schedules');
|
||||
private readonly AlertsTabText: string = localize('jobDialog.alerts', 'Alerts');
|
||||
private readonly NotificationsTabText: string = localize('jobDialog.notifications', 'Notifications');
|
||||
private readonly BlankJobNameErrorText: string = localize('jobDialog.blankJobNameError', 'The name of the job cannot be blank.');
|
||||
|
||||
// General tab strings
|
||||
private readonly NameTextBoxLabel: string = localize('jobDialog.name', 'Name');
|
||||
private readonly OwnerTextBoxLabel: string = localize('jobDialog.owner', 'Owner');
|
||||
private readonly CategoryDropdownLabel: string = localize('jobDialog.category', 'Category');
|
||||
private readonly DescriptionTextBoxLabel: string = localize('jobDialog.description', 'Description');
|
||||
private readonly EnabledCheckboxLabel: string = localize('jobDialog.enabled', 'Enabled');
|
||||
|
||||
// Steps tab strings
|
||||
private readonly JobStepsTopLabelString: string = localize('jobDialog.jobStepList', 'Job step list');
|
||||
private readonly StepsTable_StepColumnString: string = localize('jobDialog.step', 'Step');
|
||||
private readonly StepsTable_NameColumnString: string = localize('jobDialog.name', 'Name');
|
||||
private readonly StepsTable_TypeColumnString: string = localize('jobDialog.type', 'Type');
|
||||
private readonly StepsTable_SuccessColumnString: string = localize('jobDialog.onSuccess', 'On Success');
|
||||
private readonly StepsTable_FailureColumnString: string = localize('jobDialog.onFailure', 'On Failure');
|
||||
private readonly NewStepButtonString: string = localize('jobDialog.new', 'New...');
|
||||
private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit');
|
||||
private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete');
|
||||
private readonly MoveStepUpButtonString: string = localize('jobDialog.moveUp', 'Move Step Up');
|
||||
private readonly MoveStepDownButtonString: string = localize('jobDialog.moveDown', 'Move Step Up');
|
||||
|
||||
// Notifications tab strings
|
||||
private readonly NotificationsTabTopLabelString: string = localize('jobDialog.notificationsTabTop', 'Actions to perform when the job completes');
|
||||
private readonly EmailCheckBoxString: string = localize('jobDialog.email', 'Email');
|
||||
private readonly PagerCheckBoxString: string = localize('jobDialog.page', 'Page');
|
||||
private readonly EventLogCheckBoxString: string = localize('jobDialog.eventLogCheckBoxLabel', 'Write to the Windows Application event log');
|
||||
private readonly DeleteJobCheckBoxString: string = localize('jobDialog.deleteJobLabel', 'Automatically delete job');
|
||||
|
||||
// Schedules tab strings
|
||||
private readonly SchedulesTopLabelString: string = localize('jobDialog.schedulesaLabel', 'Schedules list');
|
||||
private readonly PickScheduleButtonString: string = localize('jobDialog.pickSchedule', 'Pick Schedule');
|
||||
private readonly ScheduleNameLabelString: string = localize('jobDialog.scheduleNameLabel', 'Schedule Name');
|
||||
|
||||
// Alerts tab strings
|
||||
private readonly AlertsTopLabelString: string = localize('jobDialog.alertsList', 'Alerts list');
|
||||
private readonly NewAlertButtonString: string = localize('jobDialog.newAlert', 'New Alert');
|
||||
private readonly AlertNameLabelString: string = localize('jobDialog.alertNameLabel', 'Alert Name');
|
||||
|
||||
// UI Components
|
||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private stepsTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private alertsTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private schedulesTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private notificationsTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
|
||||
// General tab controls
|
||||
private nameTextBox: sqlops.InputBoxComponent;
|
||||
private ownerTextBox: sqlops.InputBoxComponent;
|
||||
private categoryDropdown: sqlops.DropDownComponent;
|
||||
private descriptionTextBox: sqlops.InputBoxComponent;
|
||||
private enabledCheckBox: sqlops.CheckBoxComponent;
|
||||
|
||||
// Steps tab controls
|
||||
private stepsTable: sqlops.TableComponent;
|
||||
private newStepButton: sqlops.ButtonComponent;
|
||||
private moveStepUpButton: sqlops.ButtonComponent;
|
||||
private moveStepDownButton: sqlops.ButtonComponent;
|
||||
private editStepButton: sqlops.ButtonComponent;
|
||||
private deleteStepButton: sqlops.ButtonComponent;
|
||||
|
||||
// Notifications tab controls
|
||||
private notificationsTabTopLabel: sqlops.TextComponent;
|
||||
private emailCheckBox: sqlops.CheckBoxComponent;
|
||||
private emailOperatorDropdown: sqlops.DropDownComponent;
|
||||
private emailConditionDropdown: sqlops.DropDownComponent;
|
||||
private pagerCheckBox: sqlops.CheckBoxComponent;
|
||||
private pagerOperatorDropdown: sqlops.DropDownComponent;
|
||||
private pagerConditionDropdown: sqlops.DropDownComponent;
|
||||
private eventLogCheckBox: sqlops.CheckBoxComponent;
|
||||
private eventLogConditionDropdown: sqlops.DropDownComponent;
|
||||
private deleteJobCheckBox: sqlops.CheckBoxComponent;
|
||||
private deleteJobConditionDropdown: sqlops.DropDownComponent;
|
||||
|
||||
// Schedule tab controls
|
||||
private schedulesTable: sqlops.TableComponent;
|
||||
private pickScheduleButton: sqlops.ButtonComponent;
|
||||
|
||||
// Alert tab controls
|
||||
private alertsTable: sqlops.TableComponent;
|
||||
private newAlertButton: sqlops.ButtonComponent;
|
||||
|
||||
constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) {
|
||||
super(
|
||||
ownerUri,
|
||||
new JobData(ownerUri, jobInfo),
|
||||
jobInfo ? JobDialog.EditDialogTitle : JobDialog.CreateDialogTitle);
|
||||
}
|
||||
|
||||
protected async initializeDialog() {
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(this.GeneralTabText);
|
||||
this.stepsTab = sqlops.window.modelviewdialog.createTab(this.StepsTabText);
|
||||
this.alertsTab = sqlops.window.modelviewdialog.createTab(this.AlertsTabText);
|
||||
this.schedulesTab = sqlops.window.modelviewdialog.createTab(this.SchedulesTabText);
|
||||
this.notificationsTab = sqlops.window.modelviewdialog.createTab(this.NotificationsTabText);
|
||||
this.initializeGeneralTab();
|
||||
this.initializeStepsTab();
|
||||
this.initializeAlertsTab();
|
||||
this.initializeSchedulesTab();
|
||||
this.initializeNotificationsTab();
|
||||
this.dialog.content = [this.generalTab, this.stepsTab, this.schedulesTab, this.alertsTab, this.notificationsTab];
|
||||
|
||||
this.dialog.registerCloseValidator(() => {
|
||||
this.updateModel();
|
||||
let validationResult = this.model.validate();
|
||||
if (!validationResult.valid) {
|
||||
// TODO: Show Error Messages
|
||||
console.error(validationResult.errorMessages.join(','));
|
||||
}
|
||||
|
||||
return validationResult.valid;
|
||||
});
|
||||
}
|
||||
|
||||
private initializeGeneralTab() {
|
||||
this.generalTab.registerContent(async view => {
|
||||
this.nameTextBox = view.modelBuilder.inputBox().component();
|
||||
this.nameTextBox.required = true;
|
||||
this.nameTextBox.onTextChanged(() => {
|
||||
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
|
||||
this.dialog.message = null;
|
||||
}
|
||||
});
|
||||
this.ownerTextBox = view.modelBuilder.inputBox().component();
|
||||
this.categoryDropdown = view.modelBuilder.dropDown().component();
|
||||
this.descriptionTextBox = view.modelBuilder.inputBox().withProperties({
|
||||
multiline: true,
|
||||
height: 200
|
||||
}).component();
|
||||
this.enabledCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: this.EnabledCheckboxLabel
|
||||
}).component();
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.nameTextBox,
|
||||
title: this.NameTextBoxLabel
|
||||
}, {
|
||||
component: this.ownerTextBox,
|
||||
title: this.OwnerTextBoxLabel
|
||||
}, {
|
||||
component: this.categoryDropdown,
|
||||
title: this.CategoryDropdownLabel
|
||||
}, {
|
||||
component: this.descriptionTextBox,
|
||||
title: this.DescriptionTextBoxLabel
|
||||
}, {
|
||||
component: this.enabledCheckBox,
|
||||
title: ''
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
this.nameTextBox.value = this.model.name;
|
||||
this.ownerTextBox.value = this.model.defaultOwner;
|
||||
this.categoryDropdown.values = this.model.jobCategories;
|
||||
|
||||
let idx: number = undefined;
|
||||
if (this.model.category && this.model.category !== '') {
|
||||
idx = this.model.jobCategories.indexOf(this.model.category);
|
||||
}
|
||||
this.categoryDropdown.value = this.model.jobCategories[idx > 0 ? idx : 0];
|
||||
|
||||
this.enabledCheckBox.checked = this.model.enabled;
|
||||
this.descriptionTextBox.value = this.model.description;
|
||||
});
|
||||
}
|
||||
|
||||
private initializeStepsTab() {
|
||||
this.stepsTab.registerContent(async view => {
|
||||
this.stepsTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
this.StepsTable_StepColumnString,
|
||||
this.StepsTable_NameColumnString,
|
||||
this.StepsTable_TypeColumnString,
|
||||
this.StepsTable_SuccessColumnString,
|
||||
this.StepsTable_FailureColumnString
|
||||
],
|
||||
data: [],
|
||||
height: 430
|
||||
}).component();
|
||||
|
||||
this.moveStepUpButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.MoveStepUpButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.moveStepDownButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.MoveStepDownButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.moveStepUpButton.enabled = false;
|
||||
this.moveStepDownButton.enabled = false;
|
||||
|
||||
this.newStepButton = view.modelBuilder.button().withProperties({
|
||||
label: this.NewStepButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.newStepButton.onDidClick((e)=>{
|
||||
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
|
||||
let stepDialog = new JobStepDialog(this.model.ownerUri, this.nameTextBox.value, '' , 1, this.model);
|
||||
stepDialog.openNewStepDialog();
|
||||
} else {
|
||||
this.dialog.message = { text: this.BlankJobNameErrorText };
|
||||
}
|
||||
});
|
||||
|
||||
this.editStepButton = view.modelBuilder.button().withProperties({
|
||||
label: this.EditStepButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.deleteStepButton = view.modelBuilder.button().withProperties({
|
||||
label: this.DeleteStepButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.stepsTable,
|
||||
title: this.JobStepsTopLabelString,
|
||||
actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton]
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
}
|
||||
|
||||
private initializeAlertsTab() {
|
||||
this.alertsTab.registerContent(async view => {
|
||||
this.alertsTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
this.AlertNameLabelString
|
||||
],
|
||||
data: [],
|
||||
height: 430,
|
||||
width: 400
|
||||
}).component();
|
||||
|
||||
this.newAlertButton = view.modelBuilder.button().withProperties({
|
||||
label: this.NewAlertButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.newAlertButton.onDidClick((e)=>{
|
||||
let alertDialog = new AlertDialog(this.model.ownerUri, null, []);
|
||||
alertDialog.onSuccess((dialogModel) => {
|
||||
});
|
||||
alertDialog.openDialog();
|
||||
});
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.alertsTable,
|
||||
title: this.AlertsTopLabelString,
|
||||
actions: [this.newAlertButton]
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
}
|
||||
|
||||
private initializeSchedulesTab() {
|
||||
this.schedulesTab.registerContent(async view => {
|
||||
this.schedulesTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
this.ScheduleNameLabelString
|
||||
],
|
||||
data: [],
|
||||
height: 430,
|
||||
width: 420
|
||||
}).component();
|
||||
|
||||
this.pickScheduleButton = view.modelBuilder.button().withProperties({
|
||||
label: this.PickScheduleButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.pickScheduleButton.onDidClick((e)=>{
|
||||
let pickScheduleDialog = new PickScheduleDialog(this.model.ownerUri);
|
||||
pickScheduleDialog.onSuccess((dialogModel) => {
|
||||
let selectedSchedule = dialogModel.selectedSchedule;
|
||||
if (selectedSchedule) {
|
||||
this.model.addJobSchedule(selectedSchedule);
|
||||
this.populateScheduleTable();
|
||||
}
|
||||
});
|
||||
pickScheduleDialog.showDialog();
|
||||
});
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.schedulesTable,
|
||||
title: this.SchedulesTopLabelString,
|
||||
actions: [this.pickScheduleButton]
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
this.populateScheduleTable();
|
||||
});
|
||||
}
|
||||
|
||||
private populateScheduleTable() {
|
||||
if (this.model.jobSchedules) {
|
||||
let data: any[][] = [];
|
||||
for (let i = 0; i < this.model.jobSchedules.length; ++i) {
|
||||
let schedule = this.model.jobSchedules[i];
|
||||
data[i] = [ schedule.name ];
|
||||
}
|
||||
this.schedulesTable.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
private initializeNotificationsTab() {
|
||||
this.notificationsTab.registerContent(async view => {
|
||||
|
||||
this.notificationsTabTopLabel = view.modelBuilder.text().withProperties({ value: this.NotificationsTabTopLabelString }).component();
|
||||
this.emailCheckBox = view.modelBuilder.checkBox().withProperties({
|
||||
label: this.EmailCheckBoxString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.pagerCheckBox = view.modelBuilder.checkBox().withProperties({
|
||||
label: this.PagerCheckBoxString,
|
||||
width: 80
|
||||
}).component();
|
||||
this.eventLogCheckBox = view.modelBuilder.checkBox().withProperties({
|
||||
label: this.EventLogCheckBoxString,
|
||||
width: 250
|
||||
}).component();
|
||||
this.deleteJobCheckBox = view.modelBuilder.checkBox().withProperties({
|
||||
label: this.DeleteJobCheckBoxString,
|
||||
width: 250
|
||||
}).component();
|
||||
|
||||
this.emailCheckBox.onChanged(() => {
|
||||
this.emailConditionDropdown.enabled = this.emailCheckBox.checked;
|
||||
this.emailOperatorDropdown.enabled = this.emailCheckBox.checked;
|
||||
});
|
||||
|
||||
this.pagerCheckBox.onChanged(() => {
|
||||
this.pagerConditionDropdown.enabled = this.pagerCheckBox.checked;
|
||||
this.pagerOperatorDropdown.enabled = this.pagerCheckBox.checked;
|
||||
});
|
||||
this.eventLogCheckBox.onChanged(() => {
|
||||
this.eventLogConditionDropdown.enabled = this.eventLogCheckBox.checked;
|
||||
});
|
||||
|
||||
this.deleteJobCheckBox.onChanged(() => {
|
||||
this.deleteJobConditionDropdown.enabled = this.deleteJobCheckBox.checked;
|
||||
});
|
||||
|
||||
this.emailOperatorDropdown = view.modelBuilder.dropDown().withProperties({ width: 150 }).component();
|
||||
this.pagerOperatorDropdown = view.modelBuilder.dropDown().withProperties({ width: 150 }).component();
|
||||
this.emailConditionDropdown = view.modelBuilder.dropDown().withProperties({ width: 150 }).component();
|
||||
this.pagerConditionDropdown = view.modelBuilder.dropDown().withProperties({ width: 150 }).component();
|
||||
this.eventLogConditionDropdown = view.modelBuilder.dropDown().withProperties({ width: 150 }).component();
|
||||
this.deleteJobConditionDropdown = view.modelBuilder.dropDown().withProperties({ width: 150 }).component();
|
||||
|
||||
let emailContainer = this.createRowContainer(view).withItems([this.emailCheckBox, this.emailOperatorDropdown, this.emailConditionDropdown]).component();
|
||||
|
||||
let pagerContainer = this.createRowContainer(view).withItems([this.pagerCheckBox, this.pagerOperatorDropdown, this.pagerConditionDropdown]).component();
|
||||
|
||||
let eventLogContainer = this.createRowContainer(view).withItems([this.eventLogCheckBox, this.eventLogConditionDropdown]).component();
|
||||
|
||||
let deleteJobContainer = this.createRowContainer(view).withItems([this.deleteJobCheckBox, this.deleteJobConditionDropdown]).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer().withFormItems([
|
||||
{
|
||||
components:
|
||||
[{
|
||||
component: emailContainer,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: pagerContainer,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: eventLogContainer,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: deleteJobContainer,
|
||||
title: ''
|
||||
}], title: this.NotificationsTabTopLabelString}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
this.emailConditionDropdown.values = this.model.JobCompletionActionConditions;
|
||||
this.pagerConditionDropdown.values = this.model.JobCompletionActionConditions;
|
||||
this.eventLogConditionDropdown.values = this.model.JobCompletionActionConditions;
|
||||
this.deleteJobConditionDropdown.values = this.model.JobCompletionActionConditions;
|
||||
this.setConditionDropdownSelectedValue(this.emailConditionDropdown, this.model.emailLevel);
|
||||
this.setConditionDropdownSelectedValue(this.pagerConditionDropdown, this.model.pageLevel);
|
||||
this.setConditionDropdownSelectedValue(this.eventLogConditionDropdown, this.model.eventLogLevel);
|
||||
this.setConditionDropdownSelectedValue(this.deleteJobConditionDropdown, this.model.deleteLevel);
|
||||
this.emailOperatorDropdown.values = this.model.operators;
|
||||
this.pagerOperatorDropdown.values = this.model.operators;
|
||||
this.emailCheckBox.checked = false;
|
||||
this.pagerCheckBox.checked = false;
|
||||
this.eventLogCheckBox.checked = false;
|
||||
this.deleteJobCheckBox.checked = false;
|
||||
this.emailOperatorDropdown.enabled = false;
|
||||
this.pagerOperatorDropdown.enabled = false;
|
||||
this.emailConditionDropdown.enabled = false;
|
||||
this.pagerConditionDropdown.enabled = false;
|
||||
this.eventLogConditionDropdown.enabled = false;
|
||||
this.deleteJobConditionDropdown.enabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
private createRowContainer(view: sqlops.ModelView): sqlops.FlexBuilder {
|
||||
return view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'row',
|
||||
alignItems: 'left',
|
||||
justifyContent: 'space-between'
|
||||
});
|
||||
}
|
||||
|
||||
protected updateModel() {
|
||||
this.model.name = this.nameTextBox.value;
|
||||
this.model.owner = this.ownerTextBox.value;
|
||||
this.model.enabled = this.enabledCheckBox.checked;
|
||||
this.model.description = this.descriptionTextBox.value;
|
||||
this.model.category = this.getDropdownValue(this.categoryDropdown);
|
||||
this.model.emailLevel = this.getActualConditionValue(this.emailCheckBox, this.emailConditionDropdown);
|
||||
this.model.operatorToEmail = this.getDropdownValue(this.emailOperatorDropdown);
|
||||
this.model.operatorToPage = this.getDropdownValue(this.pagerOperatorDropdown);
|
||||
this.model.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown);
|
||||
this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown);
|
||||
this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown);
|
||||
}
|
||||
}
|
||||
510
extensions/agent/src/dialogs/jobStepDialog.ts
Normal file
510
extensions/agent/src/dialogs/jobStepDialog.ts
Normal file
@@ -0,0 +1,510 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { JobStepData } from '../data/jobStepData';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { JobData } from '../data/jobData';
|
||||
const path = require('path');
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class JobStepDialog {
|
||||
|
||||
// TODO: localize
|
||||
// Top level
|
||||
//
|
||||
private readonly DialogTitle: string = localize('jobStepDialog.newJobStep', 'New Job Step');
|
||||
private readonly FileBrowserDialogTitle: string = localize('jobStepDialog.fileBrowserTitle', 'Locate Database Files - ');
|
||||
private readonly OkButtonText: string = localize('jobStepDialog.ok', 'OK');
|
||||
private readonly CancelButtonText: string = localize('jobStepDialog.cancel', 'Cancel');
|
||||
private readonly GeneralTabText: string = localize('jobStepDialog.general', 'General');
|
||||
private readonly AdvancedTabText: string = localize('jobStepDialog.advanced', 'Advanced');
|
||||
private readonly OpenCommandText: string = localize('jobStepDialog.open', 'Open...');
|
||||
private readonly ParseCommandText: string = localize('jobStepDialog.parse','Parse');
|
||||
private readonly NextButtonText: string = localize('jobStepDialog.next', 'Next');
|
||||
private readonly PreviousButtonText: string = localize('jobStepDialog.previous','Previous');
|
||||
private readonly SuccessfulParseText: string = localize('jobStepDialog.successParse', 'The command was successfully parsed.');
|
||||
private readonly FailureParseText: string = localize('jobStepDialog.failParse', 'The command failed.');
|
||||
private readonly BlankStepNameErrorText: string = localize('jobStepDialog.blankStepName', 'The step name cannot be left blank');
|
||||
|
||||
// General Control Titles
|
||||
private readonly StepNameLabelString: string = localize('jobStepDialog.stepNameLabel', 'Step Name');
|
||||
private readonly TypeLabelString: string = localize('jobStepDialog.typeLabel', 'Type');
|
||||
private readonly RunAsLabelString: string = localize('jobStepDialog.runAsLabel', 'Run as');
|
||||
private readonly DatabaseLabelString: string = localize('jobStepDialog.databaseLabel', 'Database');
|
||||
private readonly CommandLabelString: string = localize('jobStepDialog.commandLabel', 'Command');
|
||||
|
||||
// Advanced Control Titles
|
||||
private readonly SuccessActionLabel: string = localize('jobStepDialog.successAction', 'On success action');
|
||||
private readonly FailureActionLabel: string = localize('jobStepDialog.failureAction', 'On failure action');
|
||||
private readonly RunAsUserLabel: string = localize('jobStepDialog.runAsUser', 'Run as user');
|
||||
private readonly RetryAttemptsLabel: string = localize('jobStepDialog.retryAttempts', 'Retry Attempts');
|
||||
private readonly RetryIntervalLabel: string = localize('jobStepDialog.retryInterval', 'Retry Interval (minutes)');
|
||||
private readonly LogToTableLabel: string = localize('jobStepDialog.logToTable', 'Log to table');
|
||||
private readonly AppendExistingTableEntryLabel: string = localize('jobStepDialog.appendExistingTableEntry', 'Append output to exisiting entry in table');
|
||||
private readonly IncludeStepOutputHistoryLabel: string = localize('jobStepDialog.includeStepOutputHistory', 'Include step output in history');
|
||||
private readonly OutputFileNameLabel: string = localize('jobStepDialog.outputFile', 'Output File');
|
||||
private readonly AppendOutputToFileLabel: string = localize('jobStepDialog.appendOutputToFile', 'Append output to existing file');
|
||||
|
||||
// File Browser Control Titles
|
||||
private readonly SelectedPathLabelString: string = localize('jobStepDialog.selectedPath', 'Selected path');
|
||||
private readonly FilesOfTypeLabelString: string = localize('jobStepDialog.filesOfType', 'Files of type');
|
||||
private readonly FileNameLabelString: string = localize('jobStepDialog.fileName', 'File name');
|
||||
private readonly AllFilesLabelString: string = localize('jobStepDialog.allFiles', 'All Files (*)');
|
||||
|
||||
// Dropdown options
|
||||
private readonly TSQLScript: string = localize('jobStepDialog.TSQL', 'Transact-SQL script (T-SQL)');
|
||||
private readonly AgentServiceAccount: string = localize('jobStepDialog.agentServiceAccount', 'SQL Server Agent Service Account');
|
||||
private readonly NextStep: string = localize('jobStepDialog.nextStep', 'Go to the next step');
|
||||
private readonly QuitJobReportingSuccess: string = localize('jobStepDialog.quitJobSuccess', 'Quit the job reporting success');
|
||||
private readonly QuitJobReportingFailure: string = localize('jobStepDialog.quitJobFailure', 'Quit the job reporting failure');
|
||||
|
||||
// UI Components
|
||||
|
||||
// Dialogs
|
||||
private dialog: sqlops.window.modelviewdialog.Dialog;
|
||||
private fileBrowserDialog: sqlops.window.modelviewdialog.Dialog;
|
||||
|
||||
// Dialog tabs
|
||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private advancedTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
|
||||
//Input boxes
|
||||
private nameTextBox: sqlops.InputBoxComponent;
|
||||
private commandTextBox: sqlops.InputBoxComponent;
|
||||
private selectedPathTextBox: sqlops.InputBoxComponent;
|
||||
private retryAttemptsBox: sqlops.InputBoxComponent;
|
||||
private retryIntervalBox: sqlops.InputBoxComponent;
|
||||
private outputFileNameBox: sqlops.InputBoxComponent;
|
||||
private fileBrowserNameBox: sqlops.InputBoxComponent;
|
||||
private userInputBox: sqlops.InputBoxComponent;
|
||||
|
||||
// Dropdowns
|
||||
private typeDropdown: sqlops.DropDownComponent;
|
||||
private runAsDropdown: sqlops.DropDownComponent;
|
||||
private databaseDropdown: sqlops.DropDownComponent;
|
||||
private successActionDropdown: sqlops.DropDownComponent;
|
||||
private failureActionDropdown: sqlops.DropDownComponent;
|
||||
private fileTypeDropdown: sqlops.DropDownComponent;
|
||||
|
||||
// Buttons
|
||||
private openButton: sqlops.ButtonComponent;
|
||||
private parseButton: sqlops.ButtonComponent;
|
||||
private nextButton: sqlops.ButtonComponent;
|
||||
private previousButton: sqlops.ButtonComponent;
|
||||
private outputFileBrowserButton: sqlops.ButtonComponent;
|
||||
|
||||
// Checkbox
|
||||
private appendToExistingFileCheckbox: sqlops.CheckBoxComponent;
|
||||
private logToTableCheckbox: sqlops.CheckBoxComponent;
|
||||
|
||||
private fileBrowserTree: sqlops.FileBrowserTreeComponent;
|
||||
private jobModel: JobData;
|
||||
private model: JobStepData;
|
||||
private ownerUri: string;
|
||||
private jobName: string;
|
||||
private server: string;
|
||||
private stepId: number;
|
||||
|
||||
constructor(
|
||||
ownerUri: string,
|
||||
jobName: string,
|
||||
server: string,
|
||||
stepId: number,
|
||||
jobModel?: JobData
|
||||
) {
|
||||
this.model = new JobStepData(ownerUri);
|
||||
this.stepId = stepId;
|
||||
this.ownerUri = ownerUri;
|
||||
this.jobName = jobName;
|
||||
this.server = server;
|
||||
this.jobModel = jobModel;
|
||||
}
|
||||
|
||||
private initializeUIComponents() {
|
||||
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(this.GeneralTabText);
|
||||
this.advancedTab = sqlops.window.modelviewdialog.createTab(this.AdvancedTabText);
|
||||
this.dialog.content = [this.generalTab, this.advancedTab];
|
||||
this.dialog.okButton.onClick(async () => await this.execute());
|
||||
this.dialog.okButton.label = this.OkButtonText;
|
||||
this.dialog.cancelButton.label = this.CancelButtonText;
|
||||
}
|
||||
|
||||
private createCommands(view, queryProvider: sqlops.QueryProvider) {
|
||||
this.openButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.OpenCommandText,
|
||||
width: '80px',
|
||||
isFile: true
|
||||
}).component();
|
||||
this.parseButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.ParseCommandText,
|
||||
width: '80px',
|
||||
isFile: false
|
||||
}).component();
|
||||
this.openButton.onDidClick(e => {
|
||||
let queryContent = e;
|
||||
this.commandTextBox.value = queryContent;
|
||||
});
|
||||
this.parseButton.onDidClick(e => {
|
||||
if (this.commandTextBox.value) {
|
||||
queryProvider.parseSyntax(this.ownerUri, this.commandTextBox.value).then(result => {
|
||||
if (result && result.parseable) {
|
||||
this.dialog.message = { text: this.SuccessfulParseText, level: 2};
|
||||
} else if (result && !result.parseable) {
|
||||
this.dialog.message = { text: this.FailureParseText };
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
this.commandTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
height: 300,
|
||||
width: 400,
|
||||
multiline: true,
|
||||
inputType: 'text'
|
||||
})
|
||||
.component();
|
||||
this.nextButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.NextButtonText,
|
||||
enabled: false,
|
||||
width: '80px'
|
||||
}).component();
|
||||
this.previousButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.PreviousButtonText,
|
||||
enabled: false,
|
||||
width: '80px'
|
||||
}).component();
|
||||
}
|
||||
|
||||
private createGeneralTab(databases: string[], queryProvider: sqlops.QueryProvider) {
|
||||
this.generalTab.registerContent(async (view) => {
|
||||
this.nameTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
}).component();
|
||||
this.nameTextBox.required = true;
|
||||
this.nameTextBox.onTextChanged(() => {
|
||||
if (this.nameTextBox.value.length > 0) {
|
||||
this.dialog.message = null;
|
||||
}
|
||||
});
|
||||
|
||||
this.typeDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: this.TSQLScript,
|
||||
values: [this.TSQLScript]
|
||||
})
|
||||
.component();
|
||||
this.runAsDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: '',
|
||||
values: ['']
|
||||
})
|
||||
.component();
|
||||
this.runAsDropdown.enabled = false;
|
||||
this.typeDropdown.onValueChanged((type) => {
|
||||
if (type.selected !== this.TSQLScript) {
|
||||
this.runAsDropdown.value = this.AgentServiceAccount;
|
||||
this.runAsDropdown.values = [this.runAsDropdown.value];
|
||||
} else {
|
||||
this.runAsDropdown.value = '';
|
||||
this.runAsDropdown.values = [''];
|
||||
}
|
||||
});
|
||||
this.databaseDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: databases[0],
|
||||
values: databases
|
||||
}).component();
|
||||
|
||||
// create the commands section
|
||||
this.createCommands(view, queryProvider);
|
||||
|
||||
let buttonContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: 420
|
||||
}).withItems([this.openButton, this.parseButton, this.previousButton, this.nextButton], {
|
||||
flex: '1 1 50%'
|
||||
}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.nameTextBox,
|
||||
title: this.StepNameLabelString
|
||||
}, {
|
||||
component: this.typeDropdown,
|
||||
title: this.TypeLabelString
|
||||
}, {
|
||||
component: this.runAsDropdown,
|
||||
title: this.RunAsLabelString
|
||||
}, {
|
||||
component: this.databaseDropdown,
|
||||
title: this.DatabaseLabelString
|
||||
}, {
|
||||
component: this.commandTextBox,
|
||||
title: this.CommandLabelString,
|
||||
actions: [buttonContainer]
|
||||
}], {
|
||||
horizontal: false,
|
||||
componentWidth: 420
|
||||
}).component();
|
||||
let formWrapper = view.modelBuilder.loadingComponent().withItem(formModel).component();
|
||||
formWrapper.loading = false;
|
||||
await view.initializeModel(formWrapper);
|
||||
});
|
||||
}
|
||||
|
||||
private createAdvancedTab() {
|
||||
this.advancedTab.registerContent(async (view) => {
|
||||
this.successActionDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
width: '100%',
|
||||
value: this.NextStep,
|
||||
values: [this.NextStep, this.QuitJobReportingSuccess, this.QuitJobReportingFailure]
|
||||
})
|
||||
.component();
|
||||
let retryFlexContainer = this.createRetryCounters(view);
|
||||
|
||||
this.failureActionDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: this.QuitJobReportingFailure,
|
||||
values: [this.QuitJobReportingFailure, this.NextStep, this.QuitJobReportingSuccess]
|
||||
})
|
||||
.component();
|
||||
let optionsGroup = this.createTSQLOptions(view);
|
||||
this.logToTableCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: this.LogToTableLabel
|
||||
}).component();
|
||||
let appendToExistingEntryInTableCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({ label: this.AppendExistingTableEntryLabel }).component();
|
||||
appendToExistingEntryInTableCheckbox.enabled = false;
|
||||
this.logToTableCheckbox.onChanged(e => {
|
||||
appendToExistingEntryInTableCheckbox.enabled = e;
|
||||
});
|
||||
let appendCheckboxContainer = view.modelBuilder.groupContainer()
|
||||
.withItems([appendToExistingEntryInTableCheckbox]).component();
|
||||
let logToTableContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'row', justifyContent: 'space-between', width: 300 })
|
||||
.withItems([this.logToTableCheckbox]).component();
|
||||
let logStepOutputHistoryCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({ label: this.IncludeStepOutputHistoryLabel }).component();
|
||||
this.userInputBox = view.modelBuilder.inputBox()
|
||||
.withProperties({ inputType: 'text', width: '100%' }).component();
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[{
|
||||
component: this.successActionDropdown,
|
||||
title: this.SuccessActionLabel
|
||||
}, {
|
||||
component: retryFlexContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.failureActionDropdown,
|
||||
title: this.FailureActionLabel
|
||||
}, {
|
||||
component: optionsGroup,
|
||||
title: this.TSQLScript
|
||||
}, {
|
||||
component: logToTableContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: appendCheckboxContainer,
|
||||
title: ' '
|
||||
}, {
|
||||
component: logStepOutputHistoryCheckbox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.userInputBox,
|
||||
title: this.RunAsUserLabel
|
||||
}], {
|
||||
componentWidth: 400
|
||||
}).component();
|
||||
|
||||
let formWrapper = view.modelBuilder.loadingComponent().withItem(formModel).component();
|
||||
formWrapper.loading = false;
|
||||
view.initializeModel(formWrapper);
|
||||
});
|
||||
}
|
||||
|
||||
private createRetryCounters(view) {
|
||||
this.retryAttemptsBox = view.modelBuilder.inputBox()
|
||||
.withValidation(component => component.value >= 0)
|
||||
.withProperties({
|
||||
inputType: 'number',
|
||||
width: '100%',
|
||||
placeHolder: '0'
|
||||
})
|
||||
.component();
|
||||
this.retryIntervalBox = view.modelBuilder.inputBox()
|
||||
.withValidation(component => component.value >= 0)
|
||||
.withProperties({
|
||||
inputType: 'number',
|
||||
width: '100%',
|
||||
placeHolder: '0'
|
||||
}).component();
|
||||
|
||||
let retryAttemptsContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[{
|
||||
component: this.retryAttemptsBox,
|
||||
title: this.RetryAttemptsLabel
|
||||
}], {
|
||||
horizontal: false,
|
||||
componentWidth: '100%'
|
||||
})
|
||||
.component();
|
||||
|
||||
let retryIntervalContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[{
|
||||
component: this.retryIntervalBox,
|
||||
title: this.RetryIntervalLabel
|
||||
}], {
|
||||
horizontal: false
|
||||
})
|
||||
.component();
|
||||
|
||||
let retryFlexContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
}).withItems([retryAttemptsContainer, retryIntervalContainer]).component();
|
||||
return retryFlexContainer;
|
||||
}
|
||||
|
||||
private openFileBrowserDialog() {
|
||||
let fileBrowserTitle = this.FileBrowserDialogTitle + `${this.server}`;
|
||||
this.fileBrowserDialog = sqlops.window.modelviewdialog.createDialog(fileBrowserTitle);
|
||||
let fileBrowserTab = sqlops.window.modelviewdialog.createTab('File Browser');
|
||||
this.fileBrowserDialog.content = [fileBrowserTab];
|
||||
fileBrowserTab.registerContent(async (view) => {
|
||||
this.fileBrowserTree = view.modelBuilder.fileBrowserTree()
|
||||
.withProperties({ ownerUri: this.ownerUri, width: 420, height: 700 })
|
||||
.component();
|
||||
this.selectedPathTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({ inputType: 'text'})
|
||||
.component();
|
||||
this.fileBrowserTree.onDidChange((args) => {
|
||||
this.selectedPathTextBox.value = args.fullPath;
|
||||
this.fileBrowserNameBox.value = args.isFile ? path.win32.basename(args.fullPath) : '';
|
||||
});
|
||||
this.fileTypeDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: this.AllFilesLabelString,
|
||||
values: [this.AllFilesLabelString]
|
||||
})
|
||||
.component();
|
||||
this.fileBrowserNameBox = view.modelBuilder.inputBox()
|
||||
.withProperties({})
|
||||
.component();
|
||||
let fileBrowserContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.fileBrowserTree,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.selectedPathTextBox,
|
||||
title: this.SelectedPathLabelString
|
||||
}, {
|
||||
component: this.fileTypeDropdown,
|
||||
title: this.FilesOfTypeLabelString
|
||||
}, {
|
||||
component: this.fileBrowserNameBox,
|
||||
title: this.FileNameLabelString
|
||||
}
|
||||
]).component();
|
||||
view.initializeModel(fileBrowserContainer);
|
||||
});
|
||||
this.fileBrowserDialog.okButton.onClick(() => {
|
||||
this.outputFileNameBox.value = path.join(path.dirname(this.selectedPathTextBox.value), this.fileBrowserNameBox.value);
|
||||
});
|
||||
this.fileBrowserDialog.okButton.label = this.OkButtonText;
|
||||
this.fileBrowserDialog.cancelButton.label = this.CancelButtonText;
|
||||
sqlops.window.modelviewdialog.openDialog(this.fileBrowserDialog);
|
||||
}
|
||||
|
||||
private createTSQLOptions(view) {
|
||||
this.outputFileBrowserButton = view.modelBuilder.button()
|
||||
.withProperties({ width: '20px', label: '...' }).component();
|
||||
this.outputFileBrowserButton.onDidClick(() => this.openFileBrowserDialog());
|
||||
this.outputFileNameBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
width: 250,
|
||||
inputType: 'text'
|
||||
}).component();
|
||||
let outputButtonContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
textAlign: 'right',
|
||||
width: '100%'
|
||||
}).withItems([this.outputFileBrowserButton], { flex: '1 1 50%' }).component();
|
||||
let outputFlexBox = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
width: 350
|
||||
}).withItems([this.outputFileNameBox, outputButtonContainer], {
|
||||
flex: '1 1 50%'
|
||||
}).component();
|
||||
this.appendToExistingFileCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: this.AppendOutputToFileLabel
|
||||
}).component();
|
||||
this.appendToExistingFileCheckbox.enabled = false;
|
||||
this.outputFileNameBox.onTextChanged((input) => {
|
||||
if (input !== '') {
|
||||
this.appendToExistingFileCheckbox.enabled = true;
|
||||
} else {
|
||||
this.appendToExistingFileCheckbox.enabled = false;
|
||||
}
|
||||
});
|
||||
let outputFileForm = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: outputFlexBox,
|
||||
title: this.OutputFileNameLabel
|
||||
}, {
|
||||
component: this.appendToExistingFileCheckbox,
|
||||
title: ''
|
||||
}], { horizontal: false, componentWidth: 200 }).component();
|
||||
return outputFileForm;
|
||||
}
|
||||
|
||||
protected execute() {
|
||||
this.model.stepName = this.nameTextBox.value;
|
||||
if (!this.model.stepName || this.model.stepName.length === 0) {
|
||||
this.dialog.message = this.dialog.message = { text: this.BlankStepNameErrorText };
|
||||
return;
|
||||
}
|
||||
this.model.jobName = this.jobName;
|
||||
this.model.id = this.stepId;
|
||||
this.model.server = this.server;
|
||||
this.model.stepName = this.nameTextBox.value;
|
||||
this.model.subSystem = this.typeDropdown.value as string;
|
||||
this.model.databaseName = this.databaseDropdown.value as string;
|
||||
this.model.script = this.commandTextBox.value;
|
||||
this.model.successAction = this.successActionDropdown.value as string;
|
||||
this.model.retryAttempts = this.retryAttemptsBox.value ? +this.retryAttemptsBox.value : 0;
|
||||
this.model.retryInterval = +this.retryIntervalBox.value ? +this.retryIntervalBox.value : 0;
|
||||
this.model.failureAction = this.failureActionDropdown.value as string;
|
||||
this.model.outputFileName = this.outputFileNameBox.value;
|
||||
this.model.appendToLogFile = this.appendToExistingFileCheckbox.checked;
|
||||
}
|
||||
|
||||
public async openNewStepDialog() {
|
||||
let databases = await AgentUtils.getDatabases(this.ownerUri);
|
||||
let queryProvider = await AgentUtils.getQueryProvider();
|
||||
this.initializeUIComponents();
|
||||
this.createGeneralTab(databases, queryProvider);
|
||||
this.createAdvancedTab();
|
||||
sqlops.window.modelviewdialog.openDialog(this.dialog);
|
||||
}
|
||||
}
|
||||
404
extensions/agent/src/dialogs/operatorDialog.ts
Normal file
404
extensions/agent/src/dialogs/operatorDialog.ts
Normal file
@@ -0,0 +1,404 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { OperatorData } from '../data/operatorData';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { AgentDialog } from './agentDialog';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
|
||||
// Top level
|
||||
private static readonly CreateDialogTitle: string = localize('createOperator.createOperator', 'Create Operator');
|
||||
private static readonly EditDialogTitle: string = localize('createOperator.editOperator', 'Edit Operator');
|
||||
private static readonly GeneralTabText: string = localize('createOperator.General', 'General');
|
||||
private static readonly NotificationsTabText: string = localize('createOperator.Notifications', 'Notifications');
|
||||
|
||||
// General tab strings
|
||||
private static readonly NameLabel: string = localize('createOperator.Name', 'Name');
|
||||
private static readonly EnabledCheckboxLabel: string = localize('createOperator.Enabled', 'Enabled');
|
||||
private static readonly EmailNameTextLabel: string = localize('createOperator.EmailName', 'E-mail Name');
|
||||
private static readonly PagerEmailNameTextLabel: string = localize('createOperator.PagerEmailName', 'Pager E-mail Name');
|
||||
private static readonly PagerMondayCheckBoxLabel: string = localize('createOperator.PagerMondayCheckBox', 'Monday');
|
||||
private static readonly PagerTuesdayCheckBoxLabel: string = localize('createOperator.PagerTuesdayCheckBox', 'Tuesday');
|
||||
private static readonly PagerWednesdayCheckBoxLabel: string = localize('createOperator.PagerWednesdayCheckBox', 'Wednesday');
|
||||
private static readonly PagerThursdayCheckBoxLabel: string = localize('createOperator.PagerThursdayCheckBox', 'Thursday');
|
||||
private static readonly PagerFridayCheckBoxLabel: string = localize('createOperator.PagerFridayCheckBox', 'Friday ');
|
||||
private static readonly PagerSaturdayCheckBoxLabel: string = localize('createOperator.PagerSaturdayCheckBox', 'Saturday');
|
||||
private static readonly PagerSundayCheckBoxLabel: string = localize('createOperator.PagerSundayCheckBox', 'Sunday');
|
||||
private static readonly WorkdayBeginLabel: string = localize('createOperator.workdayBegin', 'Workday begin');
|
||||
private static readonly WorkdayEndLabel: string = localize('createOperator.workdayEnd', 'Workday end');
|
||||
private static readonly PagerDutyScheduleLabel: string = localize('createOperator.PagerDutySchedule', 'Pager on duty schdule');
|
||||
|
||||
// Notifications tab strings
|
||||
private static readonly AlertsTableLabel: string = localize('createOperator.AlertListHeading', 'Alert list');
|
||||
private static readonly AlertNameColumnLabel: string = localize('createOperator.AlertNameColumnLabel', 'Alert name');
|
||||
private static readonly AlertEmailColumnLabel: string = localize('createOperator.AlertEmailColumnLabel', 'E-mail');
|
||||
private static readonly AlertPagerColumnLabel: string = localize('createOperator.AlertPagerColumnLabel', 'Pager');
|
||||
|
||||
// UI Components
|
||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
private notificationsTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
|
||||
// General tab controls
|
||||
private nameTextBox: sqlops.InputBoxComponent;
|
||||
private enabledCheckBox: sqlops.CheckBoxComponent;
|
||||
private emailNameTextBox: sqlops.InputBoxComponent;
|
||||
private pagerEmailNameTextBox: sqlops.InputBoxComponent;
|
||||
private pagerMondayCheckBox: sqlops.CheckBoxComponent;
|
||||
private pagerTuesdayCheckBox: sqlops.CheckBoxComponent;
|
||||
private pagerWednesdayCheckBox: sqlops.CheckBoxComponent;
|
||||
private pagerThursdayCheckBox: sqlops.CheckBoxComponent;
|
||||
private pagerFridayCheckBox: sqlops.CheckBoxComponent;
|
||||
private pagerSaturdayCheckBox: sqlops.CheckBoxComponent;
|
||||
private pagerSundayCheckBox: sqlops.CheckBoxComponent;
|
||||
private weekdayPagerStartTimeInput: sqlops.InputBoxComponent;
|
||||
private weekdayPagerEndTimeInput: sqlops.InputBoxComponent;
|
||||
private saturdayPagerStartTimeInput: sqlops.InputBoxComponent;
|
||||
private saturdayPagerEndTimeInput: sqlops.InputBoxComponent;
|
||||
private sundayPagerStartTimeInput: sqlops.InputBoxComponent;
|
||||
private sundayPagerEndTimeInput: sqlops.InputBoxComponent;
|
||||
|
||||
// Notification tab controls
|
||||
private alertsTable: sqlops.TableComponent;
|
||||
|
||||
constructor(ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo = undefined) {
|
||||
super(
|
||||
ownerUri,
|
||||
new OperatorData(ownerUri, operatorInfo),
|
||||
operatorInfo ? OperatorDialog.EditDialogTitle : OperatorDialog.CreateDialogTitle);
|
||||
}
|
||||
|
||||
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(OperatorDialog.GeneralTabText);
|
||||
this.notificationsTab = sqlops.window.modelviewdialog.createTab(OperatorDialog.NotificationsTabText);
|
||||
|
||||
this.initializeGeneralTab();
|
||||
this.initializeNotificationTab();
|
||||
|
||||
this.dialog.content = [this.generalTab, this.notificationsTab];
|
||||
}
|
||||
|
||||
private initializeGeneralTab() {
|
||||
this.generalTab.registerContent(async view => {
|
||||
|
||||
this.nameTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.enabledCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.EnabledCheckboxLabel
|
||||
}).component();
|
||||
this.enabledCheckBox.checked = true;
|
||||
this.emailNameTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.pagerEmailNameTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.enabledCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.EnabledCheckboxLabel
|
||||
}).component();
|
||||
|
||||
this.pagerMondayCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.PagerMondayCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
this.pagerMondayCheckBox.onChanged(() => {
|
||||
if (this.pagerMondayCheckBox.checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = true;
|
||||
this.weekdayPagerEndTimeInput.enabled = true;
|
||||
} else {
|
||||
if (!this.pagerTuesdayCheckBox.checked && !this.pagerWednesdayCheckBox.checked &&
|
||||
!this.pagerThursdayCheckBox.checked && !this.pagerFridayCheckBox.checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = false;
|
||||
this.weekdayPagerEndTimeInput.enabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.pagerTuesdayCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.PagerTuesdayCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
|
||||
this.pagerTuesdayCheckBox.onChanged(() => {
|
||||
if (this.pagerTuesdayCheckBox .checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = true;
|
||||
this.weekdayPagerEndTimeInput.enabled = true;
|
||||
} else {
|
||||
if (!this.pagerMondayCheckBox.checked && !this.pagerWednesdayCheckBox.checked &&
|
||||
!this.pagerThursdayCheckBox.checked && !this.pagerFridayCheckBox.checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = false;
|
||||
this.weekdayPagerEndTimeInput.enabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.pagerWednesdayCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.PagerWednesdayCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
this.pagerWednesdayCheckBox.onChanged(() => {
|
||||
if (this.pagerWednesdayCheckBox .checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = true;
|
||||
this.weekdayPagerEndTimeInput.enabled = true;
|
||||
} else {
|
||||
if (!this.pagerMondayCheckBox.checked && !this.pagerTuesdayCheckBox.checked &&
|
||||
!this.pagerThursdayCheckBox.checked && !this.pagerFridayCheckBox.checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = false;
|
||||
this.weekdayPagerEndTimeInput.enabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.pagerThursdayCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.PagerThursdayCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
this.pagerThursdayCheckBox.onChanged(() => {
|
||||
if (this.pagerThursdayCheckBox .checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = true;
|
||||
this.weekdayPagerEndTimeInput.enabled = true;
|
||||
} else {
|
||||
if (!this.pagerMondayCheckBox.checked && !this.pagerWednesdayCheckBox.checked &&
|
||||
!this.pagerTuesdayCheckBox.checked && !this.pagerFridayCheckBox.checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = false;
|
||||
this.weekdayPagerEndTimeInput.enabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.weekdayPagerStartTimeInput = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'time',
|
||||
placeHolder: '08:00:00',
|
||||
}).component();
|
||||
this.weekdayPagerStartTimeInput.enabled = false;
|
||||
let weekdayStartInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.weekdayPagerStartTimeInput,
|
||||
title: OperatorDialog.WorkdayBeginLabel
|
||||
}]).component();
|
||||
|
||||
this.weekdayPagerEndTimeInput = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'time',
|
||||
placeHolder: '06:00:00'
|
||||
}).component();
|
||||
this.weekdayPagerEndTimeInput.enabled = false;
|
||||
let weekdayEndInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.weekdayPagerEndTimeInput,
|
||||
title: OperatorDialog.WorkdayEndLabel
|
||||
}]).component();
|
||||
|
||||
this.pagerFridayCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.PagerFridayCheckBoxLabel,
|
||||
width: 80
|
||||
}).component();
|
||||
this.pagerFridayCheckBox.onChanged(() => {
|
||||
if (this.pagerFridayCheckBox.checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = true;
|
||||
this.weekdayPagerEndTimeInput.enabled = true;
|
||||
} else {
|
||||
if (!this.pagerMondayCheckBox.checked && !this.pagerWednesdayCheckBox.checked &&
|
||||
!this.pagerThursdayCheckBox.checked && !this.pagerTuesdayCheckBox.checked) {
|
||||
this.weekdayPagerStartTimeInput.enabled = false;
|
||||
this.weekdayPagerEndTimeInput.enabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let pagerFridayCheckboxContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
alignItems: 'baseline',
|
||||
width: '100%'
|
||||
}).withItems([this.pagerFridayCheckBox, weekdayStartInputContainer, weekdayEndInputContainer])
|
||||
.component();
|
||||
|
||||
this.pagerSaturdayCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.PagerSaturdayCheckBoxLabel,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.pagerSaturdayCheckBox.onChanged(() => {
|
||||
if (this.pagerSaturdayCheckBox.checked) {
|
||||
this.saturdayPagerStartTimeInput.enabled = true;
|
||||
this.saturdayPagerEndTimeInput.enabled = true;
|
||||
} else {
|
||||
this.saturdayPagerStartTimeInput.enabled = false;
|
||||
this.saturdayPagerEndTimeInput.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.saturdayPagerStartTimeInput = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'time',
|
||||
placeHolder: '08:00:00'
|
||||
}).component();
|
||||
this.saturdayPagerStartTimeInput.enabled = false;
|
||||
let saturdayStartInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.saturdayPagerStartTimeInput,
|
||||
title: OperatorDialog.WorkdayBeginLabel
|
||||
}]).component();
|
||||
|
||||
this.saturdayPagerEndTimeInput = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'time',
|
||||
placeHolder: '06:00:00'
|
||||
}).component();
|
||||
this.saturdayPagerEndTimeInput.enabled = false;
|
||||
let saturdayEndInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.saturdayPagerEndTimeInput,
|
||||
title: OperatorDialog.WorkdayEndLabel
|
||||
}]).component();
|
||||
|
||||
let pagerSaturdayCheckboxContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
alignItems: 'baseline'
|
||||
}).withItems([this.pagerSaturdayCheckBox, saturdayStartInputContainer, saturdayEndInputContainer])
|
||||
.component();
|
||||
|
||||
this.pagerSundayCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: OperatorDialog.PagerSundayCheckBoxLabel,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.pagerSundayCheckBox.onChanged(() => {
|
||||
if (this.pagerSundayCheckBox.checked) {
|
||||
this.sundayPagerStartTimeInput.enabled = true;
|
||||
this.sundayPagerEndTimeInput.enabled = true;
|
||||
} else {
|
||||
this.sundayPagerStartTimeInput.enabled = false;
|
||||
this.sundayPagerEndTimeInput.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.sundayPagerStartTimeInput = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'time',
|
||||
placeHolder: '08:00:00'
|
||||
}).component();
|
||||
this.sundayPagerStartTimeInput.enabled = false;
|
||||
let sundayStartInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.sundayPagerStartTimeInput,
|
||||
title: OperatorDialog.WorkdayBeginLabel
|
||||
}]).component();
|
||||
|
||||
this.sundayPagerEndTimeInput = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'time',
|
||||
placeHolder: '06:00:00'
|
||||
}).component();
|
||||
this.sundayPagerEndTimeInput.enabled = false;
|
||||
let sundayEndInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.sundayPagerEndTimeInput,
|
||||
title: OperatorDialog.WorkdayEndLabel
|
||||
}]).component();
|
||||
|
||||
let pagerSundayCheckboxContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
alignItems: 'baseline'
|
||||
}).withItems([this.pagerSundayCheckBox, sundayStartInputContainer, sundayEndInputContainer])
|
||||
.component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.nameTextBox,
|
||||
title: OperatorDialog.NameLabel
|
||||
}, {
|
||||
component: this.enabledCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.emailNameTextBox,
|
||||
title: OperatorDialog.EmailNameTextLabel
|
||||
}, {
|
||||
component: this.pagerEmailNameTextBox,
|
||||
title: OperatorDialog.PagerEmailNameTextLabel
|
||||
}, {
|
||||
components: [{
|
||||
component: this.pagerMondayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerTuesdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerWednesdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerThursdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerFridayCheckboxContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerSaturdayCheckboxContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerSundayCheckboxContainer,
|
||||
title: ''
|
||||
}] ,
|
||||
title: OperatorDialog.PagerDutyScheduleLabel
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
}
|
||||
|
||||
private initializeNotificationTab() {
|
||||
this.notificationsTab.registerContent(async view => {
|
||||
|
||||
this.alertsTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
OperatorDialog.AlertNameColumnLabel,
|
||||
OperatorDialog.AlertEmailColumnLabel,
|
||||
OperatorDialog.AlertPagerColumnLabel
|
||||
],
|
||||
data: [],
|
||||
height: 500
|
||||
}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.alertsTable,
|
||||
title: OperatorDialog.AlertsTableLabel
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
}
|
||||
|
||||
protected updateModel() {
|
||||
this.model.name = this.nameTextBox.value;
|
||||
this.model.enabled = this.enabledCheckBox.checked;
|
||||
this.model.emailAddress = this.emailNameTextBox.value;
|
||||
this.model.pagerAddress = this.pagerEmailNameTextBox.value;
|
||||
this.model.weekdayPagerStartTime = this.weekdayPagerStartTimeInput.value;
|
||||
this.model.weekdayPagerEndTime = this.weekdayPagerEndTimeInput.value;
|
||||
this.model.saturdayPagerStartTime = this.saturdayPagerStartTimeInput.value;
|
||||
this.model.saturdayPagerEndTime = this.saturdayPagerEndTimeInput.value;
|
||||
this.model.sundayPagerStartTime = this.sundayPagerStartTimeInput.value;
|
||||
this.model.sundayPagerEndTime = this.sundayPagerEndTimeInput.value;
|
||||
}
|
||||
}
|
||||
95
extensions/agent/src/dialogs/pickScheduleDialog.ts
Normal file
95
extensions/agent/src/dialogs/pickScheduleDialog.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { PickScheduleData } from '../data/pickScheduleData';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class PickScheduleDialog {
|
||||
|
||||
// TODO: localize
|
||||
// Top level
|
||||
private readonly DialogTitle: string = localize('pickSchedule.jobSchedules', 'Job Schedules');
|
||||
private readonly OkButtonText: string = localize('pickSchedule.ok', 'OK');
|
||||
private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel');
|
||||
private readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Schedule Name');
|
||||
private readonly SchedulesLabelText: string = localize('pickSchedule.schedules', 'Schedules');
|
||||
|
||||
// UI Components
|
||||
private dialog: sqlops.window.modelviewdialog.Dialog;
|
||||
private schedulesTable: sqlops.TableComponent;
|
||||
|
||||
private model: PickScheduleData;
|
||||
|
||||
private _onSuccess: vscode.EventEmitter<PickScheduleData> = new vscode.EventEmitter<PickScheduleData>();
|
||||
public readonly onSuccess: vscode.Event<PickScheduleData> = this._onSuccess.event;
|
||||
|
||||
constructor(ownerUri: string) {
|
||||
this.model = new PickScheduleData(ownerUri);
|
||||
}
|
||||
|
||||
public async showDialog() {
|
||||
await this.model.initialize();
|
||||
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
|
||||
this.initializeContent();
|
||||
this.dialog.okButton.onClick(async () => await this.execute());
|
||||
this.dialog.cancelButton.onClick(async () => await this.cancel());
|
||||
this.dialog.okButton.label = this.OkButtonText;
|
||||
this.dialog.cancelButton.label = this.CancelButtonText;
|
||||
sqlops.window.modelviewdialog.openDialog(this.dialog);
|
||||
}
|
||||
|
||||
private initializeContent() {
|
||||
this.dialog.registerContent(async view => {
|
||||
this.schedulesTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
this.ScheduleNameLabelText
|
||||
],
|
||||
data: [],
|
||||
height: '80em',
|
||||
width: '40em'
|
||||
}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.schedulesTable,
|
||||
title: this.SchedulesLabelText
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
if (this.model.schedules) {
|
||||
let data: any[][] = [];
|
||||
for (let i = 0; i < this.model.schedules.length; ++i) {
|
||||
let schedule = this.model.schedules[i];
|
||||
data[i] = [ schedule.name ];
|
||||
}
|
||||
this.schedulesTable.data = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async execute() {
|
||||
this.updateModel();
|
||||
await this.model.save();
|
||||
this._onSuccess.fire(this.model);
|
||||
}
|
||||
|
||||
private async cancel() {
|
||||
}
|
||||
|
||||
private updateModel() {
|
||||
let selectedRows = this.schedulesTable.selectedRows;
|
||||
if (selectedRows && selectedRows.length > 0) {
|
||||
let selectedRow = selectedRows[0];
|
||||
this.model.selectedSchedule = this.model.schedules[selectedRow];
|
||||
}
|
||||
}
|
||||
}
|
||||
219
extensions/agent/src/dialogs/proxyDialog.ts
Normal file
219
extensions/agent/src/dialogs/proxyDialog.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import { AgentDialog } from './agentDialog';
|
||||
import { ProxyData } from '../data/proxyData';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class ProxyDialog extends AgentDialog<ProxyData> {
|
||||
|
||||
// Top level
|
||||
private static readonly CreateDialogTitle: string = localize('createProxy.createProxy', 'Create Proxy');
|
||||
private static readonly EditDialogTitle: string = localize('createProxy.editProxy', 'Edit Proxy');
|
||||
private static readonly GeneralTabText: string = localize('createProxy.General', 'General');
|
||||
|
||||
// General tab strings
|
||||
private static readonly ProxyNameTextBoxLabel: string = localize('createProxy.ProxyName', 'Proxy name');
|
||||
private static readonly CredentialNameTextBoxLabel: string = localize('createProxy.CredentialName', 'Credential name');
|
||||
private static readonly DescriptionTextBoxLabel: string = localize('createProxy.Description', 'Description');
|
||||
private static readonly SubsystemLabel: string = localize('createProxy.SubsystemName', 'Subsystem');
|
||||
private static readonly OperatingSystemLabel: string = localize('createProxy.OperatingSystem', 'Operating system (CmdExec)');
|
||||
private static readonly ReplicationSnapshotLabel: string = localize('createProxy.ReplicationSnapshot', 'Replication Snapshot');
|
||||
private static readonly ReplicationTransactionLogLabel: string = localize('createProxy.ReplicationTransactionLog', 'Replication Transaction-Log Reader');
|
||||
private static readonly ReplicationDistributorLabel: string = localize('createProxy.ReplicationDistributor', 'Replication Distributor');
|
||||
private static readonly ReplicationMergeLabel: string = localize('createProxy.ReplicationMerge', 'Replication Merge');
|
||||
private static readonly ReplicationQueueReaderLabel: string = localize('createProxy.ReplicationQueueReader', 'Replication Queue Reader');
|
||||
private static readonly SSASQueryLabel: string = localize('createProxy.SSASQueryLabel', 'SQL Server Analysis Services Query');
|
||||
private static readonly SSASCommandLabel: string = localize('createProxy.SSASCommandLabel', 'SQL Server Analysis Services Command');
|
||||
private static readonly SSISPackageLabel: string = localize('createProxy.SSISPackage', 'SQL Server Integration Services Package');
|
||||
private static readonly PowerShellLabel: string = localize('createProxy.PowerShell', 'PowerShell');
|
||||
private static readonly SubSystemHeadingLabel: string = localize('createProxy.subSystemHeading', 'Active to the following subsytems');
|
||||
|
||||
// UI Components
|
||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
|
||||
// General tab controls
|
||||
private proxyNameTextBox: sqlops.InputBoxComponent;
|
||||
private credentialNameDropDown: sqlops.DropDownComponent;
|
||||
private descriptionTextBox: sqlops.InputBoxComponent;
|
||||
private subsystemCheckBox: sqlops.CheckBoxComponent;
|
||||
private operatingSystemCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationSnapshotCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationTransactionLogCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationDistributorCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationMergeCheckbox: sqlops.CheckBoxComponent;
|
||||
private replicationQueueReaderCheckbox: sqlops.CheckBoxComponent;
|
||||
private sqlQueryCheckBox: sqlops.CheckBoxComponent;
|
||||
private sqlCommandCheckBox: sqlops.CheckBoxComponent;
|
||||
private sqlIntegrationServicesPackageCheckbox: sqlops.CheckBoxComponent;
|
||||
private powershellCheckBox: sqlops.CheckBoxComponent;
|
||||
|
||||
private credentials: sqlops.CredentialInfo[];
|
||||
|
||||
constructor(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo = undefined, credentials: sqlops.CredentialInfo[]) {
|
||||
super(
|
||||
ownerUri,
|
||||
new ProxyData(ownerUri, proxyInfo),
|
||||
proxyInfo ? ProxyDialog.EditDialogTitle : ProxyDialog.CreateDialogTitle);
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(ProxyDialog.GeneralTabText);
|
||||
|
||||
|
||||
this.initializeGeneralTab();
|
||||
|
||||
this.dialog.content = [this.generalTab];
|
||||
}
|
||||
|
||||
private initializeGeneralTab() {
|
||||
this.generalTab.registerContent(async view => {
|
||||
|
||||
this.proxyNameTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({width: 420})
|
||||
.component();
|
||||
|
||||
this.credentialNameDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
width: 432,
|
||||
value: '',
|
||||
editable: true,
|
||||
values: this.credentials.length > 0 ? this.credentials.map(c => c.name) : ['']
|
||||
})
|
||||
.component();
|
||||
|
||||
this.descriptionTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
width: 420,
|
||||
multiline: true,
|
||||
height: 300
|
||||
})
|
||||
.component();
|
||||
|
||||
this.subsystemCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SubsystemLabel
|
||||
}).component();
|
||||
|
||||
this.subsystemCheckBox.onChanged(() => {
|
||||
if (this.subsystemCheckBox.checked) {
|
||||
this.operatingSystemCheckBox.checked = true;
|
||||
this.replicationSnapshotCheckBox.checked = true;
|
||||
this.replicationTransactionLogCheckBox.checked = true;
|
||||
this.replicationDistributorCheckBox.checked = true;
|
||||
this.replicationMergeCheckbox.checked = true;
|
||||
this.replicationQueueReaderCheckbox.checked = true;
|
||||
this.sqlQueryCheckBox.checked = true;
|
||||
this.sqlCommandCheckBox.checked = true;
|
||||
this.sqlIntegrationServicesPackageCheckbox.checked = true;
|
||||
this.powershellCheckBox.checked = true;
|
||||
} else {
|
||||
this.operatingSystemCheckBox.checked = false;
|
||||
this.replicationSnapshotCheckBox.checked = false;
|
||||
this.replicationTransactionLogCheckBox.checked = false;
|
||||
this.replicationDistributorCheckBox.checked = false;
|
||||
this.replicationMergeCheckbox.checked = false;
|
||||
this.replicationQueueReaderCheckbox.checked = false;
|
||||
this.sqlQueryCheckBox.checked = false;
|
||||
this.sqlCommandCheckBox.checked = false;
|
||||
this.sqlIntegrationServicesPackageCheckbox.checked = false;
|
||||
this.powershellCheckBox.checked = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.operatingSystemCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.OperatingSystemLabel
|
||||
}).component();
|
||||
|
||||
this.replicationSnapshotCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationSnapshotLabel
|
||||
}).component();
|
||||
|
||||
this.replicationTransactionLogCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationTransactionLogLabel
|
||||
}).component();
|
||||
|
||||
this.replicationDistributorCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationDistributorLabel
|
||||
}).component();
|
||||
|
||||
this.replicationMergeCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationMergeLabel
|
||||
}).component();
|
||||
|
||||
this.replicationQueueReaderCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationQueueReaderLabel
|
||||
}).component();
|
||||
|
||||
this.sqlQueryCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SSASQueryLabel
|
||||
}).component();
|
||||
|
||||
this.sqlCommandCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SSASCommandLabel
|
||||
}).component();
|
||||
|
||||
this.sqlIntegrationServicesPackageCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SSISPackageLabel
|
||||
}).component();
|
||||
|
||||
this.powershellCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.PowerShellLabel
|
||||
}).component();
|
||||
|
||||
let checkBoxContainer = view.modelBuilder.groupContainer()
|
||||
.withItems([this.operatingSystemCheckBox, this.replicationSnapshotCheckBox,
|
||||
this.replicationTransactionLogCheckBox, this.replicationDistributorCheckBox, this.replicationMergeCheckbox,
|
||||
this.replicationQueueReaderCheckbox, this.sqlQueryCheckBox, this.sqlCommandCheckBox, this.sqlIntegrationServicesPackageCheckbox,
|
||||
this.powershellCheckBox])
|
||||
.component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.proxyNameTextBox,
|
||||
title: ProxyDialog.ProxyNameTextBoxLabel
|
||||
}, {
|
||||
component: this.credentialNameDropDown,
|
||||
title: ProxyDialog.CredentialNameTextBoxLabel
|
||||
}, {
|
||||
component: this.descriptionTextBox,
|
||||
title: ProxyDialog.DescriptionTextBoxLabel
|
||||
}]).withLayout({ width: 420 }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
this.proxyNameTextBox.value = this.model.accountName;
|
||||
this.credentialNameDropDown.value = this.model.credentialName;
|
||||
this.descriptionTextBox.value = this.model.description;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected updateModel() {
|
||||
this.model.accountName = this.proxyNameTextBox.value;
|
||||
this.model.credentialName = this.credentialNameDropDown.value as string;
|
||||
this.model.credentialId = this.credentials.find(
|
||||
c => c.name === this.model.credentialName).id;
|
||||
this.model.credentialIdentity = this.credentials.find(
|
||||
c => c.name === this.model.credentialName).identity;
|
||||
this.model.description = this.descriptionTextBox.value;
|
||||
}
|
||||
}
|
||||
95
extensions/agent/src/dialogs/scheduleDialog.ts
Normal file
95
extensions/agent/src/dialogs/scheduleDialog.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { ScheduleData } from '../data/scheduleData';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class ScheduleDialog {
|
||||
|
||||
// Top level
|
||||
private readonly DialogTitle: string = localize('scheduleDialog.newSchedule', 'New Schedule');
|
||||
private readonly OkButtonText: string = localize('scheduleDialog.ok', 'OK');
|
||||
private readonly CancelButtonText: string = localize('scheduleDialog.cancel', 'Cancel');
|
||||
private readonly ScheduleNameText: string = localize('scheduleDialog.scheduleName', 'Schedule Name');
|
||||
private readonly SchedulesLabelText: string = localize('scheduleDialog.schedules', 'Schedules');
|
||||
|
||||
// UI Components
|
||||
private dialog: sqlops.window.modelviewdialog.Dialog;
|
||||
private schedulesTable: sqlops.TableComponent;
|
||||
|
||||
private model: ScheduleData;
|
||||
|
||||
private _onSuccess: vscode.EventEmitter<ScheduleData> = new vscode.EventEmitter<ScheduleData>();
|
||||
public readonly onSuccess: vscode.Event<ScheduleData> = this._onSuccess.event;
|
||||
|
||||
constructor(ownerUri: string) {
|
||||
this.model = new ScheduleData(ownerUri);
|
||||
}
|
||||
|
||||
public async showDialog() {
|
||||
await this.model.initialize();
|
||||
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
|
||||
this.initializeContent();
|
||||
this.dialog.okButton.onClick(async () => await this.execute());
|
||||
this.dialog.cancelButton.onClick(async () => await this.cancel());
|
||||
this.dialog.okButton.label = this.OkButtonText;
|
||||
this.dialog.cancelButton.label = this.CancelButtonText;
|
||||
|
||||
sqlops.window.modelviewdialog.openDialog(this.dialog);
|
||||
}
|
||||
|
||||
private initializeContent() {
|
||||
this.dialog.registerContent(async view => {
|
||||
this.schedulesTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
this.ScheduleNameText
|
||||
],
|
||||
data: [],
|
||||
height: 600,
|
||||
width: 400
|
||||
}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.schedulesTable,
|
||||
title: this.SchedulesLabelText
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
if (this.model.schedules) {
|
||||
let data: any[][] = [];
|
||||
for (let i = 0; i < this.model.schedules.length; ++i) {
|
||||
let schedule = this.model.schedules[i];
|
||||
data[i] = [ schedule.name ];
|
||||
}
|
||||
this.schedulesTable.data = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async execute() {
|
||||
this.updateModel();
|
||||
await this.model.save();
|
||||
this._onSuccess.fire(this.model);
|
||||
}
|
||||
|
||||
private async cancel() {
|
||||
}
|
||||
|
||||
private updateModel() {
|
||||
let selectedRows = this.schedulesTable.selectedRows;
|
||||
if (selectedRows && selectedRows.length > 0) {
|
||||
let selectedRow = selectedRows[0];
|
||||
this.model.selectedSchedule = this.model.schedules[selectedRow];
|
||||
}
|
||||
}
|
||||
}
|
||||
17
extensions/agent/src/interfaces.ts
Normal file
17
extensions/agent/src/interfaces.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
export enum AgentDialogMode {
|
||||
CREATE = 1,
|
||||
EDIT = 2,
|
||||
VIEW = 3
|
||||
}
|
||||
|
||||
export interface IAgentDialogData {
|
||||
dialogMode: AgentDialogMode;
|
||||
initialize(): void;
|
||||
save(): void;
|
||||
}
|
||||
21
extensions/agent/src/main.ts
Normal file
21
extensions/agent/src/main.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import vscode = require('vscode');
|
||||
import { MainController } from './mainController';
|
||||
export let controller: MainController;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
controller = new MainController(context);
|
||||
controller.activate();
|
||||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
export function deactivate(): void {
|
||||
if (controller) {
|
||||
controller.deactivate();
|
||||
}
|
||||
}
|
||||
72
extensions/agent/src/mainController.ts
Normal file
72
extensions/agent/src/mainController.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { AlertDialog } from './dialogs/alertDialog';
|
||||
import { JobDialog } from './dialogs/jobDialog';
|
||||
import { OperatorDialog } from './dialogs/operatorDialog';
|
||||
import { ProxyDialog } from './dialogs/proxyDialog';
|
||||
import { JobStepDialog } from './dialogs/jobStepDialog';
|
||||
import { PickScheduleDialog } from './dialogs/pickScheduleDialog';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
*/
|
||||
export class MainController {
|
||||
protected _context: vscode.ExtensionContext;
|
||||
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
public constructor(context: vscode.ExtensionContext) {
|
||||
this._context = context;
|
||||
}
|
||||
|
||||
public static showNotYetImplemented(): void {
|
||||
vscode.window.showInformationMessage(
|
||||
localize('mainController.notImplemented', "This feature is under development. Check-out the latest insiders build if you'd like to try out the most recent changes!"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the extension
|
||||
*/
|
||||
public activate(): void {
|
||||
vscode.commands.registerCommand('agent.openJobDialog', (ownerUri: string, jobInfo: sqlops.AgentJobInfo) => {
|
||||
let dialog = new JobDialog(ownerUri, jobInfo);
|
||||
dialog.openDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, jobId: string, server: string, stepId: number) => {
|
||||
let dialog = new JobStepDialog(ownerUri, jobId, server, stepId);
|
||||
dialog.openNewStepDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openPickScheduleDialog', (ownerUri: string) => {
|
||||
let dialog = new PickScheduleDialog(ownerUri);
|
||||
dialog.showDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, alertInfo: sqlops.AgentAlertInfo, jobs: string[]) => {
|
||||
let dialog = new AlertDialog(ownerUri, alertInfo, jobs);
|
||||
dialog.openDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openOperatorDialog', (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo) => {
|
||||
let dialog = new OperatorDialog(ownerUri, operatorInfo);
|
||||
dialog.openDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openProxyDialog', (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo, credentials: sqlops.CredentialInfo[]) => {
|
||||
//@TODO: reenable create proxy after snapping July release (7/14/18)
|
||||
// let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
|
||||
// dialog.openDialog();
|
||||
MainController.showNotYetImplemented();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the extension
|
||||
*/
|
||||
public deactivate(): void {
|
||||
}
|
||||
}
|
||||
21
extensions/agent/src/test/agent.test.ts
Normal file
21
extensions/agent/src/test/agent.test.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import * as sqlops from 'sqlops';
|
||||
import { JobData } from '../data/jobData';
|
||||
import { TestAgentService } from './testAgentService';
|
||||
|
||||
const testOwnerUri = 'agent://testuri';
|
||||
|
||||
suite('Agent extension', () => {
|
||||
test('Create Job Data', async () => {
|
||||
let testAgentService = new TestAgentService();
|
||||
let data = new JobData(testOwnerUri, undefined, testAgentService);
|
||||
data.save();
|
||||
});
|
||||
});
|
||||
110
extensions/agent/src/test/testAgentService.ts
Normal file
110
extensions/agent/src/test/testAgentService.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
export class TestAgentService implements sqlops.AgentServicesProvider {
|
||||
handle?: number;
|
||||
readonly providerId: string = 'Test Provider';
|
||||
|
||||
// Job management methods
|
||||
getJobs(ownerUri: string): Thenable<sqlops.AgentJobsResult> {
|
||||
return undefined;
|
||||
}
|
||||
getJobHistory(ownerUri: string, jobId: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return undefined;
|
||||
}
|
||||
jobAction(ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> {
|
||||
return undefined;
|
||||
}
|
||||
createJob(ownerUri: string, jobInfo: sqlops.AgentJobInfo): Thenable<sqlops.CreateAgentJobResult> {
|
||||
return undefined;
|
||||
}
|
||||
updateJob(ownerUri: string, originalJobName: string, jobInfo: sqlops.AgentJobInfo): Thenable<sqlops.UpdateAgentJobResult> {
|
||||
return undefined;
|
||||
}
|
||||
deleteJob(ownerUri: string, jobInfo: sqlops.AgentJobInfo): Thenable<sqlops.ResultStatus> {
|
||||
return undefined;
|
||||
}
|
||||
getJobDefaults(ownerUri: string): Thenable<sqlops.AgentJobDefaultsResult> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Job Step management methods
|
||||
createJobStep(ownerUri: string, jobInfo: sqlops.AgentJobStepInfo): Thenable<sqlops.CreateAgentJobStepResult> {
|
||||
return undefined;
|
||||
}
|
||||
updateJobStep(ownerUri: string, originalJobStepName: string, jobInfo: sqlops.AgentJobStepInfo): Thenable<sqlops.UpdateAgentJobStepResult> {
|
||||
return undefined;
|
||||
}
|
||||
deleteJobStep(ownerUri: string, jobInfo: sqlops.AgentJobStepInfo): Thenable<sqlops.ResultStatus> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Alert management methods
|
||||
getAlerts(ownerUri: string): Thenable<sqlops.AgentAlertsResult> {
|
||||
return undefined;
|
||||
}
|
||||
createAlert(ownerUri: string, alertInfo: sqlops.AgentAlertInfo): Thenable<sqlops.CreateAgentAlertResult> {
|
||||
return undefined;
|
||||
}
|
||||
updateAlert(ownerUri: string, originalAlertName: string, alertInfo: sqlops.AgentAlertInfo): Thenable<sqlops.UpdateAgentAlertResult> {
|
||||
return undefined;
|
||||
}
|
||||
deleteAlert(ownerUri: string, alertInfo: sqlops.AgentAlertInfo): Thenable<sqlops.ResultStatus> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Operator management methods
|
||||
getOperators(ownerUri: string): Thenable<sqlops.AgentOperatorsResult> {
|
||||
return undefined;
|
||||
}
|
||||
createOperator(ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo): Thenable<sqlops.CreateAgentOperatorResult> {
|
||||
return undefined;
|
||||
}
|
||||
updateOperator(ownerUri: string, originalOperatorName: string, operatorInfo: sqlops.AgentOperatorInfo): Thenable<sqlops.UpdateAgentOperatorResult> {
|
||||
return undefined;
|
||||
}
|
||||
deleteOperator(ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo): Thenable<sqlops.ResultStatus> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Proxy management methods
|
||||
getProxies(ownerUri: string): Thenable<sqlops.AgentProxiesResult> {
|
||||
return undefined;
|
||||
}
|
||||
createProxy(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.CreateAgentOperatorResult> {
|
||||
return undefined;
|
||||
}
|
||||
updateProxy(ownerUri: string, originalProxyName: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.UpdateAgentOperatorResult> {
|
||||
return undefined;
|
||||
}
|
||||
deleteProxy(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Agent Credential method
|
||||
getCredentials(ownerUri: string): Thenable<sqlops.GetCredentialsResult> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Job Schedule management methods
|
||||
getJobSchedules(ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> {
|
||||
return undefined;
|
||||
}
|
||||
createJobSchedule(ownerUri: string, scheduleInfo: sqlops.AgentJobScheduleInfo): Thenable<sqlops.CreateAgentJobScheduleResult> {
|
||||
return undefined;
|
||||
}
|
||||
updateJobSchedule(ownerUri: string, originalScheduleName: string, scheduleInfo: sqlops.AgentJobScheduleInfo): Thenable<sqlops.UpdateAgentJobScheduleResult> {
|
||||
return undefined;
|
||||
}
|
||||
deleteJobSchedule(ownerUri: string, scheduleInfo: sqlops.AgentJobScheduleInfo): Thenable<sqlops.ResultStatus> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
registerOnUpdated(handler: () => any): void {
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
|
||||
/// <reference types='@types/node'/>
|
||||
/// <reference path='../../../../src/sql/sqlops.d.ts'/>
|
||||
/// <reference path='../../../../src/sql/sqlops.proposed.d.ts'/>
|
||||
/// <reference types='@types/node'/>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/mmims/language-batchfile/commit/3dd105c31484e5975144478dac1aa91d8f51e528",
|
||||
"version": "https://github.com/mmims/language-batchfile/commit/6235c491be4dff49cd3966b50142874d7f79580a",
|
||||
"name": "Batch File",
|
||||
"scopeName": "source.batchfile",
|
||||
"patterns": [
|
||||
@@ -46,14 +46,17 @@
|
||||
"commands": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "(?<=^|[\\s@])(?i:adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|brea|cacls|cd|certreq|certutil|change|chcp|chdir|chglogon|chgport|chgusr|chkdsk|chkntfs|choice|cipher|clip|clscluadmin|cluster|cmd|cmdkey|cmstp|color|comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|dispdiag|doin|dnscmd|doskey|driverquery|dsacls|dsadd|dsamain|dsdbutil|dsget|dsmgmt|dsmod|dsmove|dsquery|dsrm|edit|endlocal|eraseesentutl|eventcreate|eventquery|eventtriggers|evntcmd|expand|extract|fc|filescrn|find|findstr|finger|flattemp|fonde|forfiles|format|freedisk|fsutil|ftp|ftype|fveupdate|getmac|gettype|gpfixup|gpresult|gpupdate|graftabl|hashgen|hep|helpctr|hostname|icacls|iisreset|inuse|ipconfig|ipxroute|irftp|ismserv|jetpack|klist|ksetup|ktmutil|ktpass|label|ldifd|ldp|lodctr|logman|logoff|lpq|lpr|macfile|makecab|manage-bde|mapadmin|md|mkdir|mklink|mmc|mode|more|mount|mountvol|move|mqbup|mqsvc|mqtgsvc|msdt|msg|msiexec|msinfo32|mstsc|nbtstat|net computer|net group|net localgroup|net print|net session|net share|net start|net stop|net use|net user|net view|net|netcfg|netdiag|netdom|netsh|netstat|nfsadmin|nfsshare|nfsstat|nlb|nlbmgr|nltest|nslookup|ntackup|ntcmdprompt|ntdsutil|ntfrsutl|openfiles|pagefileconfig|path|pathping|pause|pbadmin|pentnt|perfmon|ping|pnpunatten|pnputil|popd|powercfg|powershell|powershell_ise|print|prncnfg|prndrvr|prnjobs|prnmngr|prnport|prnqctl|prompt|pubprn|pushd|pushprinterconnections|pwlauncher|qappsrv|qprocess|query|quser|qwinsta|rasdial|rcp|rd|rdpsign|regentc|recover|redircmp|redirusr|reg|regini|regsvr32|relog|ren|rename|rendom|repadmin|repair-bde|replace|reset session|rxec|risetup|rmdir|robocopy|route|rpcinfo|rpcping|rsh|runas|rundll32|rwinsta|sc|schtasks|scwcmd|secedit|serverceipoptin|servrmanagercmd|serverweroptin|setlocal|setspn|setx|sfc|shadow|shift|showmount|shutdown|sort|start|storrept|subst|sxstrace|ysocmgr|systeminfo|takeown|tapicfg|taskkill|tasklist|tcmsetup|telnet|tftp|time|timeout|title|tlntadmn|tpmvscmgr|tpmvscmgr|tacerpt|tracert|tree|tscon|tsdiscon|tsecimp|tskill|tsprof|type|typeperf|tzutil|uddiconfig|umount|unlodctr|ver|verifier|verif|vol|vssadmin|w32tm|waitfor|wbadmin|wdsutil|wecutil|wevtutil|where|whoami|winnt|winnt32|winpop|winrm|winrs|winsat|wlbs|mic|wscript|xcopy)(?=$|\\s)",
|
||||
"match": "(?<=^|[\\s@])(?i:adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|brea|cacls|cd|certreq|certutil|change|chcp|chdir|chglogon|chgport|chgusr|chkdsk|chkntfs|choice|cipher|clip|cls|clscluadmin|cluster|cmd|cmdkey|cmstp|color|comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|dispdiag|doin|dnscmd|doskey|driverquery|dsacls|dsadd|dsamain|dsdbutil|dsget|dsmgmt|dsmod|dsmove|dsquery|dsrm|edit|endlocal|eraseesentutl|eventcreate|eventquery|eventtriggers|evntcmd|expand|extract|fc|filescrn|find|findstr|finger|flattemp|fonde|forfiles|format|freedisk|fsutil|ftp|ftype|fveupdate|getmac|gettype|gpfixup|gpresult|gpupdate|graftabl|hashgen|hep|helpctr|hostname|icacls|iisreset|inuse|ipconfig|ipxroute|irftp|ismserv|jetpack|klist|ksetup|ktmutil|ktpass|label|ldifd|ldp|lodctr|logman|logoff|lpq|lpr|macfile|makecab|manage-bde|mapadmin|md|mkdir|mklink|mmc|mode|more|mount|mountvol|move|mqbup|mqsvc|mqtgsvc|msdt|msg|msiexec|msinfo32|mstsc|nbtstat|net computer|net group|net localgroup|net print|net session|net share|net start|net stop|net use|net user|net view|net|netcfg|netdiag|netdom|netsh|netstat|nfsadmin|nfsshare|nfsstat|nlb|nlbmgr|nltest|nslookup|ntackup|ntcmdprompt|ntdsutil|ntfrsutl|openfiles|pagefileconfig|path|pathping|pause|pbadmin|pentnt|perfmon|ping|pnpunatten|pnputil|popd|powercfg|powershell|powershell_ise|print|prncnfg|prndrvr|prnjobs|prnmngr|prnport|prnqctl|prompt|pubprn|pushd|pushprinterconnections|pwlauncher|qappsrv|qprocess|query|quser|qwinsta|rasdial|rcp|rd|rdpsign|regentc|recover|redircmp|redirusr|reg|regini|regsvr32|relog|ren|rename|rendom|repadmin|repair-bde|replace|reset session|rxec|risetup|rmdir|robocopy|route|rpcinfo|rpcping|rsh|runas|rundll32|rwinsta|sc|schtasks|scwcmd|secedit|serverceipoptin|servrmanagercmd|serverweroptin|setspn|setx|sfc|shadow|shift|showmount|shutdown|sort|start|storrept|subst|sxstrace|ysocmgr|systeminfo|takeown|tapicfg|taskkill|tasklist|tcmsetup|telnet|tftp|time|timeout|title|tlntadmn|tpmvscmgr|tpmvscmgr|tacerpt|tracert|tree|tscon|tsdiscon|tsecimp|tskill|tsprof|type|typeperf|tzutil|uddiconfig|umount|unlodctr|ver|verifier|verif|vol|vssadmin|w32tm|waitfor|wbadmin|wdsutil|wecutil|wevtutil|where|whoami|winnt|winnt32|winpop|winrm|winrs|winsat|wlbs|mic|wscript|xcopy)(?=$|\\s)",
|
||||
"name": "keyword.command.batchfile"
|
||||
},
|
||||
{
|
||||
"begin": "(?<=^|[\\s@])(?i:echo)(?=$|\\s|\\.)",
|
||||
"begin": "(?i)(?<=^|[\\s@])(echo)(?:(?=$|\\.|:)|\\s+(?:(on|off)(?=\\s*$))?)",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"1": {
|
||||
"name": "keyword.command.batchfile"
|
||||
},
|
||||
"2": {
|
||||
"name": "keyword.other.special-method.batchfile"
|
||||
}
|
||||
},
|
||||
"end": "(?=$\\n|[&|><)])",
|
||||
@@ -72,6 +75,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": "(?i)(?<=^|[\\s@])(setlocal)(?:\\s*$|\\s+(EnableExtensions|DisableExtensions|EnableDelayedExpansion|DisableDelayedExpansion)(?=\\s*$))",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.command.batchfile"
|
||||
},
|
||||
"2": {
|
||||
"name": "keyword.other.special-method.batchfile"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": "#command_set"
|
||||
}
|
||||
@@ -110,35 +124,7 @@
|
||||
"include": "#parens"
|
||||
},
|
||||
{
|
||||
"begin": "(\")\\s*([^ ][^=]*)(=)\"?",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.string.begin.batchfile"
|
||||
},
|
||||
"2": {
|
||||
"name": "variable.other.readwrite.batchfile"
|
||||
},
|
||||
"3": {
|
||||
"name": "keyword.operator.assignment.batchfile"
|
||||
}
|
||||
},
|
||||
"end": "\"",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "string.quoted.double.batchfile"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#variables"
|
||||
},
|
||||
{
|
||||
"include": "#numbers"
|
||||
},
|
||||
{
|
||||
"include": "#parens"
|
||||
}
|
||||
]
|
||||
"include": "#command_set_strings"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
@@ -215,6 +201,9 @@
|
||||
"begin": "\\s+/[pP]\\s+",
|
||||
"end": "(?=$\\n|[&|><)])",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#command_set_strings"
|
||||
},
|
||||
{
|
||||
"begin": "([^ ][^=]*)(=)",
|
||||
"beginCaptures": {
|
||||
@@ -294,6 +283,42 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"command_set_strings": {
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "(\")\\s*([^ ][^=]*)(=)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.string.begin.batchfile"
|
||||
},
|
||||
"2": {
|
||||
"name": "variable.other.readwrite.batchfile"
|
||||
},
|
||||
"3": {
|
||||
"name": "keyword.operator.assignment.batchfile"
|
||||
}
|
||||
},
|
||||
"end": "\"",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.batchfile"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.double.batchfile",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#variables"
|
||||
},
|
||||
{
|
||||
"include": "#numbers"
|
||||
},
|
||||
{
|
||||
"include": "#escaped_characters"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
@@ -359,7 +384,7 @@
|
||||
"controls": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "(?<=^|\\s)(?i)(?:goto|call|exit)(?=$|\\s)",
|
||||
"match": "(?i)(?<=^|\\s)(?:call|exit(?=$|\\s)|goto(?=$|\\s|:))",
|
||||
"name": "keyword.control.statement.batchfile"
|
||||
},
|
||||
{
|
||||
@@ -389,7 +414,7 @@
|
||||
"escaped_characters": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "%%|\\^\\^!|\\^.|\\^\\n",
|
||||
"match": "%%|\\^\\^!|\\^(?=.)|\\^\\n",
|
||||
"name": "constant.character.escape.batchfile"
|
||||
}
|
||||
]
|
||||
@@ -397,7 +422,7 @@
|
||||
"labels": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "^\\s*(:)([^+=,;:\\s].*)$",
|
||||
"match": "(?i)(?:^\\s*|(?<=goto)\\s*)(:)([^+=,;:\\s].*)$",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "punctuation.separator.batchfile"
|
||||
@@ -432,11 +457,11 @@
|
||||
"name": "keyword.operator.logical.batchfile"
|
||||
},
|
||||
{
|
||||
"match": "&&?|\\|\\|",
|
||||
"match": "(?<!\\^)&&?|\\|\\|",
|
||||
"name": "keyword.operator.conditional.batchfile"
|
||||
},
|
||||
{
|
||||
"match": "\\|",
|
||||
"match": "(?<!\\^)\\|",
|
||||
"name": "keyword.operator.pipe.batchfile"
|
||||
},
|
||||
{
|
||||
@@ -493,6 +518,10 @@
|
||||
},
|
||||
"name": "string.quoted.double.batchfile",
|
||||
"patterns": [
|
||||
{
|
||||
"match": "%%",
|
||||
"name": "constant.character.escape.batchfile"
|
||||
},
|
||||
{
|
||||
"include": "#variables"
|
||||
}
|
||||
@@ -507,9 +536,11 @@
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.batchfile"
|
||||
},
|
||||
"2": {
|
||||
"name": "variable.parameter.batchfile"
|
||||
}
|
||||
},
|
||||
"name": "variable.parameter.batchfile"
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": "#variable"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " off",
|
||||
"c": " ",
|
||||
"t": "source.batchfile",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
@@ -32,6 +32,17 @@
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "off",
|
||||
"t": "source.batchfile keyword.other.special-method.batchfile",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "setlocal",
|
||||
"t": "source.batchfile keyword.command.batchfile",
|
||||
@@ -89,13 +100,13 @@
|
||||
},
|
||||
{
|
||||
"c": "%",
|
||||
"t": "source.batchfile variable.parameter.batchfile punctuation.definition.variable.batchfile",
|
||||
"t": "source.batchfile punctuation.definition.variable.batchfile",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
"engines": {
|
||||
"vscode": "^1.0.0"
|
||||
},
|
||||
"categories": [
|
||||
"Languages",
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:json",
|
||||
"onLanguage:jsonc"
|
||||
|
||||
@@ -70,7 +70,12 @@ function autoFixSettingsJSON(willSaveEvent: vscode.TextDocumentWillSaveEvent): v
|
||||
onError(error: ParseErrorCode, offset: number, length: number): void {
|
||||
if (error === ParseErrorCode.CommaExpected && lastEndOfSomething > -1) {
|
||||
const fixPosition = document.positionAt(lastEndOfSomething);
|
||||
edit.insert(document.uri, fixPosition, ',');
|
||||
|
||||
// Don't insert a comma immediately before a : or ' :'
|
||||
const colonRange = document.getWordRangeAtPosition(fixPosition, / *:/);
|
||||
if (!colonRange) {
|
||||
edit.insert(document.uri, fixPosition, ',');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"version": "0.0.0",
|
||||
"license": "Apache2",
|
||||
"repositoryURL": "https://github.com/moby/moby",
|
||||
"description": "The file syntaxes/Dockerfile.tmLanguage was included from https://github.com/moby/moby/blob/master/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage."
|
||||
"description": "The file syntaxes/docker.tmLanguage was included from https://github.com/moby/moby/blob/master/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage."
|
||||
}]
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
"engines": {
|
||||
"vscode": "^1.4.0"
|
||||
},
|
||||
"categories": [
|
||||
"Languages",
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:json",
|
||||
"onLanguage:markdown",
|
||||
|
||||
@@ -834,6 +834,23 @@
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
}
|
||||
],
|
||||
"editor/context": [
|
||||
{
|
||||
"command": "git.stageSelectedRanges",
|
||||
"group": "2_git@1",
|
||||
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageSelectedRanges",
|
||||
"group": "2_git@2",
|
||||
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
},
|
||||
{
|
||||
"command": "git.revertSelectedRanges",
|
||||
"group": "2_git@3",
|
||||
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
|
||||
}
|
||||
],
|
||||
"scm/change/title": [
|
||||
{
|
||||
"command": "git.stageChange",
|
||||
@@ -861,7 +878,7 @@
|
||||
],
|
||||
"description": "%config.path%",
|
||||
"default": null,
|
||||
"isExecutable": true
|
||||
"scope": "application"
|
||||
},
|
||||
"git.autoRepositoryDetection": {
|
||||
"type": "boolean",
|
||||
@@ -964,6 +981,12 @@
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%config.detectSubmodules%"
|
||||
},
|
||||
"git.detectSubmodulesLimit": {
|
||||
"type": "number",
|
||||
"scope": "resource",
|
||||
"default": 10,
|
||||
"description": "%config.detectSubmodulesLimit%"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1090,7 +1113,8 @@
|
||||
"byline": "^5.0.0",
|
||||
"file-type": "^7.2.0",
|
||||
"iconv-lite": "0.4.19",
|
||||
"vscode-extension-telemetry": "0.0.15",
|
||||
"jschardet": "^1.6.0",
|
||||
"vscode-extension-telemetry": "0.0.17",
|
||||
"vscode-nls": "^3.2.1",
|
||||
"which": "^1.3.0"
|
||||
},
|
||||
@@ -1102,4 +1126,4 @@
|
||||
"@types/which": "^1.0.28",
|
||||
"mocha": "^3.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"config.showInlineOpenFileAction": "Controls whether to show an inline Open File action in the Git changes view.",
|
||||
"config.inputValidation": "Controls when to show commit message input validation.",
|
||||
"config.detectSubmodules": "Controls whether to automatically detect git submodules.",
|
||||
"config.detectSubmodulesLimit": "Controls the limit of git submodules detected.",
|
||||
"colors.modified": "Color for modified resources.",
|
||||
"colors.deleted": "Color for deleted resources.",
|
||||
"colors.untracked": "Color for untracked resources.",
|
||||
|
||||
@@ -6,37 +6,55 @@
|
||||
'use strict';
|
||||
|
||||
import { Model } from './model';
|
||||
import { Uri } from 'vscode';
|
||||
import { Repository as ModelRepository } from './repository';
|
||||
import { Uri, SourceControlInputBox } from 'vscode';
|
||||
|
||||
export interface InputBox {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export class InputBoxImpl implements InputBox {
|
||||
set value(value: string) { this.inputBox.value = value; }
|
||||
get value(): string { return this.inputBox.value; }
|
||||
constructor(private inputBox: SourceControlInputBox) { }
|
||||
}
|
||||
|
||||
export interface Repository {
|
||||
readonly rootUri: Uri;
|
||||
readonly inputBox: InputBox;
|
||||
}
|
||||
|
||||
export interface API {
|
||||
getRepositories(): Promise<Repository[]>;
|
||||
export class RepositoryImpl implements Repository {
|
||||
|
||||
readonly rootUri: Uri;
|
||||
readonly inputBox: InputBox;
|
||||
|
||||
constructor(repository: ModelRepository) {
|
||||
this.rootUri = Uri.file(repository.root);
|
||||
this.inputBox = new InputBoxImpl(repository.inputBox);
|
||||
}
|
||||
}
|
||||
|
||||
export function createApi(modelPromise: Promise<Model>) {
|
||||
return {
|
||||
async getRepositories(): Promise<Repository[]> {
|
||||
const model = await modelPromise;
|
||||
export interface API {
|
||||
getRepositories(): Promise<Repository[]>;
|
||||
getGitPath(): Promise<string>;
|
||||
}
|
||||
|
||||
return model.repositories.map(repository => ({
|
||||
rootUri: Uri.file(repository.root),
|
||||
inputBox: {
|
||||
set value(value: string) {
|
||||
repository.inputBox.value = value;
|
||||
},
|
||||
get value(): string {
|
||||
return repository.inputBox.value;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
export class APIImpl implements API {
|
||||
|
||||
constructor(private modelPromise: Promise<Model>) { }
|
||||
|
||||
async getGitPath(): Promise<string> {
|
||||
const model = await this.modelPromise;
|
||||
return model.git.path;
|
||||
}
|
||||
|
||||
async getRepositories(): Promise<Repository[]> {
|
||||
const model = await this.modelPromise;
|
||||
return model.repositories.map(repository => new RepositoryImpl(repository));
|
||||
}
|
||||
}
|
||||
|
||||
export function createApi(modelPromise: Promise<Model>): API {
|
||||
return new APIImpl(modelPromise);
|
||||
}
|
||||
@@ -56,7 +56,8 @@ export class AutoFetcher {
|
||||
const yes: MessageItem = { title: localize('yes', "Yes") };
|
||||
const no: MessageItem = { isCloseAffordance: true, title: localize('no', "No") };
|
||||
const askLater: MessageItem = { title: localize('not now', "Ask Me Later") };
|
||||
const result = await window.showInformationMessage(localize('suggest auto fetch', "Would you like Code to [periodically run 'git fetch']({0})?", 'https://go.microsoft.com/fwlink/?linkid=865294'), yes, no, askLater);
|
||||
// {{SQL CARBON EDIT}}
|
||||
const result = await window.showInformationMessage(localize('suggest auto fetch', "Would you like SQL Operations Studio to [periodically run 'git fetch']({0})?", 'https://go.microsoft.com/fwlink/?linkid=865294'), yes, no, askLater);
|
||||
|
||||
if (result === askLater) {
|
||||
return;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor, CancellationTokenSource, StatusBarAlignment } from 'vscode';
|
||||
import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor, MessageOptions } from 'vscode';
|
||||
import { Ref, RefType, Git, GitErrorCodes, Branch } from './git';
|
||||
import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository';
|
||||
import { Model } from './model';
|
||||
@@ -328,8 +328,6 @@ export class CommandCenter {
|
||||
return '';
|
||||
}
|
||||
|
||||
private static cloneId = 0;
|
||||
|
||||
@command('git.clone')
|
||||
async clone(url?: string): Promise<void> {
|
||||
if (!url) {
|
||||
@@ -350,15 +348,18 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
const config = workspace.getConfiguration('git');
|
||||
let value = config.get<string>('defaultCloneDirectory') || os.homedir();
|
||||
let defaultCloneDirectory = config.get<string>('defaultCloneDirectory') || os.homedir();
|
||||
defaultCloneDirectory = defaultCloneDirectory.replace(/^~/, os.homedir());
|
||||
|
||||
const parentPath = await window.showInputBox({
|
||||
prompt: localize('parent', "Parent Directory"),
|
||||
value,
|
||||
ignoreFocusOut: true
|
||||
const uris = await window.showOpenDialog({
|
||||
canSelectFiles: false,
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
defaultUri: Uri.file(defaultCloneDirectory),
|
||||
openLabel: localize('selectFolder', "Select Repository Location")
|
||||
});
|
||||
|
||||
if (!parentPath) {
|
||||
if (!uris || uris.length === 0) {
|
||||
/* __GDPR__
|
||||
"clone" : {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
@@ -368,25 +369,33 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const cancelCommandId = `cancelClone${CommandCenter.cloneId++}`;
|
||||
const commandDisposable = commands.registerCommand(cancelCommandId, () => tokenSource.cancel());
|
||||
|
||||
const statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
|
||||
statusBarItem.text = localize('cancel', "$(sync~spin) Cloning repository... Click to cancel");
|
||||
statusBarItem.tooltip = localize('cancel tooltip', "Cancel clone");
|
||||
statusBarItem.command = cancelCommandId;
|
||||
statusBarItem.show();
|
||||
|
||||
const clonePromise = this.git.clone(url, parentPath.replace(/^~/, os.homedir()), tokenSource.token);
|
||||
const uri = uris[0];
|
||||
const parentPath = uri.fsPath;
|
||||
|
||||
try {
|
||||
window.withProgress({ location: ProgressLocation.SourceControl, title: localize('cloning', "Cloning git repository...") }, () => clonePromise);
|
||||
const opts = {
|
||||
location: ProgressLocation.Notification,
|
||||
title: localize('cloning', "Cloning git repository '{0}'...", url),
|
||||
cancellable: true
|
||||
};
|
||||
|
||||
const repositoryPath = await clonePromise;
|
||||
const repositoryPath = await window.withProgress(
|
||||
opts,
|
||||
(_, token) => this.git.clone(url!, parentPath, token)
|
||||
);
|
||||
|
||||
const choices = [];
|
||||
let message = localize('proposeopen', "Would you like to open the cloned repository?");
|
||||
const open = localize('openrepo', "Open Repository");
|
||||
const result = await window.showInformationMessage(localize('proposeopen', "Would you like to open the cloned repository?"), open);
|
||||
choices.push(open);
|
||||
|
||||
const addToWorkspace = localize('add', "Add to Workspace");
|
||||
if (workspace.workspaceFolders) {
|
||||
message = localize('proposeopen2', "Would you like to open the cloned repository, or add it to the current workspace?");
|
||||
choices.push(addToWorkspace);
|
||||
}
|
||||
|
||||
const result = await window.showInformationMessage(message, ...choices);
|
||||
|
||||
const openFolder = result === open;
|
||||
/* __GDPR__
|
||||
@@ -396,8 +405,13 @@ export class CommandCenter {
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'success' }, { openFolder: openFolder ? 1 : 0 });
|
||||
|
||||
const uri = Uri.file(repositoryPath);
|
||||
|
||||
if (openFolder) {
|
||||
commands.executeCommand('vscode.openFolder', Uri.file(repositoryPath));
|
||||
commands.executeCommand('vscode.openFolder', uri);
|
||||
} else if (result === addToWorkspace) {
|
||||
workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri });
|
||||
}
|
||||
} catch (err) {
|
||||
if (/already exists and is not an empty directory/.test(err && err.stderr || '')) {
|
||||
@@ -419,9 +433,6 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
throw err;
|
||||
} finally {
|
||||
commandDisposable.dispose();
|
||||
statusBarItem.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,7 +1216,7 @@ export class CommandCenter {
|
||||
|
||||
const message = localize('confirm force delete branch', "The branch '{0}' is not fully merged. Delete anyway?", name);
|
||||
const yes = localize('delete branch', "Delete Branch");
|
||||
const pick = await window.showWarningMessage(message, yes);
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes);
|
||||
|
||||
if (pick === yes) {
|
||||
await run(true);
|
||||
@@ -1333,7 +1344,7 @@ export class CommandCenter {
|
||||
|
||||
const remoteCharCnt = remotePick.label.length;
|
||||
|
||||
repository.pull(false, remotePick.label, branchPick.label.slice(remoteCharCnt + 1));
|
||||
repository.pullFrom(false, remotePick.label, branchPick.label.slice(remoteCharCnt + 1));
|
||||
}
|
||||
|
||||
@command('git.pull', { repository: true })
|
||||
@@ -1345,7 +1356,7 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.pull();
|
||||
await repository.pull(repository.HEAD);
|
||||
}
|
||||
|
||||
@command('git.pullRebase', { repository: true })
|
||||
@@ -1357,7 +1368,7 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.pullWithRebase();
|
||||
await repository.pullWithRebase(repository.HEAD);
|
||||
}
|
||||
|
||||
@command('git.push', { repository: true })
|
||||
@@ -1375,7 +1386,7 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
try {
|
||||
await repository.push();
|
||||
await repository.push(repository.HEAD);
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode !== GitErrorCodes.NoUpstreamBranch) {
|
||||
throw err;
|
||||
@@ -1443,7 +1454,7 @@ export class CommandCenter {
|
||||
const shouldPrompt = config.get<boolean>('confirmSync') === true;
|
||||
|
||||
if (shouldPrompt) {
|
||||
const message = localize('sync is unpredictable', "This action will push and pull commits to and from '{0}'.", HEAD.upstream);
|
||||
const message = localize('sync is unpredictable', "This action will push and pull commits to and from '{0}/{1}'.", HEAD.upstream.remote, HEAD.upstream.name);
|
||||
const yes = localize('ok', "OK");
|
||||
const neverAgain = localize('never again', "OK, Don't Show Again");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes, neverAgain);
|
||||
@@ -1456,9 +1467,9 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
if (rebase) {
|
||||
await repository.syncRebase();
|
||||
await repository.syncRebase(HEAD);
|
||||
} else {
|
||||
await repository.sync();
|
||||
await repository.sync(HEAD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1476,7 +1487,7 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.sync();
|
||||
await repository.sync(HEAD);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1635,6 +1646,10 @@ export class CommandCenter {
|
||||
this.telemetryReporter.sendTelemetryEvent('git.command', { command: id });
|
||||
|
||||
return result.catch(async err => {
|
||||
const options: MessageOptions = {
|
||||
modal: err.gitErrorCode === GitErrorCodes.DirtyWorkTree
|
||||
};
|
||||
|
||||
let message: string;
|
||||
|
||||
switch (err.gitErrorCode) {
|
||||
@@ -1664,9 +1679,11 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
options.modal = true;
|
||||
|
||||
const outputChannel = this.outputChannel as OutputChannel;
|
||||
const openOutputChannelChoice = localize('open git log', "Open Git Log");
|
||||
const choice = await window.showErrorMessage(message, openOutputChannelChoice);
|
||||
const choice = await window.showErrorMessage(message, options, openOutputChannelChoice);
|
||||
|
||||
if (choice === openOutputChannelChoice) {
|
||||
outputChannel.show();
|
||||
|
||||
81
extensions/git/src/encoding.ts
Normal file
81
extensions/git/src/encoding.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as jschardet from 'jschardet';
|
||||
|
||||
jschardet.Constants.MINIMUM_THRESHOLD = 0.2;
|
||||
|
||||
function detectEncodingByBOM(buffer: NodeBuffer): string | null {
|
||||
if (!buffer || buffer.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const b0 = buffer.readUInt8(0);
|
||||
const b1 = buffer.readUInt8(1);
|
||||
|
||||
// UTF-16 BE
|
||||
if (b0 === 0xFE && b1 === 0xFF) {
|
||||
return 'utf16be';
|
||||
}
|
||||
|
||||
// UTF-16 LE
|
||||
if (b0 === 0xFF && b1 === 0xFE) {
|
||||
return 'utf16le';
|
||||
}
|
||||
|
||||
if (buffer.length < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const b2 = buffer.readUInt8(2);
|
||||
|
||||
// UTF-8
|
||||
if (b0 === 0xEF && b1 === 0xBB && b2 === 0xBF) {
|
||||
return 'utf8';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const IGNORE_ENCODINGS = [
|
||||
'ascii',
|
||||
'utf-8',
|
||||
'utf-16',
|
||||
'utf-32'
|
||||
];
|
||||
|
||||
const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
|
||||
'ibm866': 'cp866',
|
||||
'big5': 'cp950'
|
||||
};
|
||||
|
||||
export function detectEncoding(buffer: Buffer): string | null {
|
||||
let result = detectEncodingByBOM(buffer);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const detected = jschardet.detect(buffer);
|
||||
|
||||
if (!detected || !detected.encoding) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const encoding = detected.encoding;
|
||||
|
||||
// Ignore encodings that cannot guess correctly
|
||||
// (http://chardet.readthedocs.io/en/latest/supported-encodings.html)
|
||||
if (0 <= IGNORE_ENCODINGS.indexOf(encoding.toLowerCase())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedEncodingName = encoding.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
|
||||
const mapped = JSCHARDET_TO_ICONV_ENCODINGS[normalizedEncodingName];
|
||||
|
||||
return mapped || normalizedEncodingName;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import iconv = require('iconv-lite');
|
||||
import * as filetype from 'file-type';
|
||||
import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util';
|
||||
import { CancellationToken } from 'vscode';
|
||||
import { detectEncoding } from './encoding';
|
||||
|
||||
const readfile = denodeify<string, string | null, string>(fs.readFile);
|
||||
|
||||
@@ -53,8 +54,13 @@ export interface Ref {
|
||||
remote?: string;
|
||||
}
|
||||
|
||||
export interface UpstreamRef {
|
||||
remote: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Branch extends Ref {
|
||||
upstream?: string;
|
||||
upstream?: UpstreamRef;
|
||||
ahead?: number;
|
||||
behind?: number;
|
||||
}
|
||||
@@ -361,14 +367,14 @@ function getGitErrorCode(stderr: string): string | undefined {
|
||||
|
||||
export class Git {
|
||||
|
||||
private gitPath: string;
|
||||
readonly path: string;
|
||||
private env: any;
|
||||
|
||||
private _onOutput = new EventEmitter();
|
||||
get onOutput(): EventEmitter { return this._onOutput; }
|
||||
|
||||
constructor(options: IGitOptions) {
|
||||
this.gitPath = options.gitPath;
|
||||
this.path = options.gitPath;
|
||||
this.env = options.env || {};
|
||||
}
|
||||
|
||||
@@ -382,11 +388,29 @@ export class Git {
|
||||
}
|
||||
|
||||
async clone(url: string, parentPath: string, cancellationToken?: CancellationToken): Promise<string> {
|
||||
const folderName = decodeURI(url).replace(/^.*\//, '').replace(/\.git$/, '') || 'repository';
|
||||
const folderPath = path.join(parentPath, folderName);
|
||||
let baseFolderName = decodeURI(url).replace(/^.*\//, '').replace(/\.git$/, '') || 'repository';
|
||||
let folderName = baseFolderName;
|
||||
let folderPath = path.join(parentPath, folderName);
|
||||
let count = 1;
|
||||
|
||||
while (count < 20 && await new Promise(c => fs.exists(folderPath, c))) {
|
||||
folderName = `${baseFolderName}-${count++}`;
|
||||
folderPath = path.join(parentPath, folderName);
|
||||
}
|
||||
|
||||
await mkdirp(parentPath);
|
||||
await this.exec(parentPath, ['clone', url, folderPath], { cancellationToken });
|
||||
|
||||
try {
|
||||
await this.exec(parentPath, ['clone', url, folderPath], { cancellationToken });
|
||||
} catch (err) {
|
||||
if (err.stderr) {
|
||||
err.stderr = err.stderr.replace(/^Cloning.+$/m, '').trim();
|
||||
err.stderr = err.stderr.replace(/^ERROR:\s+/, '').trim();
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
@@ -442,7 +466,7 @@ export class Git {
|
||||
}
|
||||
|
||||
spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess {
|
||||
if (!this.gitPath) {
|
||||
if (!this.path) {
|
||||
throw new Error('git could not be found in the system.');
|
||||
}
|
||||
|
||||
@@ -464,7 +488,7 @@ export class Git {
|
||||
this.log(`> git ${args.join(' ')}\n`);
|
||||
}
|
||||
|
||||
return cp.spawn(this.gitPath, args, options);
|
||||
return cp.spawn(this.path, args, options);
|
||||
}
|
||||
|
||||
private log(output: string): void {
|
||||
@@ -654,9 +678,16 @@ export class Repository {
|
||||
return result.stdout;
|
||||
}
|
||||
|
||||
async bufferString(object: string, encoding: string = 'utf8'): Promise<string> {
|
||||
async bufferString(object: string, encoding: string = 'utf8', autoGuessEncoding = false): Promise<string> {
|
||||
const stdout = await this.buffer(object);
|
||||
return iconv.decode(stdout, iconv.encodingExists(encoding) ? encoding : 'utf8');
|
||||
|
||||
if (autoGuessEncoding) {
|
||||
encoding = detectEncoding(stdout) || encoding;
|
||||
}
|
||||
|
||||
encoding = iconv.encodingExists(encoding) ? encoding : 'utf8';
|
||||
|
||||
return iconv.decode(stdout, encoding);
|
||||
}
|
||||
|
||||
async buffer(object: string): Promise<Buffer> {
|
||||
@@ -988,7 +1019,7 @@ export class Repository {
|
||||
}
|
||||
|
||||
async pull(rebase?: boolean, remote?: string, branch?: string): Promise<void> {
|
||||
const args = ['pull'];
|
||||
const args = ['pull', '--tags'];
|
||||
|
||||
if (rebase) {
|
||||
args.push('-r');
|
||||
@@ -1008,7 +1039,8 @@ export class Repository {
|
||||
err.gitErrorCode = GitErrorCodes.NoUserNameConfigured;
|
||||
} else if (/Could not read from remote repository/.test(err.stderr || '')) {
|
||||
err.gitErrorCode = GitErrorCodes.RemoteConnectionError;
|
||||
} else if (/Pull is not possible because you have unmerged files|Cannot pull with rebase: You have unstaged changes|Your local changes to the following files would be overwritten|Please, commit your changes before you can merge/.test(err.stderr)) {
|
||||
} else if (/Pull is not possible because you have unmerged files|Cannot pull with rebase: You have unstaged changes|Your local changes to the following files would be overwritten|Please, commit your changes before you can merge/i.test(err.stderr)) {
|
||||
err.stderr = err.stderr.replace(/Cannot pull with rebase: You have unstaged changes/i, 'Cannot pull with rebase, you have unstaged changes');
|
||||
err.gitErrorCode = GitErrorCodes.DirtyWorkTree;
|
||||
}
|
||||
|
||||
@@ -1218,10 +1250,16 @@ export class Repository {
|
||||
const commit = result.stdout.trim();
|
||||
|
||||
try {
|
||||
const res2 = await this.run(['rev-parse', '--symbolic-full-name', '--abbrev-ref', name + '@{u}']);
|
||||
const upstream = res2.stdout.trim();
|
||||
const res2 = await this.run(['rev-parse', '--symbolic-full-name', name + '@{u}']);
|
||||
const fullUpstream = res2.stdout.trim();
|
||||
const match = /^refs\/remotes\/([^/]+)\/(.+)$/.exec(fullUpstream);
|
||||
|
||||
const res3 = await this.run(['rev-list', '--left-right', name + '...' + upstream]);
|
||||
if (!match) {
|
||||
throw new Error(`Could not parse upstream branch: ${fullUpstream}`);
|
||||
}
|
||||
|
||||
const upstream = { remote: match[1], name: match[2] };
|
||||
const res3 = await this.run(['rev-list', '--left-right', name + '...' + fullUpstream]);
|
||||
|
||||
let ahead = 0, behind = 0;
|
||||
let i = 0;
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Askpass } from './askpass';
|
||||
import { toDisposable, filterEvent, eventToPromise } from './util';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import { API, createApi } from './api';
|
||||
import { GitProtocolHandler } from './protocolHandler';
|
||||
|
||||
let telemetryReporter: TelemetryReporter;
|
||||
|
||||
@@ -51,7 +52,8 @@ async function init(context: ExtensionContext, outputChannel: OutputChannel, dis
|
||||
disposables.push(
|
||||
new CommandCenter(git, model, outputChannel, telemetryReporter),
|
||||
new GitContentProvider(model),
|
||||
new GitDecorations(model)
|
||||
new GitDecorations(model),
|
||||
new GitProtocolHandler()
|
||||
);
|
||||
|
||||
await checkGitVersion(info);
|
||||
|
||||
@@ -66,7 +66,7 @@ export class Model {
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(private git: Git, private globalState: Memento, private outputChannel: OutputChannel) {
|
||||
constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) {
|
||||
workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables);
|
||||
this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] });
|
||||
|
||||
@@ -227,14 +227,17 @@ export class Model {
|
||||
const changeListener = repository.onDidChangeRepository(uri => this._onDidChangeRepository.fire({ repository, uri }));
|
||||
const originalResourceChangeListener = repository.onDidChangeOriginalResource(uri => this._onDidChangeOriginalResource.fire({ repository, uri }));
|
||||
|
||||
const submodulesLimit = workspace
|
||||
.getConfiguration('git', Uri.file(repository.root))
|
||||
.get<number>('detectSubmodulesLimit') as number;
|
||||
|
||||
const checkForSubmodules = () => {
|
||||
if (repository.submodules.length > 10) {
|
||||
if (repository.submodules.length > submodulesLimit) {
|
||||
window.showWarningMessage(localize('too many submodules', "The '{0}' repository has {1} submodules which won't be opened automatically. You can still open each one individually by opening a file within.", path.basename(repository.root), repository.submodules.length));
|
||||
statusListener.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
this.scanSubmodules(repository);
|
||||
this.scanSubmodules(repository, submodulesLimit);
|
||||
};
|
||||
|
||||
const statusListener = repository.onDidRunGitStatus(checkForSubmodules);
|
||||
@@ -256,7 +259,7 @@ export class Model {
|
||||
this._onDidOpenRepository.fire(repository);
|
||||
}
|
||||
|
||||
private scanSubmodules(repository: Repository): void {
|
||||
private scanSubmodules(repository: Repository, limit: number): void {
|
||||
const shouldScanSubmodules = workspace
|
||||
.getConfiguration('git', Uri.file(repository.root))
|
||||
.get<boolean>('detectSubmodules') === true;
|
||||
@@ -266,6 +269,7 @@ export class Model {
|
||||
}
|
||||
|
||||
repository.submodules
|
||||
.slice(0, limit)
|
||||
.map(r => path.join(repository.root, r.path))
|
||||
.forEach(p => this.eventuallyScanPossibleGitRepository(p));
|
||||
}
|
||||
|
||||
39
extensions/git/src/protocolHandler.ts
Normal file
39
extensions/git/src/protocolHandler.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { ProtocolHandler, Uri, window, Disposable, commands } from 'vscode';
|
||||
import { dispose } from './util';
|
||||
import * as querystring from 'querystring';
|
||||
|
||||
export class GitProtocolHandler implements ProtocolHandler {
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor() {
|
||||
this.disposables.push(window.registerProtocolHandler(this));
|
||||
}
|
||||
|
||||
handleUri(uri: Uri): void {
|
||||
switch (uri.path) {
|
||||
case '/clone': this.clone(uri);
|
||||
}
|
||||
}
|
||||
|
||||
private clone(uri: Uri): void {
|
||||
const data = querystring.parse(uri.query);
|
||||
|
||||
if (!data.url) {
|
||||
console.warn('Failed to open URI:', uri);
|
||||
}
|
||||
|
||||
commands.executeCommand('git.clone', data.url);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
@@ -728,24 +728,48 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
@throttle
|
||||
async pullWithRebase(): Promise<void> {
|
||||
await this.run(Operation.Pull, () => this.repository.pull(true));
|
||||
async pullWithRebase(head: Branch | undefined): Promise<void> {
|
||||
let remote: string | undefined;
|
||||
let branch: string | undefined;
|
||||
|
||||
if (head && head.name && head.upstream) {
|
||||
remote = head.upstream.remote;
|
||||
branch = `${head.upstream.name}`;
|
||||
}
|
||||
|
||||
await this.run(Operation.Pull, () => this.repository.pull(true, remote, branch));
|
||||
}
|
||||
|
||||
@throttle
|
||||
async pull(rebase?: boolean, remote?: string, name?: string): Promise<void> {
|
||||
await this.run(Operation.Pull, () => this.repository.pull(rebase, remote, name));
|
||||
}
|
||||
async pull(head: Branch | undefined): Promise<void> {
|
||||
let remote: string | undefined;
|
||||
let branch: string | undefined;
|
||||
|
||||
@throttle
|
||||
async push(): Promise<void> {
|
||||
await this.run(Operation.Push, () => this.repository.push());
|
||||
if (head && head.name && head.upstream) {
|
||||
remote = head.upstream.remote;
|
||||
branch = `${head.upstream.name}`;
|
||||
}
|
||||
|
||||
await this.run(Operation.Pull, () => this.repository.pull(false, remote, branch));
|
||||
}
|
||||
|
||||
async pullFrom(rebase?: boolean, remote?: string, branch?: string): Promise<void> {
|
||||
await this.run(Operation.Pull, () => this.repository.pull(rebase, remote, branch));
|
||||
}
|
||||
|
||||
@throttle
|
||||
async push(head: Branch): Promise<void> {
|
||||
let remote: string | undefined;
|
||||
let branch: string | undefined;
|
||||
|
||||
if (head && head.name && head.upstream) {
|
||||
remote = head.upstream.remote;
|
||||
branch = `${head.name}:${head.upstream.name}`;
|
||||
}
|
||||
|
||||
await this.run(Operation.Push, () => this.repository.push(remote, branch));
|
||||
}
|
||||
|
||||
async pushTo(remote?: string, name?: string, setUpstream: boolean = false): Promise<void> {
|
||||
await this.run(Operation.Push, () => this.repository.push(remote, name, setUpstream));
|
||||
}
|
||||
@@ -754,47 +778,53 @@ export class Repository implements Disposable {
|
||||
await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true));
|
||||
}
|
||||
|
||||
private async _sync(rebase: boolean): Promise<void> {
|
||||
@throttle
|
||||
sync(head: Branch): Promise<void> {
|
||||
return this._sync(head, false);
|
||||
}
|
||||
|
||||
@throttle
|
||||
async syncRebase(head: Branch): Promise<void> {
|
||||
return this._sync(head, true);
|
||||
}
|
||||
|
||||
private async _sync(head: Branch, rebase: boolean): Promise<void> {
|
||||
let remote: string | undefined;
|
||||
let pullBranch: string | undefined;
|
||||
let pushBranch: string | undefined;
|
||||
|
||||
if (head.name && head.upstream) {
|
||||
remote = head.upstream.remote;
|
||||
pullBranch = `${head.upstream.name}`;
|
||||
pushBranch = `${head.name}:${head.upstream.name}`;
|
||||
}
|
||||
|
||||
await this.run(Operation.Sync, async () => {
|
||||
await this.repository.pull(rebase);
|
||||
await this.repository.pull(rebase, remote, pullBranch);
|
||||
|
||||
const shouldPush = this.HEAD && typeof this.HEAD.ahead === 'number' ? this.HEAD.ahead > 0 : true;
|
||||
|
||||
if (shouldPush) {
|
||||
await this.repository.push();
|
||||
await this.repository.push(remote, pushBranch);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@throttle
|
||||
sync(): Promise<void> {
|
||||
return this._sync(false);
|
||||
}
|
||||
|
||||
@throttle
|
||||
async syncRebase(): Promise<void> {
|
||||
return this._sync(true);
|
||||
}
|
||||
|
||||
async show(ref: string, filePath: string): Promise<string> {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
return this.run(Operation.Show, () => {
|
||||
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
const encoding = configFiles.get<string>('encoding');
|
||||
const defaultEncoding = configFiles.get<string>('encoding');
|
||||
const autoGuessEncoding = configFiles.get<boolean>('autoGuessEncoding');
|
||||
|
||||
// TODO@joao: Resource config api
|
||||
return await this.repository.bufferString(`${ref}:${relativePath}`, encoding);
|
||||
return this.repository.bufferString(`${ref}:${relativePath}`, defaultEncoding, autoGuessEncoding);
|
||||
});
|
||||
}
|
||||
|
||||
async buffer(ref: string, filePath: string): Promise<Buffer> {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
return this.run(Operation.Show, () => {
|
||||
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
// const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
// const encoding = configFiles.get<string>('encoding');
|
||||
|
||||
// TODO@joao: REsource config api
|
||||
return await this.repository.buffer(`${ref}:${relativePath}`);
|
||||
return this.repository.buffer(`${ref}:${relativePath}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user