Compare commits

...

144 Commits

Author SHA1 Message Date
Karl Burtram
1c48320ce0 Bump Tools Service to 1.4.0-alpha.30 (#1337) 2018-05-02 19:59:55 -07:00
Aditya Bist
96ecf79d32 resize when window resized (#1335) 2018-05-02 17:02:24 -07:00
Leila Lali
6d243e0ac8 reverting row which escape is clicked and fixed the issue with reverting rows (#1333)
* reverting row which escape is clicked and fixed the issue with reverting row
2018-05-02 15:57:15 -07:00
Abbie Petchtes
8bf60f133f Fix widget title in home tab (#1325) 2018-05-02 12:24:22 -07:00
Matt Irvine
3b9a3aba87 Close insights dialog properly when escape is pressed (#1319) 2018-05-02 11:43:41 -07:00
Karl Burtram
f0c986858a Update Tools Service to 1.4.0-alpha.29 (#1323) 2018-05-02 11:42:02 -07:00
Karl Burtram
7ee13b4afb Integrate resources from Community Localization platform (#1313) 2018-05-02 11:17:29 -07:00
Karl Burtram
bca4102542 Bump SQL Ops to 0.29.2 (#1318) 2018-05-02 10:18:26 -07:00
Anthony Dresser
31ac8d6acc Trim server name (#1308)
* add warning for trimming of the servername and trim the servername before connection

* move the location of the trim

* move it back to simplify tests
2018-05-02 10:16:05 -07:00
Anthony Dresser
e82b7615b3 Add more options to chart viewer (#1307)
* fixing up chart viewer

* formatting

* everything is working

* removed unnecessary code

* removed unneeded code
2018-05-02 10:15:51 -07:00
Aditya Bist
6f10f7a21a Agent Improvements/Fixes (#1284)
* fixed UI bugs and increased jobs history page perf

* cached full error message

* load histories for jobs with errors first

* cr comments
2018-05-01 17:42:11 -07:00
Aditya Bist
46fb68214f added taskbar instead of custom action bar (#1288)
* added taskbar instead of custom action bar

* set actions buttons based on context

* cr comments
2018-05-01 17:19:54 -07:00
Matt Irvine
c2381424bc Combine messages to reduce rendering time when possible (#1309) 2018-05-01 15:23:41 -07:00
Abbie Petchtes
31328e79be clear the widget error every time it refreshes (#1306)
* clear the widget error every time it refreshes

* address comments
2018-05-01 15:00:19 -07:00
Matt Irvine
96657e300a Open inactive editors as sql editors when needed (#1298) 2018-05-01 10:59:39 -07:00
Leila Lali
a2e6aa9e64 fixed extension filter and search (#1301)
* fixed extension filter and search
2018-05-01 08:52:20 -07:00
Karl Burtram
8c2d79e9cf Update SQL Tools to 1.4.0-alpha.25 (#1304) 2018-04-30 22:48:17 -07:00
Matt Irvine
cd140b5527 Encode HTML when entered in edit data cells (#1302)
* Encode HTML when entered in edit data cells

* Use VS Code's string encoding function
2018-04-30 17:58:39 -07:00
Karl Burtram
a0456bf4f7 Remove all ID fields from telemetry (#1299)
* Remove all ID fields from telemetry

* Fix how some of the fields are blanked out

* Add back blank userId

* Disable VS Code tests broken by this change
2018-04-30 16:52:54 -07:00
Karl Burtram
55e3947cf7 Pick up Electron 1.7.12 (#1291)
* Pick up Electron 1.7.12

* Might as well go to 1.7.13

* Go back to 1.7.12 to match VS Code
2018-04-30 09:18:02 -07:00
Karl Burtram
db5156e4cd Fix app name in Report Issue dialog (#1292) 2018-04-29 13:19:09 -07:00
Leila Lali
eece0677a7 added libunwind8 to Debian dependencies (#1290)
* added libunwind8 to debian depedencies
2018-04-27 17:08:26 -07:00
Matt Irvine
24e8c20511 Simplify button logic and enable button updates for custom dialogs (#1283) 2018-04-27 16:29:18 -07:00
Leila Lali
886717d330 added dropdown and form layout to model view (#1269)
* added dropdown and form layout to model view
2018-04-27 15:43:23 -07:00
Kevin Cunnane
26b27a616a Refreshing package-lock for samples since it's stale (#1287) 2018-04-27 10:19:11 -07:00
Karl Burtram
0c663e5555 Add AppInsights context flag to envelope (#1282)
* Add AppInsights context flag to envelope

* Fix typo

* Use add processor instead of patching
2018-04-26 21:26:51 -07:00
Aditya Bist
0f087915f6 Agent/loading icon (#1263)
* added progress wheel to show jobs loading

* added loading wheel to jobs view page too
2018-04-26 15:01:23 -07:00
Anthony Dresser
a78fa9c0f2 Scroll properties (#1244)
* properties isn't scrolling

* working on edge cases

* formatting

* formatting

* formatting
2018-04-26 14:10:08 -07:00
Karl Burtram
b1752ea635 Show all available extensions in Extension Manager (#1273)
* Show all available extensions in Extension Manager

* Change name of functions

* Minor cleanup
2018-04-26 10:08:02 -07:00
Matt Irvine
ec150917c2 Fix button handle bug and add tests (#1267) 2018-04-25 16:22:54 -07:00
Karl Burtram
7a9a69c439 Add TRUNCATE to the keyword colorization list (#1270)
* Add TRUNCATE to the keyword colorization list

* Add DISTINCT to keyword list
2018-04-25 16:07:46 -07:00
Aditya Bist
9e9862c6f0 Agent action icons fix (#1255)
* change icon opacity based on job status

* rid of magic numbers
2018-04-25 12:20:46 -07:00
Karl Burtram
7b76d929cd Update README and CHANGELOG for April release (#1257) 2018-04-24 22:39:01 -07:00
Matt Irvine
1811dfa423 Expose custom dialog extension APIs (#1206) 2018-04-24 16:43:14 -07:00
Karl Burtram
3abbc8fd97 Bump SQL Ops Studio to 0.28.6 (#1252) 2018-04-24 13:58:09 -07:00
Abbie Petchtes
4b88b67bed update Server Reports README (#1250) 2018-04-24 13:49:56 -07:00
Aditya Bist
a2734807ca Agent bugs and fixes (#1243)
* show Error for temp placeholder

* changed message to loading error

* changed error message when loading

* localized error msg

* localized error message
2018-04-24 13:34:17 -07:00
Abbie Petchtes
d0d4df313e Initial improvement in sp_whoisactive (#1249)
* improve sp_whoisactive extension

* formatting

* use a grouping prefix for extension commands
2018-04-24 13:09:50 -07:00
Abbie Petchtes
1efd5e6502 change keyboard shortcut for focusOnCurrentQuery (#1241) 2018-04-24 13:09:32 -07:00
Abbie Petchtes
b12cac0ac3 Changed DB Space Usage and DB Buffer Usage to show only top 10 data and update README (#1248) 2018-04-24 13:09:13 -07:00
Aditya Bist
578aa6ccd2 removed test code 2018-04-24 11:04:09 -07:00
Aditya Bist
3b90530717 Feature/agent finishes (#1237)
* added icons for steps and fixed bugs in jobs view page

* put svgs in common folder

* added steps header logo

* added full path for import

* changed codes to text

* removed cat id, changed bools to yes/no and fixed steps theme

* localized the strings

* set the jobs table column widths

* added indicators for failure, unknown and canceled jobs in jobs view

* fixed jobs panel style and jobs view scrolling

* fixed jobs view page styling

* fixed job history tree size rows

* made error messages copy-able

* made job history tree work with keyboard

* fixed previous runs header

* added space between date and status in job history list

* fixed history list min width and set scrolling for jobs history page

* added scrolling when app is resized

* added scrollbars and tooltip for name

* added error handling, tab handling and other issues
2018-04-23 18:34:53 -07:00
Karl Burtram
f199c7a63c Fix instance of "Code" in git fetch user prompt (#1234) 2018-04-23 17:42:12 -07:00
Karl Burtram
50a2526d1f Only show SQL Agent for on-prem instances (#1233) 2018-04-23 17:41:46 -07:00
Anthony Dresser
7fb8a28b59 properties isn't scrolling (#1225) 2018-04-23 17:41:24 -07:00
Matt Irvine
30a825438e Fix issue where chart type select is missing for tables (#1232) 2018-04-23 17:13:58 -07:00
Matt Irvine
f63da13210 Handle errors when chart is invalid for given data (#1226) 2018-04-23 16:38:18 -07:00
Matt Irvine
08d73675d4 Fix bar chart displaying extra series (#1230) 2018-04-23 16:11:44 -07:00
Leila Lali
f0f6c00a0e Updated extension gallery link to Azure blob storage (#1220) 2018-04-23 15:44:30 -07:00
Abbie Petchtes
965458ca74 Add Query Editor API to sqlops.proposed (#1196)
* add support query editor API

* remove sqlops.proposed.d.ts in sp_whoIsActive

* address comments

* add catch error when connect
2018-04-23 13:42:27 -07:00
Karl Burtram
b30f7ee41c Add Redgate Search to recommended extensions list (#1212) 2018-04-23 13:27:03 -07:00
Abbie Petchtes
a2eb53ce0b add theming for selectbox in edit data (#1210) 2018-04-23 12:56:30 -07:00
Kevin Cunnane
619c816e7f Fix flex container and card layout issues (#1195)
* Fix main layout issues and add box around card
- Need to improve box size as it's taking too much space

* Fix UI issues with flexContainer and cards

* Simplify card HTML
2018-04-23 09:54:44 -07:00
Karl Burtram
3d6fb7a8fa Update SQL Tools Service to 1.4.0-alpha.23 (#1202) 2018-04-22 22:26:30 -07:00
Kevin Cunnane
891624c085 Fix #1198 Extension gallery doesn't show dashboard contributions in Contributions tab (#1200)
- Showing dashboard.tabs and dashboard.insights in Contributions
- Decided not to show dashboard.containers for now since these are logically just parts of the tabs, and dont' have user-facing benefit.
2018-04-22 17:42:44 -07:00
Leila Lali
a7c4686980 Feature/input box component (#1190)
* Adding new view component for input box
2018-04-20 16:26:58 -07:00
Matt Irvine
93aa052856 Initial work for custom model view dialogs (#1183) 2018-04-19 16:24:02 -07:00
Anthony Dresser
61d05f6782 adds coloring for unfocused tables (#1182) 2018-04-19 12:22:37 -07:00
Anthony Dresser
60ccae48f1 add auto refresh interval to insights (#1173) 2018-04-19 11:10:44 -07:00
Abbie Petchtes
4b454581fd fix task icon in dashboard (#1174) 2018-04-18 15:49:46 -07:00
Anthony Dresser
f0aadebd2c fix chart viewer accessibility (#1164) 2018-04-18 13:44:33 -07:00
Leila Lali
d3f0ac7954 refactor model components to not reference any dashboard services (#1168)
* refactor model components to not reference any dashboard services
2018-04-18 11:48:20 -07:00
Aditya Bist
134f76c17f Feature/agent finishes (#1149)
* added icons for steps and fixed bugs in jobs view page

* put svgs in common folder

* added steps header logo

* added full path for import

* changed codes to text

* removed cat id, changed bools to yes/no and fixed steps theme

* localized the strings

* set the jobs table column widths

* added indicators for failure, unknown and canceled jobs in jobs view

* fixed jobs panel style and jobs view scrolling

* fixed jobs view page styling

* fixed job history tree size rows

* made error messages copy-able

* made job history tree work with keyboard
2018-04-17 16:45:22 -07:00
Karl Burtram
b9c877a109 Add a "Telemetry Opt-Out" menu item (#1172) 2018-04-17 14:15:56 -07:00
Kevin Cunnane
aa243a8aae ensure npm install copies typings (#1170)
- Important so that build of the extension "works" as expected
2018-04-17 13:48:35 -07:00
Abbie Petchtes
e5c1c6f544 fix regression in insight widget where the data is set twice (#1163) 2018-04-17 11:06:40 -07:00
Anthony Dresser
9e9f85079e fix up backup dialog for accessibility (#1155) 2018-04-16 17:30:11 -07:00
Abbie Petchtes
ae8e2e1f89 Add showTopNData option to insight charts (#1157)
* add showTopNData option to insight charts

* address comments

* fix the label in the widget when label first column is set
2018-04-16 14:30:24 -07:00
Kevin Cunnane
b2c70e9301 Feat/model backed ui (#1145)
This is an initial PR for a new model-driven UI where extensions can provide definitions of the components & how they're laid out using Containers.
#1140, #1141, #1142, #1143 and #1144 are all tracking additional work needed to improve the initial implementation and fix some issues with the implementation.

Features:
- Supports defining a FlexContainer that maps to a flexbox-based layout.
- Supports creating a card component, which is a key-value pair based control that will lay out simple information to a user. Eventually this will have an optional set of actions associated with it.
- Has a sample project which shows how to use the API and was used for verification
2018-04-13 15:59:18 -07:00
Anthony Dresser
e022f4a0d1 add title to back button (#1154) 2018-04-13 15:07:09 -07:00
Anthony Dresser
8bc32e6371 add accessibility for panel (#1138) 2018-04-13 12:09:36 -07:00
Anthony Dresser
f739c47984 Adds aria labels to all input ui (#1136)
* adds aria-label to inputs for connection

* formatting

* add ariaLabels to all checkboxes/inputboxes/dropdowns
2018-04-13 12:09:25 -07:00
Abbie Petchtes
13fb9fdfd2 Add keyboard shortcuts for focus on current query and go to next output query tab (#1153)
* add go to next output query tab shotcut

* add a new keyboard shortcut for focus on current query

* minor change
2018-04-13 11:11:25 -07:00
Abbie Petchtes
9a5f51bfbf Focus on the first focus-able when toggle result and message (#1147)
* when focus on the first focusable when toggle result and message

* minor change
2018-04-12 17:26:49 -07:00
Karl Burtram
06bab6a38c Add Privacy Statement and License menu items (#1148)
* Add Privacy Statement and License menu items

* Fix spaces
2018-04-12 17:24:21 -07:00
Karl Burtram
c35a14d8fd Fix incorrect source header from previous commit (#1146) 2018-04-12 15:25:23 -07:00
Karl Burtram
b914073147 Add missing double-quotes to insights schema description (#1139) 2018-04-12 15:00:47 -07:00
ChrisSun-ms
04ae18143b fix backup URI (#1137) 2018-04-12 13:13:05 -07:00
Anthony Dresser
efe8e81b6e Connection inputs labels (#1129)
* adds aria-label to inputs for connection

* formatting
2018-04-12 11:29:16 -07:00
Anthony Dresser
c33ddfabf9 add necessary attributes for accessibility on the results grid panes (#1126) 2018-04-12 11:29:02 -07:00
Aditya Bist
8ec5451e64 Feature/agent2 adbist (#1113)
* added caching for jobs view and history page

* added build fix

* removed agent from cache service name

* put cache in job mgmt service and fixed view destroy error

* jobs view cache and refresh implemented

* refresh and cache complete

* added refresh to job history page

* fixed steps style

* explicitly tell user when no steps are available

* show message when no prev runs available

* code review refactor

* cleaned code

* added code that got left out
2018-04-12 10:36:34 -07:00
Karl Burtram
20853ddf7e Bump SQL Ops to 0.28.4 (#1134) 2018-04-11 17:07:36 -07:00
Abbie Petchtes
091d4cb924 enable keyboard for explain button and Line1 link in message pane (#1132) 2018-04-11 16:50:41 -07:00
Karl Burtram
cd0210c88a Port VS Code telemetry opt-in dialog (#1130) 2018-04-11 15:47:34 -07:00
Anthony Dresser
ed10f984b6 refactored collapsing widget, fixed refreshing a collapsed widget (#1107) 2018-04-11 14:39:23 -07:00
Karl Burtram
087a6a0810 Bump SQL Ops to 0.28.3 (#1125) 2018-04-11 13:27:05 -07:00
Abbie Petchtes
495b4ee7c2 fix all high constrast issues in sqlops (#1115) 2018-04-11 12:36:00 -07:00
Leila Lali
7833c28b7a fixed the bug with using vs code url to download manually (#1108) 2018-04-11 11:59:56 -07:00
Abbie Petchtes
bbfb68b082 fix the keyboard issue where table is empty (#1110) 2018-04-10 16:09:18 -07:00
Matt Irvine
b32e7a777c Bump tools service for node path change (#1114) 2018-04-10 15:53:06 -07:00
Anthony Dresser
a327889d05 Fix Dashboard Errors (#1106)
* fix ordering of component instance calls to fix erros

* add more verification methods
2018-04-10 13:46:07 -07:00
Abbie Petchtes
5ac89e5a49 Open query plan link when select XML showplan in the result grid (#1092)
* open query plan link

* address comments
2018-04-09 10:27:32 -07:00
Kevin Cunnane
849653927a Fix #1095 "Run kinit" helper no longer runs kinit (#1102)
VSCode refactored their terminal to have more delayed initialization,
but still return as complete before the actual instance is ready for focus
and paste events. The fix is to add a delay so this can complete before
calling the paste action. As this doesn't affect extensions (the hop to the
extension host causes a delay) I'm not raising this with VSCode as an
upstream issue, just fixing on our side
2018-04-07 13:16:05 -07:00
Matt Irvine
3545483fc1 Update action collapsed state with emitter (#1099) 2018-04-06 17:58:27 -07:00
Matt Irvine
e5a1896414 Clear connection validation messages on open (#1097) 2018-04-06 15:55:14 -07:00
Anthony Dresser
bec8e72688 fix problems with low result count breaking insights (#1052) 2018-04-06 15:54:43 -07:00
Anthony Dresser
86748e6d69 clear insights view before showing error (#1050) 2018-04-06 15:54:18 -07:00
Anthony Dresser
596f09f754 add custom action for explorer actions (#1059) 2018-04-06 15:53:45 -07:00
Anthony Dresser
563e25f073 add custom output channel (#1087) 2018-04-06 15:52:33 -07:00
Karl Burtram
1800d0baaf Bump SQL Ops to 0.28.2 (#1098) 2018-04-06 15:51:24 -07:00
Karl Burtram
2182658301 Fix OE single click and expand groups by default (#1096) 2018-04-06 15:15:41 -07:00
Karl Burtram
3990719054 Rename registeredServers to objectExplorer (#1093) 2018-04-06 13:33:49 -07:00
Abbie Petchtes
071b510fba add dropdown background color for sqlops light and dark themes (#1088)
* add dropdown background color for sqlops light and dark themes

* edit the colors

* formatting
2018-04-06 10:15:59 -07:00
Anthony Dresser
d2d2ade9f7 register feature for language client for agent (#1086) 2018-04-05 21:49:57 -07:00
Matt Irvine
d97d2e5c91 Reenable logging for SQL Tools Service (#1089) 2018-04-05 16:04:18 -07:00
Abbie Petchtes
a6ba44e435 Fix accessibility issue for clear history button in connection dialog (#1084)
* change clear history connections button to action bar

* formatting
2018-04-05 14:42:21 -07:00
Aditya Bist
4967e630fb Build fix (#1085)
* added caching for jobs view and history page

* added build fix
2018-04-05 12:58:21 -07:00
Abbie Petchtes
2508464fde fix build break in sql agent (#1083)
fix build break in master branch
2018-04-05 11:55:28 -07:00
Abbie Petchtes
782623cba9 fix keyboard issues in task and explorer widgets (#1064) 2018-04-05 10:09:02 -07:00
Aditya Bist
36045c5381 added caching for jobs view and history page (#1056) 2018-04-04 21:56:04 -07:00
Karl Burtram
7e49167530 Bump SQL Tools version to 1.4.0-alpha.18 (#1075) 2018-04-04 18:36:41 -07:00
Karl Burtram
a680a2a7dc Revert travis file to pre-1.21 merge (#1074) 2018-04-04 18:31:17 -07:00
Matt Irvine
4734451f5f Update vscode-nls version for azure extension (#1073) 2018-04-04 17:49:01 -07:00
Karl Burtram
dafb780987 Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches

* A few more merges

* Post npm install

* Fix batch of build breaks

* Fix more build breaks

* Fix more build errors

* Fix more build breaks

* Runtime fixes 1

* Get connection dialog working with some todos

* Fix a few packaging issues

* Copy several node_modules to package build to fix loader issues

* Fix breaks from master

* A few more fixes

* Make tests pass

* First pass of license header updates

* Second pass of license header updates

* Fix restore dialog issues

* Remove add additional themes menu items

* fix select box issues where the list doesn't show up

* formatting

* Fix editor dispose issue

* Copy over node modules to correct location on all platforms
2018-04-04 15:27:51 -07:00
Aditya Bist
5fba3e31b4 fixed css issues (#1066) 2018-04-04 13:42:40 -07:00
Anthony Dresser
0315020cf0 change enum type to conform to new connection (#1053) 2018-04-04 11:40:14 -07:00
Anup N. Kamath
6dca896768 When we click in recent connections the connection profile doesn't get updated (#1060)
* Trigger the update provider dropdown when a provider value is set
2018-04-04 10:36:04 -07:00
Anup N. Kamath
90454fbe87 Fixing the provider name (#1051) 2018-04-03 18:03:08 -07:00
Abbie Petchtes
f9b2136494 Fix the scrollbar issue in widget container (#1016)
* fix the scrollbar issue in widget container

* move scrollbar to widget content
2018-04-03 16:16:58 -07:00
Matt Irvine
3d1c1aefb3 Bump sql tools service (#1049) 2018-04-03 09:48:59 -07:00
Anthony Dresser
e6a65599fd fix client options in mssql (#1044) 2018-04-02 18:23:57 -07:00
Anthony Dresser
32ac907403 crypto is part of node now (#1033) 2018-03-31 11:36:44 -07:00
Brendan Mason
3af05d62b2 Add square brackets for ms_foreachdb call (#1023)
Add square brackets around ? to support database names with special characters
2018-03-30 09:54:12 -07:00
Aditya Bist
b5d8dfa509 Agent WIP (#1031)
* WIP

* wip

* SQL Agent wip

* wip

* Initial control host (wip)

* Initial hookup of SQL Agent service to job component

* Update agent package.json

* Hook up getJobs call

* A couple job view updates

* Add some more agent views

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* Rename some 'agent' classes to 'jobManagement'

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* job history page (#852)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* Switch back getJobs return type

* Make enum const

* Remove sqlops const

* WIP

* WIP

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* Feature/agent1 adbist (#899)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* made job history page css more specific

* Add visiblity check to job view

* added method signatures for job history with DMP

* Clean up jobs styling and call getJobHistory

* Add more Job Table styling

* Enable detail view in job table

* Use updated slickgrid repo

* vbumped slickgrid

* added methods for job running

* added job actions to sqlops

* Convert rowdetail slickgrid plug to TypeScript

* Feature/agent1 adbist (#945)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* added method signatures for job history with DMP

* added methods for job running

* added job actions to sqlops

* Refer to dataprotocol from feature/agentDmp1 branch

* Update SQL Tools version to 1.4.0-alpha.13

* Change Feb to March in release note prompt

* SQL Agent extension metadata

* add feature explicitly in client creation

* Update Agent job registration

* navigation works but is really slow to load data

* Update package.json

* fixed conflicts

* Feature/agent1 adbist (#955)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* added method signatures for job history with DMP

* added methods for job running

* added job actions to sqlops

* navigation works but is really slow to load data

* Add jobs view icon

* fixed bug where not all steps were being shown

* Misc. cleanups

* added more to history page

* added loadHistories and code review comments

* made the params standard

* fixed json local paths

* added step implementation

* fixed conflict

* cleaned up code

* removed extension-modules

* CR comments

* fix css

* fixed data injection

* steps now support big messages

* improve history page UX

* added messages for job actions

* styling fix

* cr comments
2018-03-29 16:29:40 -07:00
Abbie Petchtes
612987d1e5 fix the close icons in sqlops (#1032) 2018-03-29 16:16:39 -07:00
Aditya Bist
916598e029 Agent work (WIP) (#1012)
* WIP

* wip

* SQL Agent wip

* wip

* Initial control host (wip)

* Initial hookup of SQL Agent service to job component

* Update agent package.json

* Hook up getJobs call

* A couple job view updates

* Add some more agent views

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* Rename some 'agent' classes to 'jobManagement'

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* job history page (#852)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* Switch back getJobs return type

* Make enum const

* Remove sqlops const

* WIP

* WIP

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* Feature/agent1 adbist (#899)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* made job history page css more specific

* Add visiblity check to job view

* added method signatures for job history with DMP

* Clean up jobs styling and call getJobHistory

* Add more Job Table styling

* Enable detail view in job table

* Use updated slickgrid repo

* vbumped slickgrid

* added methods for job running

* added job actions to sqlops

* Convert rowdetail slickgrid plug to TypeScript

* Feature/agent1 adbist (#945)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* added method signatures for job history with DMP

* added methods for job running

* added job actions to sqlops

* Refer to dataprotocol from feature/agentDmp1 branch

* Update SQL Tools version to 1.4.0-alpha.13

* Change Feb to March in release note prompt

* SQL Agent extension metadata

* add feature explicitly in client creation

* Update Agent job registration

* navigation works but is really slow to load data

* Update package.json

* fixed conflicts

* Feature/agent1 adbist (#955)

* added back button, run actions and overview accordion

* refactoring

* overview table complete

* fixed the dropdown arrow for the overview section

* added table for prev job list

* fixed agent job result type

* code cleaning and code review comments

* fixed yarn.lock conflicts

* added function for job history

* changed vscode-languageclient version

* changed yarn lock file

* fixed yarn lock file

* fixed yarn file

* fixed css paths

* added images to packaging step

* fix resource path for packaging

* added steps lists

* fixed style and dimensions

* fixed conflicts

* implemented job list

* added the Date and Status columns

* update yarn files

* merged feature/agent1

* added theme styling for light theme

* changed yarn lock files

* added method signatures for job history with DMP

* added methods for job running

* added job actions to sqlops

* navigation works but is really slow to load data

* Add jobs view icon

* fixed bug where not all steps were being shown

* Misc. cleanups

* added more to history page

* added loadHistories and code review comments

* made the params standard

* fixed json local paths

* added step implementation

* fixed conflict

* cleaned up code

* removed extension-modules

* CR comments

* fix css

* fixed data injection

* steps now support big messages

* improve history page UX
2018-03-29 12:41:31 -07:00
Anthony Dresser
c45c634938 change layout to refresh (#1025) 2018-03-28 21:10:03 -07:00
Anthony Dresser
1bed0d0733 rename sqlops extension (#1002)
* rename sqlops extension

* fix sqlops references
2018-03-28 14:59:59 -07:00
Anthony Dresser
e0075b7633 fix error in task widget (#1017) 2018-03-28 14:24:38 -07:00
Anthony Dresser
0029767561 add dev depencies to keep yanr from erroring during build (#1015) 2018-03-28 14:24:22 -07:00
Matt Irvine
93f9828d04 Focus connection dialog on password when prompting for it (#1019) 2018-03-28 13:56:10 -07:00
Aditya Bist
c484af0901 get latest toolsservice 2018-03-28 12:57:45 -07:00
Leila Lali
b2a96bbe50 Fix/use sqlops engine version (#1011)
* using sqlops as engine version instead of vscode
2018-03-28 11:30:44 -07:00
Anthony Dresser
2414f43757 Refactor out extensions-modules and rewrite mssql extension (#909)
* commting .d.ts changes

* added serverinfo to .d.ts

* maybe its working?

* works

* updated contrib

* remove unnecessary code

* fix compile errors

* init

* conitnue

* on the way to working maybe?

* close

* EVERYTHING WORKS

* moved src out of client folder

* formatting

* reenable logging

* working on build file

* fixed install service gulp command

* fix the command to properly return promises

* clean up code

* add telemetry

* formatting

* added logging/telemetry/statusview

* formatting

* address comments

* resolute vscode-language versions
2018-03-28 10:59:08 -07:00
Anthony Dresser
22c54a9917 connection contribution point (#880)
* init

* finished compile erros

* fixed all merge conflicts

* fix dialog problems

* formatting

* fix opening dialog on first open

* fix various problems with connectiondialog

* formatting

* fix tests

* added connection contrib

* formatting

* formatting and adding capabilities to shutdown

* fix connection buffering

* formatting

* fix tests
2018-03-28 10:58:47 -07:00
Karl Burtram
a14c0351ba Update readme.md and changelog for March release (#1008)
* Update changelog

* Update readme fwlinks

* A couple more thank you's
2018-03-27 20:26:43 -07:00
Anthony Dresser
31f75a46c8 add proper typings to sqlops (#1010) 2018-03-27 19:17:27 -07:00
Abbie Petchtes
08d1e9cd73 fix small typo in readme (#1005) 2018-03-27 13:31:44 -07:00
Abbie Petchtes
0da83b5d4b Update screenshots for extensions' READ ME (#1004)
* update readme for sample extensions

* Address comments

* Address comments

* edit screenshot URLS
2018-03-27 13:26:14 -07:00
Abbie Petchtes
37d7266751 Update read me for sample extensions (#1003)
* update readme for sample extensions

* Address comments

* Address comments
2018-03-27 13:07:26 -07:00
Anthony Dresser
ddfb61b46a change settings to only affect grid; remove default fontfamily (#989) 2018-03-27 11:14:54 -07:00
Matt Irvine
9a2e8cffed Use nvarchar(128) for database name in db space script (#999) 2018-03-26 17:42:26 -07:00
Matt Irvine
e9299d1991 Tabs should fill entire panel (#995) 2018-03-26 16:01:40 -07:00
Karl Burtram
08d97cc795 Bump SQL Ops to 0.28 for April release train (#993) 2018-03-26 14:46:16 -07:00
10820 changed files with 180727 additions and 115092 deletions

9
.vscode/launch.json vendored
View File

@@ -1,7 +1,6 @@
{
"version": "0.1.0",
"configurations": [
{
"type": "node",
"request": "launch",
@@ -9,7 +8,7 @@
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
"stopOnEntry": true,
"args": [
"watch-extension:json-client"
"hygiene"
],
"cwd": "${workspaceFolder}"
},
@@ -87,7 +86,11 @@
"runtimeArgs": [
"--inspect=5875"
],
"webRoot": "${workspaceFolder}"
"skipFiles": [
"**/winjs*.js"
],
"webRoot": "${workspaceFolder}",
"timeout": 15000
},
{
"type": "node",

View File

@@ -10,6 +10,9 @@
"when": "$(basename).ts"
}
},
"files.associations": {
"OSSREADME.json": "jsonc"
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
@@ -35,6 +38,5 @@
}
}
],
"typescript.tsdk": "node_modules/typescript/lib",
"git.ignoreLimitWarning": true
}
"typescript.tsdk": "node_modules/typescript/lib"
}

View File

@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron"
target "1.7.11"
target "1.7.12"
runtime "electron"

View File

@@ -1,5 +1,35 @@
# Change Log
## 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
## What's new in this version
The March Public Preview release enables some key aspects of the SQL Operations
Studio extensibility story. Here are some highlights in this release.
* Enhance the Manage Dashboard extensibility model to support tabbed Insights and Configuration panes
* Dashboard Insights extensions for `sp_whoisactive` from [whoisactive.com](http://whoisactive.com)
* Extension Manager enables simple acquisition of 1st-party and 3rd-party extensions
* Add additional Extensibility APIs for `connection` and `objectexplorer` management
* Community Localization open for 10 languages
* Continue to fix important customer impacting GitHub issues
## Version 0.26.7
* Release date: February 16, 2017
* Release status: Public Preview Hotfix 1

View File

@@ -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 February Public Preview**
**Download SQL Operations Studio March Public Preview**
Platform | Link
-- | --
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=867998
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=867997
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=867999
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=868000
Linux DEB | https://go.microsoft.com/fwlink/?linkid=868002
Linux RPM | https://go.microsoft.com/fwlink/?linkid=868001
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=872717
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=872718
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=872719
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=872720
Linux DEB | https://go.microsoft.com/fwlink/?linkid=872722
Linux RPM | https://go.microsoft.com/fwlink/?linkid=872721
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,8 @@ 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:
* 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)`
* mikaoelitiana for fix: `revert README and CONTRIBUTING after last VSCode merge (#574)`
* alextercete for `Reinstate menu item to install from VSIX (#682)`
@@ -79,6 +73,10 @@ We would like to thank all our users who raised issues, and in particular the fo
* stebet for `Fix #153: Fixing sql snippets that failed on a DB with case-sensitive collation. (#152)`
* 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)*
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)
## License

View File

@@ -11,6 +11,7 @@ install:
build_script:
- yarn
- .\node_modules\.bin\gulp electron
- .\node_modules\.bin\tsc -p .\src\tsconfig.monaco.json --noEmit
- npm run compile
test_script:

View File

@@ -0,0 +1,12 @@
[
{
"name": "ms-vscode.node-debug",
"version": "1.21.8",
"repo": "https://github.com/Microsoft/vscode-node-debug"
},
{
"name": "ms-vscode.node-debug2",
"version": "1.21.2",
"repo": "https://github.com/Microsoft/vscode-node-debug2"
}
]

20
build/builtin/.eslintrc Normal file
View File

@@ -0,0 +1,20 @@
{
"env": {
"node": true,
"es6": true,
"browser": true
},
"rules": {
"no-console": 0,
"no-cond-assign": 0,
"no-unused-vars": 1,
"no-extra-semi": "warn",
"semi": "warn"
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
}
}

View File

@@ -0,0 +1,126 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const fs = require('fs');
const path = require('path');
const os = require('os');
// @ts-ignore review
const { remote } = require('electron');
const dialog = remote.dialog;
const builtInExtensionsPath = path.join(__dirname, '..', 'builtInExtensions.json');
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
function readJson(filePath) {
return JSON.parse(fs.readFileSync(filePath, { encoding: 'utf8' }));
}
function writeJson(filePath, obj) {
fs.writeFileSync(filePath, JSON.stringify(obj, null, 2));
}
function renderOption(form, id, title, value, checked) {
const input = document.createElement('input');
input.type = 'radio';
input.id = id;
input.name = 'choice';
input.value = value;
input.checked = !!checked;
form.appendChild(input);
const label = document.createElement('label');
label.setAttribute('for', id);
label.textContent = title;
form.appendChild(label);
return input;
}
function render(el, state) {
function setState(state) {
try {
writeJson(controlFilePath, state.control);
} catch (err) {
console.error(err);
}
el.innerHTML = '';
render(el, state);
}
const ul = document.createElement('ul');
const { builtin, control } = state;
for (const ext of builtin) {
const controlState = control[ext.name] || 'marketplace';
const li = document.createElement('li');
ul.appendChild(li);
const name = document.createElement('code');
name.textContent = ext.name;
li.appendChild(name);
const form = document.createElement('form');
li.appendChild(form);
const marketplaceInput = renderOption(form, `marketplace-${ext.name}`, 'Marketplace', 'marketplace', controlState === 'marketplace');
marketplaceInput.onchange = function () {
control[ext.name] = 'marketplace';
setState({ builtin, control });
};
const disabledInput = renderOption(form, `disabled-${ext.name}`, 'Disabled', 'disabled', controlState === 'disabled');
disabledInput.onchange = function () {
control[ext.name] = 'disabled';
setState({ builtin, control });
};
let local = undefined;
if (controlState !== 'marketplace' && controlState !== 'disabled') {
local = controlState;
}
const localInput = renderOption(form, `local-${ext.name}`, 'Local', 'local', !!local);
localInput.onchange = function () {
const result = dialog.showOpenDialog(remote.getCurrentWindow(), {
title: 'Choose Folder',
properties: ['openDirectory']
});
if (result && result.length >= 1) {
control[ext.name] = result[0];
}
setState({ builtin, control });
};
if (local) {
const localSpan = document.createElement('code');
localSpan.className = 'local';
localSpan.textContent = local;
form.appendChild(localSpan);
}
}
el.appendChild(ul);
}
function main() {
const el = document.getElementById('extensions');
const builtin = readJson(builtInExtensionsPath);
let control;
try {
control = readJson(controlFilePath);
} catch (err) {
control = {};
}
render(el, { builtin, control });
}
window.onload = main;

46
build/builtin/index.html Normal file
View File

@@ -0,0 +1,46 @@
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Manage Built-in Extensions</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="browser-main.js"></script>
<style>
body {
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
font-size: 10pt;
}
code {
font-family: 'Menlo', 'Courier New', 'Courier', monospace;
}
ul {
padding-left: 1em;
}
li {
list-style: none;
padding: 0.3em 0;
}
label {
margin-right: 1em;
}
form {
padding: 0.3em 0 0.3em 0.3em;
}
</style>
</head>
<body>
<h1>Built-in Extensions</h1>
<div id="extensions"></div>
</body>
</html>

20
build/builtin/main.js Normal file
View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const { app, BrowserWindow } = require('electron');
const url = require('url');
const path = require('path');
let window = null;
app.once('ready', () => {
window = new BrowserWindow({ width: 800, height: 600 });
window.setMenuBarVisibility(false);
window.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true }));
// window.webContents.openDevTools();
window.once('closed', () => window = null);
});
app.on('window-all-closed', () => app.quit());

View File

@@ -0,0 +1,5 @@
{
"name": "builtin",
"version": "0.1.0",
"main": "main.js"
}

View File

@@ -12,6 +12,7 @@ var File = require('vinyl');
var root = path.dirname(__dirname);
var sha1 = util.getVersion(root);
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
var semver = require('./monaco/package.json').version;
var headerVersion = semver + '(' + sha1 + ')';
@@ -21,14 +22,14 @@ var editorEntryPoints = [
{
name: 'vs/editor/editor.main',
include: [],
exclude: [ 'vs/css', 'vs/nls' ],
prepend: [ 'out-build/vs/css.js', 'out-build/vs/nls.js' ],
exclude: ['vs/css', 'vs/nls'],
prepend: ['out-build/vs/css.js', 'out-build/vs/nls.js'],
},
{
name: 'vs/base/common/worker/simpleWorker',
include: [ 'vs/editor/common/services/editorSimpleWorker' ],
prepend: [ 'vs/loader.js' ],
append: [ 'vs/base/worker/workerMain' ],
include: ['vs/editor/common/services/editorSimpleWorker'],
prepend: ['vs/loader.js'],
append: ['vs/base/worker/workerMain'],
dest: 'vs/base/worker/workerMain.js'
}
];
@@ -79,14 +80,15 @@ gulp.task('optimize-editor', ['clean-optimized-editor', 'compile-client-build'],
bundleLoader: false,
header: BUNDLED_FILE_HEADER,
bundleInfo: true,
out: 'out-editor'
out: 'out-editor',
languages: undefined
}));
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-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', 'minify-editor', 'optimize-editor'], function () {
return es.merge(
// other assets
es.merge(
@@ -97,17 +99,17 @@ gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-ed
// package.json
gulp.src('build/monaco/package.json')
.pipe(es.through(function(data) {
.pipe(es.through(function (data) {
var json = JSON.parse(data.contents.toString());
json.private = false;
data.contents = new Buffer(JSON.stringify(json, null, ' '));
data.contents = Buffer.from(JSON.stringify(json, null, ' '));
this.emit('data', data);
}))
.pipe(gulp.dest('out-monaco-editor-core')),
// README.md
gulp.src('build/monaco/README-npm.md')
.pipe(es.through(function(data) {
.pipe(es.through(function (data) {
this.emit('data', new File({
path: data.path.replace(/README-npm\.md/, 'README.md'),
base: data.base,
@@ -124,10 +126,10 @@ gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-ed
// min folder
es.merge(
gulp.src('out-editor-min/**/*')
).pipe(filterStream(function(path) {
).pipe(filterStream(function (path) {
// no map files
return !/(\.js\.map$)|(nls\.metadata\.json$)|(bundleInfo\.json$)/.test(path);
})).pipe(es.through(function(data) {
})).pipe(es.through(function (data) {
// tweak the sourceMappingURL
if (!/\.js$/.test(data.path)) {
this.emit('data', data);
@@ -140,49 +142,50 @@ gulp.task('editor-distro', ['clean-editor-distro', 'minify-editor', 'optimize-ed
var newStr = '//# sourceMappingURL=' + relativePathToMap.replace(/\\/g, '/');
strContents = strContents.replace(/\/\/\# sourceMappingURL=[^ ]+$/, newStr);
data.contents = new Buffer(strContents);
data.contents = Buffer.from(strContents);
this.emit('data', data);
})).pipe(gulp.dest('out-monaco-editor-core/min')),
// min-maps folder
es.merge(
gulp.src('out-editor-min/**/*')
).pipe(filterStream(function(path) {
).pipe(filterStream(function (path) {
// no map files
return /\.js\.map$/.test(path);
})).pipe(gulp.dest('out-monaco-editor-core/min-maps'))
);
});
gulp.task('analyze-editor-distro', function() {
gulp.task('analyze-editor-distro', function () {
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
var bundleInfo = require('../out-editor/bundleInfo.json');
var graph = bundleInfo.graph;
var bundles = bundleInfo.bundles;
var inverseGraph = {};
Object.keys(graph).forEach(function(module) {
Object.keys(graph).forEach(function (module) {
var dependencies = graph[module];
dependencies.forEach(function(dep) {
dependencies.forEach(function (dep) {
inverseGraph[dep] = inverseGraph[dep] || [];
inverseGraph[dep].push(module);
});
});
var detailed = {};
Object.keys(bundles).forEach(function(entryPoint) {
Object.keys(bundles).forEach(function (entryPoint) {
var included = bundles[entryPoint];
var includedMap = {};
included.forEach(function(included) {
included.forEach(function (included) {
includedMap[included] = true;
});
var explanation = [];
included.map(function(included) {
included.map(function (included) {
if (included.indexOf('!') >= 0) {
return;
}
var reason = (inverseGraph[included]||[]).filter(function(mod) {
var reason = (inverseGraph[included] || []).filter(function (mod) {
return !!includedMap[mod];
});
explanation.push({
@@ -198,7 +201,7 @@ gulp.task('analyze-editor-distro', function() {
});
function filterStream(testFunc) {
return es.through(function(data) {
return es.through(function (data) {
if (!testFunc(data.relative)) {
return;
}

View File

@@ -20,6 +20,7 @@ const sourcemaps = require('gulp-sourcemaps');
const nlsDev = require('vscode-nls-dev');
const root = path.dirname(__dirname);
const commit = util.getVersion(root);
const i18n = require('./lib/i18n');
const extensionsPath = path.join(path.dirname(__dirname), 'extensions');
@@ -29,7 +30,8 @@ const compilations = glob.sync('**/tsconfig.json', {
});
const getBaseUrl = out => `https://ticino.blob.core.windows.net/sourcemaps/${commit}/${out}`;
const languages = ['chs', 'cht', 'jpn', 'kor', 'deu', 'fra', 'esn', 'rus', 'ita'];
const languages = i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages : []);
const tasks = compilations.map(function (tsconfigFile) {
const absolutePath = path.join(extensionsPath, tsconfigFile);
@@ -55,9 +57,19 @@ const tasks = compilations.map(function (tsconfigFile) {
const srcBase = path.join(root, 'src');
const src = path.join(srcBase, '**');
const out = path.join(root, 'out');
const i18n = path.join(__dirname, '..', 'i18n');
const i18nPath = path.join(__dirname, '..', 'i18n');
const baseUrl = getBaseUrl(out);
let headerId, headerOut;
let index = relativeDirname.indexOf('/');
if (index < 0) {
headerId = 'vscode.' + relativeDirname;
headerOut = 'out';
} else {
headerId = 'vscode.' + relativeDirname.substr(0, index);
headerOut = relativeDirname.substr(index + 1) + '/out';
}
function createPipeline(build, emitError) {
const reporter = createReporter();
@@ -82,7 +94,9 @@ const tasks = compilations.map(function (tsconfigFile) {
sourceRoot: '../src'
}))
.pipe(tsFilter.restore)
.pipe(build ? nlsDev.createAdditionalLanguageFiles(languages, i18n, out) : es.through())
.pipe(build ? nlsDev.createAdditionalLanguageFiles(languages, i18nPath, out) : es.through())
.pipe(build ? nlsDev.bundleMetaDataFiles(headerId, headerOut) : es.through())
.pipe(build ? nlsDev.bundleLanguageFiles() : es.through())
.pipe(reporter.end(emitError));
return es.duplex(input, output);
@@ -129,7 +143,7 @@ const tasks = compilations.map(function (tsconfigFile) {
const watchInput = watcher(src, srcOpts);
return watchInput
.pipe(util.incremental(() => pipeline(true), input))
.pipe(util.incremental(() => pipeline(), input))
.pipe(gulp.dest(out));
});

View File

@@ -12,7 +12,11 @@ const gulptslint = require('gulp-tslint');
const gulpeslint = require('gulp-eslint');
const tsfmt = require('typescript-formatter');
const tslint = require('tslint');
const VinylFile = require('vinyl');
const vfs = require('vinyl-fs');
const path = require('path');
const fs = require('fs');
const pall = require('p-all');
/**
* Hygiene works by creating cascading subsets of all our files and
@@ -29,55 +33,56 @@ const all = [
'extensions/**/*',
'scripts/**/*',
'src/**/*',
'test/**/*'
];
const eolFilter = [
'**',
'!ThirdPartyNotices.txt',
'!LICENSE.txt',
'!extensions/**/out/**',
'!test/smoke/out/**',
'!**/node_modules/**',
'!**/fixtures/**',
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot}',
'!build/{lib,tslintRules}/**/*.js',
'!build/monaco/**',
'!build/win32/**',
'!build/**/*.sh',
'!build/tfs/**/*.js',
'!**/Dockerfile'
'test/**/*',
'!**/node_modules/**'
];
const indentationFilter = [
'**',
// except specific files
'!ThirdPartyNotices.txt',
'!**/*.md',
'!**/*.ps1',
'!**/*.template',
'!**/*.yaml',
'!**/*.yml',
'!**/yarn.lock',
'!**/lib/**',
'!extensions/**/*.d.ts',
'!src/typings/**/*.d.ts',
'!src/vs/*/**/*.d.ts',
'!**/*.d.ts.recipe',
'!LICENSE.txt',
'!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/node/terminateProcess.sh',
'!src/vs/base/node/ps-win.ps1',
'!test/assert.js',
// except specific folders
'!test/smoke/out/**',
'!extensions/vscode-api-tests/testWorkspace/**',
'!extensions/vscode-api-tests/testWorkspace2/**',
'!build/monaco/**',
'!build/win32/**',
// except multiple specific files
'!**/package.json',
'!**/yarn.lock',
// except multiple specific folders
'!**/octicons/**',
'!**/vs/base/common/marked/raw.marked.js',
'!**/vs/base/common/winjs.base.raw.js',
'!**/vs/base/node/terminateProcess.sh',
'!**/vs/base/node/ps-win.ps1',
'!**/vs/nls.js',
'!**/vs/css.js',
'!**/vs/loader.js',
'!**/fixtures/**',
'!**/lib/**',
'!extensions/**/out/**',
'!extensions/**/snippets/**',
'!extensions/**/syntaxes/**',
'!extensions/**/themes/**',
'!extensions/**/colorize-fixtures/**',
'!extensions/vscode-api-tests/testWorkspace/**'
// except specific file types
'!src/vs/*/**/*.d.ts',
'!src/typings/**/*.d.ts',
'!extensions/**/*.d.ts',
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe}',
'!build/{lib,tslintRules}/**/*.js',
'!build/**/*.sh',
'!build/tfs/**/*.js',
'!**/Dockerfile',
'!extensions/markdown/media/*.js'
];
const copyrightFilter = [
@@ -95,6 +100,7 @@ const copyrightFilter = [
'!**/*.xpm',
'!**/*.opts',
'!**/*.disabled',
'!**/*.code-workspace',
'!build/**/*.init',
'!resources/linux/snap/snapcraft.yaml',
'!resources/win32/bin/code.js',
@@ -124,6 +130,7 @@ const tslintFilter = [
'!**/node_modules/**',
'!extensions/typescript/test/colorize-fixtures/**',
'!extensions/vscode-api-tests/testWorkspace/**',
'!extensions/vscode-api-tests/testWorkspace2/**',
'!extensions/**/*.test.ts',
'!extensions/html/server/lib/jquery.d.ts'
];
@@ -144,31 +151,23 @@ gulp.task('eslint', () => {
});
gulp.task('tslint', () => {
// {{SQL CARBON EDIT}}
const options = { emitError: false };
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(tslintFilter))
.pipe(gulptslint({ rulesDirectory: 'build/lib/tslint' }))
.pipe(gulptslint.report(options));
.pipe(gulptslint.default({ rulesDirectory: 'build/lib/tslint' }))
.pipe(gulptslint.default.report(options));
});
const hygiene = exports.hygiene = (some, options) => {
options = options || {};
function hygiene(some) {
let errorCount = 0;
const eol = es.through(function (file) {
if (/\r\n?/g.test(file.contents.toString('utf8'))) {
console.error(file.relative + ': Bad EOL found');
errorCount++;
}
this.emit('data', file);
});
const indentation = es.through(function (file) {
file.contents
.toString('utf8')
.split(/\r\n|\r|\n/)
const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
file.__lines = lines;
lines
.forEach((line, i) => {
if (/^\s*$/.test(line)) {
// empty or whitespace lines are OK
@@ -186,9 +185,14 @@ const hygiene = exports.hygiene = (some, options) => {
});
const copyrights = es.through(function (file) {
if (file.contents.toString('utf8').indexOf(copyrightHeader) !== 0) {
console.error(file.relative + ': Missing or bad copyright statement');
errorCount++;
const lines = file.__lines;
for (let i = 0; i < copyrightHeaderLines.length; i++) {
if (lines[i] !== copyrightHeaderLines[i]) {
console.error(file.relative + ': Missing or bad copyright statement');
errorCount++;
break;
}
}
this.emit('data', file);
@@ -196,12 +200,20 @@ const hygiene = exports.hygiene = (some, options) => {
const formatting = es.map(function (file, cb) {
tsfmt.processString(file.path, file.contents.toString('utf8'), {
verify: true,
verify: false,
tsfmt: true,
// verbose: true
// keep checkJS happy
editorconfig: undefined,
replace: undefined,
tsconfig: undefined,
tslint: undefined
}).then(result => {
if (result.error) {
console.error(result.message);
let original = result.src.replace(/\r\n/gm, '\n');
let formatted = result.dest.replace(/\r\n/gm, '\n');
if (original !== formatted) {
console.error('File not formatted:', file.relative);
errorCount++;
}
cb(null, file);
@@ -211,43 +223,31 @@ const hygiene = exports.hygiene = (some, options) => {
});
});
function reportFailures(failures) {
failures.forEach(failure => {
const name = failure.name || failure.fileName;
const position = failure.startPosition;
const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line;
const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character;
// console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`);
});
}
const tslintConfiguration = tslint.Configuration.findConfiguration('tslint.json', '.');
const tslintOptions = { fix: false, formatter: 'json' };
const tsLinter = new tslint.Linter(tslintOptions);
const tsl = es.through(function (file) {
const configuration = tslint.Configuration.findConfiguration(null, '.');
const options = { formatter: 'json', rulesDirectory: 'build/lib/tslint' };
const contents = file.contents.toString('utf8');
const linter = new tslint.Linter(options);
linter.lint(file.relative, contents, configuration.results);
const result = linter.getResult();
if (result.failures.length > 0) {
reportFailures(result.failures);
errorCount += result.failures.length;
}
tsLinter.lint(file.relative, contents, tslintConfiguration.results);
this.emit('data', file);
});
const result = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true })
let input;
if (Array.isArray(some) || typeof some === 'string' || !some) {
input = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true });
} else {
input = some;
}
const result = input
.pipe(filter(f => !f.stat.isDirectory()))
.pipe(filter(eolFilter))
// {{SQL CARBON EDIT}}
//.pipe(options.skipEOL ? es.through() : eol)
.pipe(filter(indentationFilter))
.pipe(indentation)
.pipe(filter(copyrightFilter))
.pipe(filter(copyrightFilter));
// {{SQL CARBON EDIT}}
//.pipe(copyrights);
// .pipe(copyrights);
const typescript = result
.pipe(filter(tslintFilter))
@@ -257,23 +257,52 @@ const hygiene = exports.hygiene = (some, options) => {
const javascript = result
.pipe(filter(eslintFilter))
.pipe(gulpeslint('src/.eslintrc'))
.pipe(gulpeslint.formatEach('compact'))
// {{SQL CARBON EDIT}}
.pipe(gulpeslint.formatEach('compact'));
// {{SQL CARBON EDIT}}
// .pipe(gulpeslint.failAfterError());
return es.merge(typescript, javascript)
.pipe(es.through(null, function () {
// {{SQL CARBON EDIT}}
// if (errorCount > 0) {
// this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
// } else {
// this.emit('end');
// }
this.emit('end');
}));
};
let count = 0;
return es.merge(typescript, javascript)
.pipe(es.through(function (data) {
// {{SQL CARBON EDIT}}
this.emit('end');
}));
}
gulp.task('hygiene', () => hygiene(''));
function createGitIndexVinyls(paths) {
const cp = require('child_process');
const repositoryPath = process.cwd();
const fns = paths.map(relativePath => () => new Promise((c, e) => {
const fullPath = path.join(repositoryPath, relativePath);
fs.stat(fullPath, (err, stat) => {
if (err && err.code === 'ENOENT') { // ignore deletions
return c(null);
} else if (err) {
return e(err);
}
cp.exec(`git show :${relativePath}`, { maxBuffer: 2000 * 1024, encoding: 'buffer' }, (err, out) => {
if (err) {
return e(err);
}
c(new VinylFile({
path: fullPath,
base: repositoryPath,
contents: out,
stat
}));
});
});
}));
return pall(fns, { concurrency: 4 })
.then(r => r.filter(p => !!p));
}
gulp.task('hygiene', () => hygiene());
// this allows us to run hygiene as a git pre-commit hook
if (require.main === module) {
@@ -284,22 +313,19 @@ if (require.main === module) {
process.exit(1);
});
cp.exec('git config core.autocrlf', (err, out) => {
const skipEOL = out.trim() === 'true';
if (process.argv.length > 2) {
return hygiene(process.argv.slice(2), { skipEOL: skipEOL }).on('error', err => {
console.error();
console.error(err);
process.exit(1);
});
}
if (process.argv.length > 2) {
hygiene(process.argv.slice(2)).on('error', err => {
console.error();
console.error(err);
process.exit(1);
});
} else {
cp.exec('git diff --cached --name-only', { maxBuffer: 2000 * 1024 }, (err, out) => {
if (err) {
console.error();
console.error(err);
process.exit(1);
return;
}
const some = out
@@ -307,12 +333,18 @@ if (require.main === module) {
.filter(l => !!l);
if (some.length > 0) {
hygiene(some, { skipEOL: skipEOL }).on('error', err => {
console.error();
console.error(err);
process.exit(1);
});
console.log('Reading git index versions...');
createGitIndexVinyls(some)
.then(vinyls => new Promise((c, e) => hygiene(es.readArray(vinyls))
.on('end', () => c())
.on('error', e)))
.catch(err => {
console.error();
console.error(err);
process.exit(1);
});
}
});
});
}
}

View File

@@ -6,9 +6,21 @@
'use strict';
const gulp = require('gulp');
const json = require('gulp-json-editor');
const buffer = require('gulp-buffer');
const filter = require('gulp-filter');
const es = require('event-stream');
const util = require('./lib/util');
const remote = require('gulp-remote-src');
const zip = require('gulp-vinyl-zip');
const assign = require('object-assign');
// {{SQL CARBON EDIT}}
const jeditor = require('gulp-json-editor');
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const pkg = require('../package.json');
gulp.task('mixin', function () {
// {{SQL CARBON EDIT}}
const updateUrl = process.env['SQLOPS_UPDATEURL'];
@@ -25,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,

View File

@@ -13,14 +13,6 @@ const filter = require('gulp-filter');
gulp.task('clean-mssql-extension', util.rimraf('extensions/mssql/node_modules'));
gulp.task('clean-credentials-extension', util.rimraf('extensions/credentials/node_modules'));
gulp.task('clean-extensions-modules', util.rimraf('extensions-modules/node_modules'));
gulp.task('clean-protocol', ['clean-extensions-modules', 'clean-mssql-extension', 'clean-credentials-extension', 'clean-client', 'clean-jsonrpc', 'clean-server', 'clean-types']);
// Tasks to clean extensions modules
gulp.task('clean-mssql-ext-mod', util.rimraf('extensions/mssql/node_modules/extensions-modules'));
gulp.task('clean-credentials-ext-mod', util.rimraf('extensions/credentials/node_modules/extensions-modules'));
gulp.task('clean-build-ext-mod', util.rimraf('build/node_modules/extensions-modules'));
gulp.task('clean-ext-mod', ['clean-mssql-ext-mod', 'clean-credentials-ext-mod', 'clean-build-ext-mod', 'clean-extensions-modules']);
gulp.task('fmt', () => formatStagedFiles());
const formatFiles = (some) => {

View File

@@ -27,17 +27,22 @@ const common = require('./lib/optimize');
const nlsDev = require('vscode-nls-dev');
const root = path.dirname(__dirname);
const commit = util.getVersion(root);
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const packageJson = require('../package.json');
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const product = require('../product.json');
const crypto = require('crypto');
const i18n = require('./lib/i18n');
const serviceInstaller = require('../extensions-modules/lib/languageservice/serviceInstallerUtil');
// {{SQL CARBON EDIT}}
const serviceDownloader = require('service-downloader').ServiceDownloadProvider;
const platformInfo = require('service-downloader/out/platform').PlatformInformation;
const glob = require('glob');
const deps = require('./dependencies');
const getElectronVersion = require('./lib/electron').getElectronVersion;
const createAsar = require('./lib/asar').createAsar;
const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname));
// @ts-ignore
// {{SQL CARBON EDIT}}
var del = require('del');
const extensionsRoot = path.join(root, 'extensions');
@@ -55,16 +60,16 @@ const nodeModules = [
.concat(_.uniq(productionDependencies.map(d => d.name)))
.concat(baseModules);
// Build
const builtInExtensions = [
{ name: 'ms-vscode.node-debug', version: '1.19.8' },
{ name: 'ms-vscode.node-debug2', version: '1.19.4' }
];
// Build
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const builtInExtensions = require('./builtInExtensions.json');
const excludedExtensions = [
'vscode-api-tests',
'vscode-colorize-tests'
'vscode-colorize-tests',
'ms-vscode.node-debug',
'ms-vscode.node-debug2',
];
// {{SQL CARBON EDIT}}
@@ -103,7 +108,8 @@ const vscodeResources = [
'out-build/vs/workbench/parts/welcome/walkThrough/**/*.md',
'out-build/vs/workbench/services/files/**/*.exe',
'out-build/vs/workbench/services/files/**/*.md',
'out-build/vs/code/electron-browser/sharedProcess.js',
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
'out-build/vs/code/electron-browser/issue/issueReporter.js',
// {{SQL CARBON EDIT}}
'out-build/sql/workbench/electron-browser/splashscreen/*',
'out-build/sql/**/*.{svg,png,cur,html}',
@@ -133,10 +139,7 @@ const BUNDLED_FILE_HEADER = [
' *--------------------------------------------------------*/'
].join('\n');
var languages = ['chs', 'cht', 'jpn', 'kor', 'deu', 'fra', 'esn', 'rus', 'ita'];
if (process.env.VSCODE_QUALITY !== 'stable') {
languages = languages.concat(['ptb', 'hun', 'trk']); // Add languages requested by the community to non-stable builds
}
const languages = i18n.defaultLanguages.concat([]); // i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages : []);
gulp.task('clean-optimized-vscode', util.rimraf('out-vscode'));
gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compile-extensions-build'], common.optimizeTask({
@@ -146,7 +149,8 @@ gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compil
loaderConfig: common.loaderConfig(nodeModules),
header: BUNDLED_FILE_HEADER,
out: 'out-vscode',
languages: languages
languages: languages,
bundleInfo: undefined
}));
@@ -168,7 +172,7 @@ const config = {
version: getElectronVersion(),
productAppName: product.nameLong,
companyName: 'Microsoft Corporation',
copyright: 'Copyright (C) 2017 Microsoft. All rights reserved',
copyright: 'Copyright (C) 2018 Microsoft. All rights reserved',
darwinIcon: 'resources/darwin/code.icns',
darwinBundleIdentifier: product.darwinBundleIdentifier,
darwinApplicationCategoryType: 'public.app-category.developer-tools',
@@ -187,7 +191,7 @@ const config = {
name: product.nameLong,
urlSchemes: [product.urlProtocol]
}],
darwinCredits: darwinCreditsTemplate ? new Buffer(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : void 0,
darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : void 0,
linuxExecutableName: product.applicationName,
winIcon: 'resources/win32/code.ico',
token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || void 0,
@@ -325,16 +329,12 @@ function packageTask(platform, arch, opts) {
const localExtensionDependencies = gulp.src(extensionDepsSrc, { base: '.', dot: true })
.pipe(filter(['**', '!**/package-lock.json']))
.pipe(util.cleanNodeModule('account-provider-azure', ['node_modules/date-utils/doc/**', 'node_modules/adal_node/node_modules/**'], undefined))
.pipe(util.cleanNodeModule('dataprotocol-client', ['node_modules/**', 'src/*.js'], undefined))
.pipe(util.cleanNodeModule('extensions-modules', ['node_modules/**', 'src/*.js'], undefined))
.pipe(util.cleanNodeModule('typescript', ['**/**'], undefined));
const sources = es.merge(src, localExtensions, localExtensionDependencies)
.pipe(util.setExecutableBit(['**/*.sh']))
.pipe(filter(['**',
'!**/*.js.map',
'!extensions/**/node_modules/**/{test, tests}/**',
'!extensions/**/node_modules/**/test.js']));
.pipe(filter(['**', '!**/*.js.map']));
let version = packageJson.version;
const quality = product.quality;
@@ -358,7 +358,7 @@ function packageTask(platform, arch, opts) {
// TODO the API should be copied to `out` during compile, not here
const api = gulp.src('src/vs/vscode.d.ts').pipe(rename('out/vs/vscode.d.ts'));
// {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}}
const dataApi = gulp.src('src/vs/data.d.ts').pipe(rename('out/sql/data.d.ts'));
const depsSrc = [
@@ -372,6 +372,7 @@ function packageTask(platform, arch, opts) {
.pipe(util.cleanNodeModule('oniguruma', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/*.js']))
.pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('native-is-elevated', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('spdlog', ['binding.gyp', 'build/**', 'deps/**', 'src/**', 'test/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('jschardet', ['dist/**']))
@@ -379,18 +380,27 @@ function packageTask(platform, arch, opts) {
.pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js']))
.pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.exe', 'build/Release/*.dll', 'build/Release/*.node']))
// {{SQL CARBON EDIT}}
.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.node', 'build/Release/*.dll', 'build/Release/*.exe']))
.pipe(util.cleanNodeModule('chart.js', ['node_modules/**'], undefined))
.pipe(util.cleanNodeModule('emmet', ['node_modules/**'], undefined))
.pipe(util.cleanNodeModule('pty.js', ['build/**'], ['build/Release/**']))
.pipe(util.cleanNodeModule('jquery-ui', ['external/**', 'demos/**'], undefined))
.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('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']));
.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'));
// {{SQL CARBON EDIT}}
let copiedModules = gulp.src([
'node_modules/jquery/**/*.*',
'node_modules/reflect-metadata/**/*.*',
'node_modules/slickgrid/**/*.*',
'node_modules/underscore/**/*.*',
'node_modules/zone.js/**/*.*',
'node_modules/chart.js/**/*.*'
], { base: '.', dot: true });
let all = es.merge(
packageJsonStream,
@@ -398,7 +408,8 @@ function packageTask(platform, arch, opts) {
license,
watermark,
api,
// {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}}
copiedModules,
dataApi,
sources,
deps
@@ -469,25 +480,21 @@ gulp.task('vscode-linux-x64-min', ['minify-vscode', 'clean-vscode-linux-x64'], p
gulp.task('vscode-linux-arm-min', ['minify-vscode', 'clean-vscode-linux-arm'], packageTask('linux', 'arm', { minified: true }));
// Transifex Localizations
const vscodeLanguages = [
'zh-hans',
'zh-hant',
'ja',
'ko',
'de',
'fr',
'es',
'ru',
'it',
'pt-br',
'hu',
'tr'
];
const setupDefaultLanguages = [
'zh-hans',
'zh-hant',
'ko'
];
const innoSetupConfig = {
'zh-cn': { codePage: 'CP936', defaultInfo: { name: 'Simplified Chinese', id: '$0804', } },
'zh-tw': { codePage: 'CP950', defaultInfo: { name: 'Traditional Chinese', id: '$0404' } },
'ko': { codePage: 'CP949', defaultInfo: { name: 'Korean', id: '$0412' } },
'ja': { codePage: 'CP932' },
'de': { codePage: 'CP1252' },
'fr': { codePage: 'CP1252' },
'es': { codePage: 'CP1252' },
'ru': { codePage: 'CP1251' },
'it': { codePage: 'CP1252' },
'pt-br': { codePage: 'CP1252' },
'hu': { codePage: 'CP1250' },
'tr': { codePage: 'CP1254' }
};
const apiHostname = process.env.TRANSIFEX_API_URL;
const apiName = process.env.TRANSIFEX_API_NAME;
@@ -495,27 +502,50 @@ const apiToken = process.env.TRANSIFEX_API_TOKEN;
gulp.task('vscode-translations-push', ['optimize-vscode'], function () {
const pathToMetadata = './out-vscode/nls.metadata.json';
const pathToExtensions = './extensions/**/*.nls.json';
const pathToExtensions = './extensions/*';
const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}';
return es.merge(
gulp.src(pathToMetadata).pipe(i18n.prepareXlfFiles()),
gulp.src(pathToSetup).pipe(i18n.prepareXlfFiles()),
gulp.src(pathToExtensions).pipe(i18n.prepareXlfFiles('vscode-extensions'))
gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()),
gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()),
gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions())
).pipe(i18n.findObsoleteResources(apiHostname, apiName, apiToken)
).pipe(i18n.pushXlfFiles(apiHostname, apiName, apiToken));
});
gulp.task('vscode-translations-pull', function () {
gulp.task('vscode-translations-push-test', ['optimize-vscode'], function () {
const pathToMetadata = './out-vscode/nls.metadata.json';
const pathToExtensions = './extensions/*';
const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}';
return es.merge(
i18n.pullXlfFiles('vscode-editor', apiHostname, apiName, apiToken, vscodeLanguages),
i18n.pullXlfFiles('vscode-workbench', apiHostname, apiName, apiToken, vscodeLanguages),
i18n.pullXlfFiles('vscode-extensions', apiHostname, apiName, apiToken, vscodeLanguages),
i18n.pullXlfFiles('vscode-setup', apiHostname, apiName, apiToken, setupDefaultLanguages)
).pipe(vfs.dest('../vscode-localization'));
gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()),
gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()),
gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions())
).pipe(i18n.findObsoleteResources(apiHostname, apiName, apiToken)
).pipe(vfs.dest('../vscode-transifex-input'));
});
gulp.task('vscode-translations-pull', function () {
[...i18n.defaultLanguages, ...i18n.extraLanguages].forEach(language => {
i18n.pullCoreAndExtensionsXlfFiles(apiHostname, apiName, apiToken, language).pipe(vfs.dest(`../vscode-localization/${language.id}/build`));
let includeDefault = !!innoSetupConfig[language.id].defaultInfo;
i18n.pullSetupXlfFiles(apiHostname, apiName, apiToken, language, includeDefault).pipe(vfs.dest(`../vscode-localization/${language.id}/setup`));
});
});
gulp.task('vscode-translations-import', function () {
return gulp.src('../vscode-localization/**/*.xlf').pipe(i18n.prepareJsonFiles()).pipe(vfs.dest('./i18n'));
[...i18n.defaultLanguages, ...i18n.extraLanguages].forEach(language => {
gulp.src(`../vscode-localization/${language.id}/build/*/*.xlf`)
.pipe(i18n.prepareI18nFiles())
.pipe(vfs.dest(`./i18n/${language.folderName}`));
// {{SQL CARBON EDIT}}
// gulp.src(`../vscode-localization/${language.id}/setup/*/*.xlf`)
// .pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id]))
// .pipe(vfs.dest(`./build/win32/i18n`));
});
});
// Sourcemaps
@@ -541,7 +571,8 @@ gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], () => {
const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () => {
const branch = process.env.BUILD_SOURCEBRANCH;
if (!branch.endsWith('/master') && branch.indexOf('/release/') < 0) {
if (!/\/master$/.test(branch) && branch.indexOf('/release/') < 0) {
console.log(`Only runs on master and release branches, not ${branch}`);
return;
}
@@ -636,6 +667,7 @@ function versionStringToNumber(versionStr) {
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) => {
const buildDir = process.env['AGENT_BUILDDIRECTORY'];
@@ -645,7 +677,8 @@ gulp.task('generate-vscode-configuration', () => {
const userDataDir = path.join(os.tmpdir(), 'tmpuserdata');
const extensionsDir = path.join(os.tmpdir(), 'tmpextdir');
const appPath = path.join(buildDir, 'VSCode-darwin/Visual\\ Studio\\ Code\\ -\\ Insiders.app/Contents/Resources/app/bin/code');
const appName = process.env.VSCODE_QUALITY === 'insider' ? 'Visual\\ Studio\\ Code\\ -\\ Insiders.app' : 'Visual\\ Studio\\ Code.app';
const appPath = path.join(buildDir, `VSCode-darwin/${appName}/Contents/Resources/app/bin/code`);
const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`);
const timer = setTimeout(() => {
@@ -674,27 +707,25 @@ gulp.task('generate-vscode-configuration', () => {
// {{SQL CARBON EDIT}}
// Install service locally before building carbon
function installService(extObj, path) {
var installer = new serviceInstaller.ServiceInstaller(extObj, path);
installer.getServiceInstallDirectoryRoot().then(serviceInstallFolder => {
console.log('Cleaning up the install folder: ' + serviceInstallFolder);
del(serviceInstallFolder + '/*').then(() => {
console.log('Installing the service. Install folder: ' + serviceInstallFolder);
installer.installService();
}, delError => {
console.log('failed to delete the install folder error: ' + delError);
});
}, getFolderPathError => {
console.log('failed to call getServiceInstallDirectoryRoot error: ' + getFolderPathError);
function installService() {
let config = require('../extensions/mssql/src/config.json');
return platformInfo.getCurrent().then(p => {
let runtime = p.runtimeId;
// fix path since it won't be correct
config.installDirectory = path.join(__dirname, '../extensions/mssql/src', config.installDirectory);
var installer = new serviceDownloader(config);
let serviceInstallFolder = installer.getInstallDirectory(runtime);
console.log('Cleaning up the install folder: ' + serviceInstallFolder);
return del(serviceInstallFolder + '/*').then(() => {
console.log('Installing the service. Install folder: ' + serviceInstallFolder);
return installer.installService(runtime);
}, delError => {
console.log('failed to delete the install folder error: ' + delError);
});
});
}
gulp.task('install-sqltoolsservice', () => {
var mssqlExt = require('../extensions/mssql/client/out/models/constants');
var extObj = new mssqlExt.Constants();
var path = '../extensions/mssql/client/out/config.json';
return installService(extObj, path);
return installService();
});

View File

@@ -12,9 +12,12 @@ const shell = require('gulp-shell');
const es = require('event-stream');
const vfs = require('vinyl-fs');
const util = require('./lib/util');
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const packageJson = require('../package.json');
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const product = require('../product.json');
const rpmDependencies = require('../resources/linux/rpm/dependencies');
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const rpmDependencies = require('../resources/linux/rpm/dependencies.json');
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
@@ -111,8 +114,7 @@ function buildDebPackage(arch) {
return shell.task([
'chmod 755 ' + product.applicationName + '-' + debArch + '/DEBIAN/postinst ' + product.applicationName + '-' + debArch + '/DEBIAN/prerm ' + product.applicationName + '-' + debArch + '/DEBIAN/postrm',
'mkdir -p deb',
'fakeroot dpkg-deb -b ' + product.applicationName + '-' + debArch + ' deb',
'dpkg-scanpackages deb /dev/null > Packages'
'fakeroot dpkg-deb -b ' + product.applicationName + '-' + debArch + ' deb'
], { cwd: '.build/linux/deb/' + debArch });
}
@@ -220,10 +222,10 @@ function prepareSnapPackage(arch) {
function buildSnapPackage(arch) {
const snapBuildPath = getSnapBuildPath(arch);
const snapFilename = `${product.applicationName}-${packageJson.version}-${linuxPackageRevision}-${arch}.snap`;
return shell.task([
`chmod +x ${snapBuildPath}/electron-launch`,
`cd ${snapBuildPath} && snapcraft snap`
`cd ${snapBuildPath} && snapcraft snap --output ../${snapFilename}`
]);
}

View File

@@ -11,8 +11,11 @@ const assert = require('assert');
const cp = require('child_process');
const _7z = require('7zip')['7z'];
const util = require('./lib/util');
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const pkg = require('../package.json');
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const product = require('../product.json');
const vfs = require('vinyl-fs');
const repoPath = path.dirname(__dirname);
// {{SQL CARBON EDIT}}
@@ -91,3 +94,13 @@ gulp.task('vscode-win32-ia32-archive', ['clean-vscode-win32-ia32-archive'], arch
gulp.task('clean-vscode-win32-x64-archive', util.rimraf(zipDir('x64')));
gulp.task('vscode-win32-x64-archive', ['clean-vscode-win32-x64-archive'], archiveWin32Setup('x64'));
function copyInnoUpdater(arch) {
return () => {
return gulp.src('build/win32/{inno_updater.exe,vcruntime140.dll}', { base: 'build/win32' })
.pipe(vfs.dest(path.join(buildPath(arch), 'tools')));
};
}
gulp.task('vscode-win32-ia32-copy-inno-updater', copyInnoUpdater('ia32'));
gulp.task('vscode-win32-x64-copy-inno-updater', copyInnoUpdater('x64'));

118
build/lib/asar.js Normal file
View File

@@ -0,0 +1,118 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
var path = require("path");
var es = require("event-stream");
var pickle = require("chromium-pickle-js");
var Filesystem = require("asar/lib/filesystem");
var VinylFile = require("vinyl");
var minimatch = require("minimatch");
function createAsar(folderPath, unpackGlobs, destFilename) {
var shouldUnpackFile = function (file) {
for (var i = 0; i < unpackGlobs.length; i++) {
if (minimatch(file.relative, unpackGlobs[i])) {
return true;
}
}
return false;
};
var filesystem = new Filesystem(folderPath);
var out = [];
// Keep track of pending inserts
var pendingInserts = 0;
var onFileInserted = function () { pendingInserts--; };
// Do not insert twice the same directory
var seenDir = {};
var insertDirectoryRecursive = function (dir) {
if (seenDir[dir]) {
return;
}
var lastSlash = dir.lastIndexOf('/');
if (lastSlash === -1) {
lastSlash = dir.lastIndexOf('\\');
}
if (lastSlash !== -1) {
insertDirectoryRecursive(dir.substring(0, lastSlash));
}
seenDir[dir] = true;
filesystem.insertDirectory(dir);
};
var insertDirectoryForFile = function (file) {
var lastSlash = file.lastIndexOf('/');
if (lastSlash === -1) {
lastSlash = file.lastIndexOf('\\');
}
if (lastSlash !== -1) {
insertDirectoryRecursive(file.substring(0, lastSlash));
}
};
var insertFile = function (relativePath, stat, shouldUnpack) {
insertDirectoryForFile(relativePath);
pendingInserts++;
filesystem.insertFile(relativePath, shouldUnpack, { stat: stat }, {}, onFileInserted);
};
return es.through(function (file) {
if (file.stat.isDirectory()) {
return;
}
if (!file.stat.isFile()) {
throw new Error("unknown item in stream!");
}
var shouldUnpack = shouldUnpackFile(file);
insertFile(file.relative, { size: file.contents.length, mode: file.stat.mode }, shouldUnpack);
if (shouldUnpack) {
// The file goes outside of xx.asar, in a folder xx.asar.unpacked
var relative = path.relative(folderPath, file.path);
this.queue(new VinylFile({
cwd: folderPath,
base: folderPath,
path: path.join(destFilename + '.unpacked', relative),
stat: file.stat,
contents: file.contents
}));
}
else {
// The file goes inside of xx.asar
out.push(file.contents);
}
}, function () {
var _this = this;
var finish = function () {
{
var headerPickle = pickle.createEmpty();
headerPickle.writeString(JSON.stringify(filesystem.header));
var headerBuf = headerPickle.toBuffer();
var sizePickle = pickle.createEmpty();
sizePickle.writeUInt32(headerBuf.length);
var sizeBuf = sizePickle.toBuffer();
out.unshift(headerBuf);
out.unshift(sizeBuf);
}
var contents = Buffer.concat(out);
out.length = 0;
_this.queue(new VinylFile({
cwd: folderPath,
base: folderPath,
path: destFilename,
contents: contents
}));
_this.queue(null);
};
// Call finish() only when all file inserts have finished...
if (pendingInserts === 0) {
finish();
}
else {
onFileInserted = function () {
pendingInserts--;
if (pendingInserts === 0) {
finish();
}
};
}
});
}
exports.createAsar = createAsar;

131
build/lib/asar.ts Normal file
View File

@@ -0,0 +1,131 @@
/*---------------------------------------------------------------------------------------------
* 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 path from 'path';
import * as es from 'event-stream';
import * as pickle from 'chromium-pickle-js';
import * as Filesystem from 'asar/lib/filesystem';
import * as VinylFile from 'vinyl';
import * as minimatch from 'minimatch';
export function createAsar(folderPath: string, unpackGlobs: string[], destFilename: string): NodeJS.ReadWriteStream {
const shouldUnpackFile = (file: VinylFile): boolean => {
for (let i = 0; i < unpackGlobs.length; i++) {
if (minimatch(file.relative, unpackGlobs[i])) {
return true;
}
}
return false;
};
const filesystem = new Filesystem(folderPath);
const out: Buffer[] = [];
// Keep track of pending inserts
let pendingInserts = 0;
let onFileInserted = () => { pendingInserts--; };
// Do not insert twice the same directory
const seenDir: { [key: string]: boolean; } = {};
const insertDirectoryRecursive = (dir: string) => {
if (seenDir[dir]) {
return;
}
let lastSlash = dir.lastIndexOf('/');
if (lastSlash === -1) {
lastSlash = dir.lastIndexOf('\\');
}
if (lastSlash !== -1) {
insertDirectoryRecursive(dir.substring(0, lastSlash));
}
seenDir[dir] = true;
filesystem.insertDirectory(dir);
};
const insertDirectoryForFile = (file: string) => {
let lastSlash = file.lastIndexOf('/');
if (lastSlash === -1) {
lastSlash = file.lastIndexOf('\\');
}
if (lastSlash !== -1) {
insertDirectoryRecursive(file.substring(0, lastSlash));
}
};
const insertFile = (relativePath: string, stat: { size: number; mode: number; }, shouldUnpack: boolean) => {
insertDirectoryForFile(relativePath);
pendingInserts++;
filesystem.insertFile(relativePath, shouldUnpack, { stat: stat }, {}, onFileInserted);
};
return es.through(function (file) {
if (file.stat.isDirectory()) {
return;
}
if (!file.stat.isFile()) {
throw new Error(`unknown item in stream!`);
}
const shouldUnpack = shouldUnpackFile(file);
insertFile(file.relative, { size: file.contents.length, mode: file.stat.mode }, shouldUnpack);
if (shouldUnpack) {
// The file goes outside of xx.asar, in a folder xx.asar.unpacked
const relative = path.relative(folderPath, file.path);
this.queue(new VinylFile({
cwd: folderPath,
base: folderPath,
path: path.join(destFilename + '.unpacked', relative),
stat: file.stat,
contents: file.contents
}));
} else {
// The file goes inside of xx.asar
out.push(file.contents);
}
}, function () {
let finish = () => {
{
const headerPickle = pickle.createEmpty();
headerPickle.writeString(JSON.stringify(filesystem.header));
const headerBuf = headerPickle.toBuffer();
const sizePickle = pickle.createEmpty();
sizePickle.writeUInt32(headerBuf.length);
const sizeBuf = sizePickle.toBuffer();
out.unshift(headerBuf);
out.unshift(sizeBuf);
}
const contents = Buffer.concat(out);
out.length = 0;
this.queue(new VinylFile({
cwd: folderPath,
base: folderPath,
path: destFilename,
contents: contents
}));
this.queue(null);
};
// Call finish() only when all file inserts have finished...
if (pendingInserts === 0) {
finish();
} else {
onFileInserted = () => {
pendingInserts--;
if (pendingInserts === 0) {
finish();
}
};
}
});
}

View File

@@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const mkdirp = require('mkdirp');
const rimraf = require('rimraf');
const es = require('event-stream');
const rename = require('gulp-rename');
const vfs = require('vinyl-fs');
const ext = require('./extensions');
const util = require('gulp-util');
const root = path.dirname(path.dirname(__dirname));
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const builtInExtensions = require('../builtInExtensions.json');
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
function getExtensionPath(extension) {
return path.join(root, '.build', 'builtInExtensions', extension.name);
}
function isUpToDate(extension) {
const packagePath = path.join(getExtensionPath(extension), 'package.json');
if (!fs.existsSync(packagePath)) {
return false;
}
const packageContents = fs.readFileSync(packagePath, { encoding: 'utf8' });
try {
const diskVersion = JSON.parse(packageContents).version;
return (diskVersion === extension.version);
} catch (err) {
return false;
}
}
function syncMarketplaceExtension(extension) {
if (isUpToDate(extension)) {
util.log(util.colors.blue('[marketplace]'), `${extension.name}@${extension.version}`, util.colors.green('✔︎'));
return es.readArray([]);
}
rimraf.sync(getExtensionPath(extension));
return ext.fromMarketplace(extension.name, extension.version)
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`))
.pipe(vfs.dest('.build/builtInExtensions'))
.on('end', () => util.log(util.colors.blue('[marketplace]'), extension.name, util.colors.green('✔︎')));
}
function syncExtension(extension, controlState) {
switch (controlState) {
case 'disabled':
util.log(util.colors.blue('[disabled]'), util.colors.gray(extension.name));
return es.readArray([]);
case 'marketplace':
return syncMarketplaceExtension(extension);
default:
if (!fs.existsSync(controlState)) {
util.log(util.colors.red(`Error: Built-in extension '${extension.name}' is configured to run from '${controlState}' but that path does not exist.`));
return es.readArray([]);
} else if (!fs.existsSync(path.join(controlState, 'package.json'))) {
util.log(util.colors.red(`Error: Built-in extension '${extension.name}' is configured to run from '${controlState}' but there is no 'package.json' file in that directory.`));
return es.readArray([]);
}
util.log(util.colors.blue('[local]'), `${extension.name}: ${util.colors.cyan(controlState)}`, util.colors.green('✔︎'));
return es.readArray([]);
}
}
function readControlFile() {
try {
return JSON.parse(fs.readFileSync(controlFilePath, 'utf8'));
} catch (err) {
return {};
}
}
function writeControlFile(control) {
mkdirp.sync(path.dirname(controlFilePath));
fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2));
}
function main() {
util.log('Syncronizing built-in extensions...');
util.log(`You can manage built-in extensions with the ${util.colors.cyan('--builtin')} flag`);
const control = readControlFile();
const streams = [];
for (const extension of builtInExtensions) {
let controlState = control[extension.name] || 'marketplace';
control[extension.name] = controlState;
streams.push(syncExtension(extension, controlState));
}
writeControlFile(control);
es.merge(streams)
.on('error', err => {
console.error(err);
process.exit(1);
})
.on('end', () => {
process.exit(0);
});
}
main();

View File

@@ -217,6 +217,7 @@ function removeDuplicateTSBoilerplate(destFiles) {
{ start: /^var __metadata/, end: /^};$/ },
{ start: /^var __param/, end: /^};$/ },
{ start: /^var __awaiter/, end: /^};$/ },
{ start: /^var __generator/, end: /^};$/ },
];
destFiles.forEach(function (destFile) {
var SEEN_BOILERPLATE = [];

View File

@@ -44,11 +44,11 @@ interface ILoaderPluginReqFunc {
export interface IEntryPoint {
name: string;
include: string[];
exclude: string[];
include?: string[];
exclude?: string[];
prepend: string[];
append: string[];
dest: string;
append?: string[];
dest?: string;
}
interface IEntryPointMap {
@@ -339,6 +339,7 @@ function removeDuplicateTSBoilerplate(destFiles: IConcatFile[]): IConcatFile[] {
{ start: /^var __metadata/, end: /^};$/ },
{ start: /^var __param/, end: /^};$/ },
{ start: /^var __awaiter/, end: /^};$/ },
{ start: /^var __generator/, end: /^};$/ },
];
destFiles.forEach((destFile) => {

View File

@@ -22,6 +22,9 @@ 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']) {
options.sourceMap = false;
}
options.rootDir = rootDir;
options.sourceRoot = util.toFileUri(rootDir);
function createCompile(build, emitError) {
@@ -58,9 +61,13 @@ function compileTask(out, build) {
return function () {
var compile = createCompile(build, true);
var src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src('node_modules/typescript/lib/lib.d.ts'));
// Do not write .d.ts files to disk, as they are not needed there.
var dtsFilter = util.filter(function (data) { return !/\.d\.ts$/.test(data.path); });
return src
.pipe(compile())
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, false));
};
}
@@ -70,54 +77,19 @@ function watchTask(out, build) {
var compile = createCompile(build);
var src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src('node_modules/typescript/lib/lib.d.ts'));
var watchSrc = watch('src/**', { base: 'src' });
// Do not write .d.ts files to disk, as they are not needed there.
var dtsFilter = util.filter(function (data) { return !/\.d\.ts$/.test(data.path); });
return watchSrc
.pipe(util.incremental(compile, src, true))
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, true));
};
}
exports.watchTask = watchTask;
function reloadTypeScriptNodeModule() {
var util = require('gulp-util');
function log(message) {
var rest = [];
for (var _i = 1; _i < arguments.length; _i++) {
rest[_i - 1] = arguments[_i];
}
util.log.apply(util, [util.colors.cyan('[memory watch dog]'), message].concat(rest));
}
function heapUsed() {
return (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2) + ' MB';
}
return es.through(function (data) {
this.emit('data', data);
}, function () {
log('memory usage after compilation finished: ' + heapUsed());
// It appears we are running into some variant of
// https://bugs.chromium.org/p/v8/issues/detail?id=2073
//
// Even though all references are dropped, some
// optimized methods in the TS compiler end up holding references
// to the entire TypeScript language host (>600MB)
//
// The idea is to force v8 to drop references to these
// optimized methods, by "reloading" the typescript node module
log('Reloading typescript node module...');
var resolvedName = require.resolve('typescript');
var originalModule = require.cache[resolvedName];
delete require.cache[resolvedName];
var newExports = require('typescript');
require.cache[resolvedName] = originalModule;
for (var prop in newExports) {
if (newExports.hasOwnProperty(prop)) {
originalModule.exports[prop] = newExports[prop];
}
}
log('typescript node module reloaded.');
this.emit('end');
});
}
function monacodtsTask(out, isWatch) {
var basePath = path.resolve(process.cwd(), out);
var neededFiles = {};
monacodts.getFilesToWatch(out).forEach(function (filePath) {
filePath = path.normalize(filePath);
@@ -160,7 +132,7 @@ function monacodtsTask(out, isWatch) {
}));
}
resultStream = es.through(function (data) {
var filePath = path.normalize(data.path);
var filePath = path.normalize(path.resolve(basePath, data.relative));
if (neededFiles[filePath]) {
setInputFile(filePath, data.contents.toString());
}

View File

@@ -25,6 +25,9 @@ const rootDir = path.join(__dirname, '../../src');
const options = require('../../src/tsconfig.json').compilerOptions;
options.verbose = false;
options.sourceMap = true;
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);
@@ -49,7 +52,6 @@ function createCompile(build: boolean, emitError?: boolean): (token?: util.ICanc
.pipe(tsFilter)
.pipe(util.loadSourcemaps())
.pipe(ts(token))
// .pipe(build ? reloadTypeScriptNodeModule() : es.through())
.pipe(noDeclarationsFilter)
.pipe(build ? nls() : es.through())
.pipe(noDeclarationsFilter.restore)
@@ -75,9 +77,14 @@ export function compileTask(out: string, build: boolean): () => NodeJS.ReadWrite
gulp.src('node_modules/typescript/lib/lib.d.ts'),
);
// Do not write .d.ts files to disk, as they are not needed there.
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
return src
.pipe(compile())
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, false));
};
}
@@ -93,62 +100,22 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt
);
const watchSrc = watch('src/**', { base: 'src' });
// Do not write .d.ts files to disk, as they are not needed there.
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
return watchSrc
.pipe(util.incremental(compile, src, true))
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, true));
};
}
function reloadTypeScriptNodeModule(): NodeJS.ReadWriteStream {
var util = require('gulp-util');
function log(message: any, ...rest: any[]): void {
util.log(util.colors.cyan('[memory watch dog]'), message, ...rest);
}
function heapUsed(): string {
return (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2) + ' MB';
}
return es.through(function (data) {
this.emit('data', data);
}, function () {
log('memory usage after compilation finished: ' + heapUsed());
// It appears we are running into some variant of
// https://bugs.chromium.org/p/v8/issues/detail?id=2073
//
// Even though all references are dropped, some
// optimized methods in the TS compiler end up holding references
// to the entire TypeScript language host (>600MB)
//
// The idea is to force v8 to drop references to these
// optimized methods, by "reloading" the typescript node module
log('Reloading typescript node module...');
var resolvedName = require.resolve('typescript');
var originalModule = require.cache[resolvedName];
delete require.cache[resolvedName];
var newExports = require('typescript');
require.cache[resolvedName] = originalModule;
for (var prop in newExports) {
if (newExports.hasOwnProperty(prop)) {
originalModule.exports[prop] = newExports[prop];
}
}
log('typescript node module reloaded.');
this.emit('end');
});
}
function monacodtsTask(out: string, isWatch: boolean): NodeJS.ReadWriteStream {
const basePath = path.resolve(process.cwd(), out);
const neededFiles: { [file: string]: boolean; } = {};
monacodts.getFilesToWatch(out).forEach(function (filePath) {
filePath = path.normalize(filePath);
@@ -196,7 +163,7 @@ function monacodtsTask(out: string, isWatch: boolean): NodeJS.ReadWriteStream {
}
resultStream = es.through(function (data) {
const filePath = path.normalize(data.path);
const filePath = path.normalize(path.resolve(basePath, data.relative));
if (neededFiles[filePath]) {
setInputFile(filePath, data.contents.toString());
}

File diff suppressed because it is too large Load Diff

View File

@@ -46,10 +46,6 @@
"name": "vs/workbench/parts/execution",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/explorers",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/extensions",
"project": "vscode-workbench"
@@ -71,7 +67,11 @@
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/nps",
"name": "vs/workbench/parts/localizations",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/logs",
"project": "vscode-workbench"
},
{
@@ -138,6 +138,10 @@
"name": "vs/workbench/parts/welcome",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/actions",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/configuration",
"project": "vscode-workbench"
@@ -146,6 +150,10 @@
"name": "vs/workbench/services/crashReporter",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/dialogs",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/editor",
"project": "vscode-workbench"
@@ -154,6 +162,10 @@
"name": "vs/workbench/services/extensions",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/jsonschemas",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/files",
"project": "vscode-workbench"
@@ -162,10 +174,6 @@
"name": "vs/workbench/services/keybinding",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/message",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/mode",
"project": "vscode-workbench"
@@ -193,10 +201,6 @@
{
"name": "vs/workbench/services/decorations",
"project": "vscode-workbench"
},
{
"name": "setup_messages",
"project": "vscode-workbench"
}
]
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -79,7 +79,7 @@ function isImportNode(node) {
function fileFrom(file, contents, path) {
if (path === void 0) { path = file.path; }
return new File({
contents: new Buffer(contents),
contents: Buffer.from(contents),
base: file.base,
cwd: file.cwd,
path: path

View File

@@ -131,7 +131,7 @@ module nls {
export function fileFrom(file: File, contents: string, path: string = file.path) {
return new File({
contents: new Buffer(contents),
contents: Buffer.from(contents),
base: file.base,
cwd: file.cwd,
path: path

View File

@@ -59,7 +59,7 @@ function loader(bundledFileHeader, bundleLoader) {
this.emit('data', new VinylFile({
path: 'fake',
base: '',
contents: new Buffer(bundledFileHeader)
contents: Buffer.from(bundledFileHeader)
}));
this.emit('data', data);
}
@@ -98,7 +98,7 @@ function toConcatStream(bundledFileHeader, sources, dest) {
return new VinylFile({
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
base: base,
contents: new Buffer(source.contents)
contents: Buffer.from(source.contents)
});
});
return es.readArray(treatedSources)
@@ -141,7 +141,7 @@ function optimizeTask(opts) {
bundleInfoArray.push(new VinylFile({
path: 'bundleInfo.json',
base: '.',
contents: new Buffer(JSON.stringify(result.bundleData, null, '\t'))
contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t'))
}));
}
es.readArray(bundleInfoArray).pipe(bundleInfoStream);
@@ -174,7 +174,6 @@ function optimizeTask(opts) {
};
}
exports.optimizeTask = optimizeTask;
;
/**
* Wrap around uglify and allow the preserveComments function
* to have a file "context" to include our copyright only once per file.
@@ -237,4 +236,3 @@ function minifyTask(src, sourceMapBaseUrl) {
};
}
exports.minifyTask = minifyTask;
;

View File

@@ -31,7 +31,7 @@ function log(prefix: string, message: string): void {
}
// {{SQL CARBON EDIT}}
export function loaderConfig(emptyPaths: string[]) {
export function loaderConfig(emptyPaths?: string[]) {
const result = {
paths: {
'vs': 'out-build/vs',
@@ -73,7 +73,7 @@ function loader(bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWr
this.emit('data', new VinylFile({
path: 'fake',
base: '',
contents: new Buffer(bundledFileHeader)
contents: Buffer.from(bundledFileHeader)
}));
this.emit('data', data);
} else {
@@ -117,7 +117,7 @@ function toConcatStream(bundledFileHeader: string, sources: bundle.IFile[], dest
return new VinylFile({
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
base: base,
contents: new Buffer(source.contents)
contents: Buffer.from(source.contents)
});
});
@@ -165,7 +165,7 @@ export interface IOptimizeTaskOpts {
/**
* (languages to process)
*/
languages: string[];
languages: i18n.Language[];
}
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
const entryPoints = opts.entryPoints;
@@ -201,7 +201,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
bundleInfoArray.push(new VinylFile({
path: 'bundleInfo.json',
base: '.',
contents: new Buffer(JSON.stringify(result.bundleData, null, '\t'))
contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t'))
}));
}
es.readArray(bundleInfoArray).pipe(bundleInfoStream);
@@ -241,7 +241,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
}))
.pipe(gulp.dest(out));
};
};
}
declare class FileWithCopyright extends VinylFile {
public __hasOurCopyright: boolean;
@@ -295,7 +295,7 @@ function uglifyWithCopyrights(): NodeJS.ReadWriteStream {
return es.duplex(input, output);
}
export function minifyTask(src: string, sourceMapBaseUrl: string): (cb: any) => void {
export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => void {
const sourceMappingURL = sourceMapBaseUrl && (f => `${sourceMapBaseUrl}/${f.relative}.map`);
return cb => {
@@ -326,4 +326,4 @@ export function minifyTask(src: string, sourceMapBaseUrl: string): (cb: any) =>
cb(err);
});
};
};
}

View File

@@ -1,7 +1,14 @@
declare module "event-stream" {
import { Stream } from 'stream';
import { ThroughStream } from 'through';
import { ThroughStream as _ThroughStream} from 'through';
import { MapStream } from 'map-stream';
import * as File from 'vinyl';
export interface ThroughStream extends _ThroughStream {
queue(data: File | null);
push(data: File | null);
paused: boolean;
}
function merge(streams: Stream[]): ThroughStream;
function merge(...streams: Stream[]): ThroughStream;

View File

@@ -143,7 +143,7 @@ function loadSourcemaps() {
cb(null, f);
return;
}
f.contents = new Buffer(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
f.contents = Buffer.from(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
fs.readFile(path.join(path.dirname(f.path), lastMatch[1]), 'utf8', function (err, contents) {
if (err) {
return cb(err);
@@ -160,7 +160,7 @@ function stripSourceMappingURL() {
var output = input
.pipe(es.mapSync(function (f) {
var contents = f.contents.toString('utf8');
f.contents = new Buffer(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
f.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
return f;
}));
return es.duplex(input, output);
@@ -173,7 +173,6 @@ function rimraf(dir) {
if (!err) {
return cb();
}
;
if (err.code === 'ENOTEMPTY' && ++retries < 5) {
return setTimeout(function () { return retry(cb); }, 10);
}

View File

@@ -28,7 +28,7 @@ export interface IStreamProvider {
(cancellationToken?: ICancellationToken): NodeJS.ReadWriteStream;
}
export function incremental(streamProvider: IStreamProvider, initial: NodeJS.ReadWriteStream, supportsCancellation: boolean): NodeJS.ReadWriteStream {
export function incremental(streamProvider: IStreamProvider, initial: NodeJS.ReadWriteStream, supportsCancellation?: boolean): NodeJS.ReadWriteStream {
const input = es.through();
const output = es.through();
let state = 'idle';
@@ -129,7 +129,7 @@ export function skipDirectories(): NodeJS.ReadWriteStream {
});
}
export function cleanNodeModule(name: string, excludes: string[], includes: string[]): NodeJS.ReadWriteStream {
export function cleanNodeModule(name: string, excludes: string[], includes?: string[]): NodeJS.ReadWriteStream {
const toGlob = (path: string) => '**/node_modules/' + name + (path ? '/' + path : '');
const negate = (str: string) => '!' + str;
@@ -190,7 +190,7 @@ export function loadSourcemaps(): NodeJS.ReadWriteStream {
return;
}
f.contents = new Buffer(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
f.contents = Buffer.from(contents.replace(/\/\/# sourceMappingURL=(.*)$/g, ''), 'utf8');
fs.readFile(path.join(path.dirname(f.path), lastMatch[1]), 'utf8', (err, contents) => {
if (err) { return cb(err); }
@@ -209,7 +209,7 @@ export function stripSourceMappingURL(): NodeJS.ReadWriteStream {
const output = input
.pipe(es.mapSync<VinylFile, VinylFile>(f => {
const contents = (<Buffer>f.contents).toString('utf8');
f.contents = new Buffer(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
f.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
return f;
}));
@@ -223,7 +223,7 @@ export function rimraf(dir: string): (cb: any) => void {
_rimraf(dir, { maxBusyTries: 1 }, (err: any) => {
if (!err) {
return cb();
};
}
if (err.code === 'ENOTEMPTY' && ++retries < 5) {
return setTimeout(() => retry(cb), 10);

View File

@@ -9,7 +9,7 @@ const es = require('event-stream');
function handleDeletions() {
return es.mapSync(f => {
if (/\.ts$/.test(f.relative) && !f.contents) {
f.contents = new Buffer('');
f.contents = Buffer.from('');
f.stat = { mtime: new Date() };
}

View File

@@ -30,12 +30,12 @@ function watch(root) {
path: path,
base: root
});
//@ts-ignore
file.event = type;
result.emit('data', file);
}
nsfw(root, function(events) {
nsfw(root, function (events) {
for (var i = 0; i < events.length; i++) {
var e = events[i];
var changeType = e.action;
@@ -47,16 +47,16 @@ function watch(root) {
handleEvent(path.join(e.directory, e.file), toChangeType(changeType));
}
}
}).then(function(watcher) {
}).then(function (watcher) {
watcher.start();
});
});
return result;
return result;
}
var cache = Object.create(null);
module.exports = function(pattern, options) {
module.exports = function (pattern, options) {
options = options || {};
var cwd = path.normalize(options.cwd || process.cwd());
@@ -66,7 +66,7 @@ module.exports = function(pattern, options) {
watcher = cache[cwd] = watch(cwd);
}
var rebase = !options.base ? es.through() : es.mapSync(function(f) {
var rebase = !options.base ? es.through() : es.mapSync(function (f) {
f.base = options.base;
return f;
});
@@ -74,13 +74,13 @@ module.exports = function(pattern, options) {
return watcher
.pipe(filter(['**', '!.git{,/**}'])) // ignore all things git
.pipe(filter(pattern))
.pipe(es.map(function(file, cb) {
fs.stat(file.path, function(err, stat) {
.pipe(es.map(function (file, cb) {
fs.stat(file.path, function (err, stat) {
if (err && err.code === 'ENOENT') { return cb(null, file); }
if (err) { return cb(); }
if (!stat.isFile()) { return cb(); }
fs.readFile(file.path, function(err, contents) {
fs.readFile(file.path, function (err, contents) {
if (err && err.code === 'ENOENT') { return cb(null, file); }
if (err) { return cb(); }

View File

@@ -24,7 +24,8 @@ function watch(root) {
var result = es.through();
var child = cp.spawn(watcherPath, [root]);
child.stdout.on('data', function(data) {
child.stdout.on('data', function (data) {
// @ts-ignore
var lines = data.toString('utf8').split('\n');
for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim();
@@ -46,17 +47,17 @@ function watch(root) {
path: changePathFull,
base: root
});
//@ts-ignore
file.event = toChangeType(changeType);
result.emit('data', file);
}
});
child.stderr.on('data', function(data) {
child.stderr.on('data', function (data) {
result.emit('error', data);
});
child.on('exit', function(code) {
child.on('exit', function (code) {
result.emit('error', 'Watcher died with code ' + code);
child = null;
});
@@ -70,7 +71,7 @@ function watch(root) {
var cache = Object.create(null);
module.exports = function(pattern, options) {
module.exports = function (pattern, options) {
options = options || {};
var cwd = path.normalize(options.cwd || process.cwd());

View File

@@ -1 +1,21 @@
See project root directory
The Source EULA
Copyright (c) 2016 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
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.

View File

@@ -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 MIT license:
This software is released under the Source EULA:
Copyright (c) Joshaven Potter
@@ -60,7 +60,7 @@ END OF string_scorer NOTICES AND INFORMATION
%% chjj-marked NOTICES AND INFORMATION BEGIN HERE
=========================================
The MIT License (MIT)
The Source EULA
Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/)

View File

@@ -62,19 +62,24 @@ export interface ICommandHandler {
#include(vs/editor/standalone/browser/colorizer): IColorizerOptions, IColorizerElementOptions
#include(vs/base/common/scrollable): ScrollbarVisibility
#include(vs/platform/theme/common/themeService): ThemeColor
#includeAll(vs/editor/common/editorCommon;IMode=>languages.IMode;LanguageIdentifier=>languages.LanguageIdentifier;editorOptions.=>): ISelection, IScrollEvent
#includeAll(vs/editor/common/model;LanguageIdentifier=>languages.LanguageIdentifier): IScrollEvent
#includeAll(vs/editor/common/editorCommon;editorOptions.=>): IScrollEvent
#includeAll(vs/editor/common/model/textModelEvents):
#includeAll(vs/editor/common/controller/cursorEvents):
#includeAll(vs/editor/common/config/editorOptions):
#includeAll(vs/editor/browser/editorBrowser;editorCommon.=>;editorOptions.=>):
#include(vs/editor/common/config/fontInfo): FontInfo, BareFontInfo
//compatibility:
export type IReadOnlyModel = ITextModel;
export type IModel = ITextModel;
}
declare module monaco.languages {
#includeAll(vs/editor/standalone/browser/standaloneLanguages;modes.=>;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData):
#includeAll(vs/editor/standalone/browser/standaloneLanguages;modes.=>;editorCommon.=>editor.;model.=>editor.;IMarkerData=>editor.IMarkerData):
#includeAll(vs/editor/common/modes/languageConfiguration):
#includeAll(vs/editor/common/modes;editorCommon.IRange=>IRange;editorCommon.IPosition=>IPosition;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData):
#includeAll(vs/editor/common/modes;editorCommon.IRange=>IRange;editorCommon.IPosition=>IPosition;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData;model.=>editor.):
#include(vs/editor/common/services/modeService): ILanguageExtensionPoint
#includeAll(vs/editor/standalone/common/monarch/monarchTypes):

View File

@@ -21,16 +21,16 @@ function yarnInstall(location, opts) {
}
// {{SQL CARBON EDIT}}
yarnInstall('extensions-modules');
yarnInstall('extensions'); // node modules shared by all extensions
const extensions = [
'vscode-colorize-tests',
'json',
'mssql',
'mssql',
'configuration-editing',
'extension-editing',
'markdown',
'markdown-basics',
'git',
'merge-conflict',
'insights-default',
@@ -43,6 +43,7 @@ extensions.forEach(extension => yarnInstall(`extensions/${extension}`));
function yarnInstallBuildDependencies() {
// make sure we install the deps of build/lib/watch for the system installed
// node, since that is the driver of gulp
//@ts-ignore
const env = Object.assign({}, process.env);
const watchPath = path.join(path.dirname(__dirname), 'lib', 'watch');
const yarnrcPath = path.join(watchPath, '.yarnrc');
@@ -60,4 +61,5 @@ runtime "${runtime}"`;
}
yarnInstall(`build`); // node modules required for build
yarnInstall('test/smoke'); // node modules required for smoketest
yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron

View File

@@ -4,9 +4,11 @@
*--------------------------------------------------------------------------------------------*/
const cp = require('child_process');
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const fs = require('fs');
const path = require('path');
function updateGrammar(location) {
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const result = cp.spawnSync(npm, ['run', 'update-grammar'], {
cwd: location,
stdio: 'inherit'
@@ -17,50 +19,17 @@ function updateGrammar(location) {
}
}
const extensions = [
'bat',
'clojure',
'coffeescript',
'cpp',
'csharp',
'css',
'diff',
'docker',
'fsharp',
'gitsyntax',
'go',
'groovy',
'handlebars',
'hlsl',
'html',
'ini',
'java',
// 'javascript', updated through JavaScript
'json',
'less',
'lua',
'make',
'markdown',
'objective-c',
'perl',
'php',
// 'powershell', grammar not ready yet, @daviwil will ping when ready
'pug',
'python',
'r',
'razor',
'ruby',
'rust',
'scss',
'shaderlab',
'shellscript',
'sql',
'swift',
'typescript',
'vb',
'xml',
'yaml'
];
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.scripts && packageJSON.scripts['update-grammar'];
} catch (e) {
return false;
}
});
console.log(`Updating ${extensions.length} grammars...`);
extensions.forEach(extension => updateGrammar(`extensions/${extension}`));
@@ -70,4 +39,5 @@ if (process.platform === 'win32') {
cp.spawn('.\scripts\test-integration.bat', [], { env: process.env, stdio: 'inherit' });
} else {
cp.spawn('/bin/bash', ['./scripts/test-integration.sh'], { env: process.env, stdio: 'inherit' });
}
}

View File

@@ -14,14 +14,19 @@ var url = require('url');
function getOptions(urlString) {
var _url = url.parse(urlString);
var headers = {
'User-Agent': 'VSCode'
};
var token = process.env['GITHUB_TOKEN'];
if (token) {
headers['Authorization'] = 'token ' + token
}
return {
protocol: _url.protocol,
host: _url.host,
port: _url.port,
path: _url.path,
headers: {
'User-Agent': 'NodeJS'
}
headers: headers
};
}
@@ -32,12 +37,16 @@ function download(url, redirectCount) {
response.on('data', function (data) {
content += data.toString();
}).on('end', function () {
if (response.statusCode === 403 && response.headers['x-ratelimit-remaining'] === '0') {
e('GitHub API rate exceeded. Set GITHUB_TOKEN environment variable to increase rate limit.');
return;
}
let count = redirectCount || 0;
if (count < 5 && response.statusCode >= 300 && response.statusCode <= 303 || response.statusCode === 307) {
let location = response.headers['location'];
if (location) {
console.log("Redirected " + url + " to " + location);
download(location, count+1).then(c, e);
download(location, count + 1).then(c, e);
return;
}
}
@@ -59,17 +68,13 @@ function getCommitSha(repoId, repoPath) {
commitDate: lastCommit.commit.author.date
});
} catch (e) {
console.error("Failed extracting the SHA: " + content);
return Promise.resolve(null);
return Promise.reject(new Error("Failed extracting the SHA: " + content));
}
}, function () {
console.error('Failed loading ' + commitInfo);
return Promise.resolve(null);
});
}
exports.update = function (repoId, repoPath, dest, modifyGrammar) {
var contentPath = 'https://raw.githubusercontent.com/' + repoId + '/master/' + repoPath;
exports.update = function (repoId, repoPath, dest, modifyGrammar, version = 'master') {
var contentPath = 'https://raw.githubusercontent.com/' + repoId + `/${version}/` + repoPath;
console.log('Reading from ' + contentPath);
return download(contentPath).then(function (content) {
var ext = path.extname(repoPath);
@@ -81,8 +86,7 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) {
} else if (ext === '.json') {
grammar = JSON.parse(content);
} else {
console.error('Unknown file extension: ' + ext);
return;
return Promise.reject(new Error('Unknown file extension: ' + ext));
}
if (modifyGrammar) {
modifyGrammar(grammar);
@@ -99,8 +103,10 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) {
if (info) {
result.version = 'https://github.com/' + repoId + '/commit/' + info.commitSha;
}
for (let key in grammar) {
if (!result.hasOwnProperty(key)) {
let keys = ['name', 'scopeName', 'comment', 'injections', 'patterns', 'repository'];
for (let key of keys) {
if (grammar.hasOwnProperty(key)) {
result[key] = grammar[key];
}
}
@@ -113,11 +119,14 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) {
console.log('Updated ' + path.basename(dest));
}
} catch (e) {
console.error(e);
return Promise.reject(e);
}
});
}, console.error);
}, console.error).catch(e => {
console.error(e);
process.exit(1);
});
};
if (path.basename(process.argv[1]) === 'update-grammar.js') {

View File

@@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
let i18n = require("../lib/i18n");
let fs = require("fs");
let path = require("path");
let vfs = require("vinyl-fs");
let rimraf = require('rimraf');
function update(idOrPath) {
if (!idOrPath) {
throw new Error('Argument must be the location of the localization extension.');
}
let locExtFolder = idOrPath;
if (/^\w{2}(-\w+)?$/.test(idOrPath)) {
locExtFolder = '../vscode-language-pack-' + idOrPath;
}
let locExtStat = fs.statSync(locExtFolder);
if (!locExtStat || !locExtStat.isDirectory) {
throw new Error('No directory found at ' + idOrPath);
}
let packageJSON = JSON.parse(fs.readFileSync(path.join(locExtFolder, 'package.json')).toString());
let contributes = packageJSON['contributes'];
if (!contributes) {
throw new Error('The extension must define a "localizations" contribution in the "package.json"');
}
let localizations = contributes['localizations'];
if (!localizations) {
throw new Error('The extension must define a "localizations" contribution of type array in the "package.json"');
}
localizations.forEach(function (localization) {
if (!localization.languageId || !localization.languageName || !localization.localizedLanguageName) {
throw new Error('Each localization contribution must define "languageId", "languageName" and "localizedLanguageName" properties.');
}
let server = localization.server || 'www.transifex.com';
let userName = localization.userName || 'api';
let apiToken = process.env.TRANSIFEX_API_TOKEN;
let languageId = localization.transifexId || localization.languageId;
let translationDataFolder = path.join(locExtFolder, 'translations');
if (fs.existsSync(translationDataFolder) && fs.existsSync(path.join(translationDataFolder, 'main.i18n.json'))) {
console.log('Clearing \'' + translationDataFolder + '\'...');
rimraf.sync(translationDataFolder);
}
console.log('Downloading translations for \'' + languageId + '\' to \'' + translationDataFolder + '\'...');
const translationPaths = [];
i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths)
.pipe(vfs.dest(translationDataFolder)).on('end', function () {
localization.translations = [];
for (let tp of translationPaths) {
localization.translations.push({ id: tp.id, path: `./translations/${tp.resourceName}`});
}
fs.writeFileSync(path.join(locExtFolder, 'package.json'), JSON.stringify(packageJSON, null, '\t'));
});
});
}
if (path.basename(process.argv[1]) === 'update-localization-extension.js') {
update(process.argv[2]);
}

View File

@@ -12,17 +12,18 @@
"azure-storage": "^2.1.0",
"decompress": "^4.2.0",
"documentdb": "1.13.0",
"extensions-modules": "file:../extensions-modules",
"service-downloader": "github:anthonydresser/service-downloader#0.1.2",
"fs-extra-promise": "^1.0.1",
"mime": "^1.3.4",
"minimist": "^1.2.0",
"typescript": "2.6.1",
"vscode": "^1.0.1",
"vscode": "^1.0.1",
"xml2js": "^0.4.17"
},
"scripts": {
"compile": "tsc",
"watch": "tsc --watch",
"postinstall": "npm run compile"
"compile": "tsc -p tsconfig.build.json",
"watch": "tsc -p tsconfig.build.json --watch",
"postinstall": "npm run compile",
"npmCheckJs": "tsc --noEmit"
}
}

View File

@@ -4,9 +4,9 @@ set -e
# setup nvm
if [[ "$OSTYPE" == "darwin"* ]]; then
export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh
source $(brew --prefix nvm)/nvm.sh --no-use
else
source $NVM_DIR/nvm.sh
source $NVM_DIR/nvm.sh --no-use
fi
# install node

View File

@@ -70,6 +70,7 @@ interface Asset {
hash: string;
sha256hash: string;
size: number;
supportsFastUpdate?: boolean;
}
function createOrUpdate(commit: string, quality: string, platform: string, type: string, release: NewDocument, asset: Asset, isUpdate: boolean): Promise<void> {
@@ -203,17 +204,30 @@ async function publish(commit: string, quality: string, platform: string, type:
// mooncake is fussy and far away, this is needed!
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
await assertContainer(mooncakeBlobService, quality);
await Promise.all([
assertContainer(blobService, quality),
assertContainer(mooncakeBlobService, quality)
]);
const mooncakeBlobExists = await doesAssetExist(mooncakeBlobService, quality, blobName);
const [blobExists, moooncakeBlobExists] = await Promise.all([
doesAssetExist(blobService, quality, blobName),
doesAssetExist(mooncakeBlobService, quality, blobName)
]);
if (!mooncakeBlobExists) {
const promises = [];
if (!blobExists) {
promises.push(uploadBlob(blobService, quality, blobName, file));
}
if (!moooncakeBlobExists) {
promises.push(uploadBlob(mooncakeBlobService, quality, blobName, file));
}
} else {
console.log('Skipping Mooncake publishing.');
}
if (promises.length === 0) {
console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`);
return;
@@ -240,6 +254,13 @@ async function publish(commit: string, quality: string, platform: string, type:
size
};
// Remove this if we ever need to rollback fast updates for windows
if (/win32/.test(platform)) {
asset.supportsFastUpdate = true;
}
console.log('Asset:', JSON.stringify(asset, null, ' '));
const release = {
id: commit,
timestamp: (new Date()).getTime(),

View File

@@ -19,6 +19,9 @@ step "Install dependencies" \
step "Hygiene" \
npm run gulp -- hygiene
step "Monaco Editor Check" \
./node_modules/.bin/tsc -p ./src/tsconfig.monaco.json --noEmit
step "Mix in repository from vscode-distro" \
npm run gulp -- mixin

View File

@@ -22,6 +22,9 @@ step "Install dependencies" \
step "Hygiene" \
npm run gulp -- hygiene
step "Monaco Editor Check" \
./node_modules/.bin/tsc -p ./src/tsconfig.monaco.json --noEmit
step "Mix in repository from vscode-distro" \
npm run gulp -- mixin

View File

@@ -24,6 +24,10 @@ step "Hygiene" {
exec { & npm run gulp -- hygiene }
}
step "Monaco Editor Check" {
exec { & .\node_modules\.bin\tsc -p .\src\tsconfig.monaco.json --noEmit }
}
$env:VSCODE_MIXIN_PASSWORD = $mixinPassword
step "Mix in repository from vscode-distro" {
exec { & npm run gulp -- mixin }
@@ -41,6 +45,10 @@ step "Build minified" {
exec { & npm run gulp -- "vscode-win32-$global:arch-min" }
}
step "Copy Inno updater" {
exec { & npm run gulp -- "vscode-win32-$global:arch-copy-inno-updater" }
}
# step "Create loader snapshot" {
# exec { & node build\lib\snapshotLoader.js --arch=$global:arch }
# }

View File

@@ -1,7 +1,7 @@
# install node
$env:Path = $env:NVM_HOME + ";" + $env:NVM_SYMLINK + ";" + $env:Path
$NodeVersion = "8.9.1"
nvm install $NodeVersion
nvm use $NodeVersion
npm install -g yarn
# nvm install $NodeVersion
# nvm use $NodeVersion
# npm install -g yarn
$env:Path = $env:NVM_HOME + "\v" + $NodeVersion + ";" + $env:Path

View File

@@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"allowJs": false,
"checkJs": false
}
}

View File

@@ -7,7 +7,12 @@
"preserveConstEnums": true,
"sourceMap": false,
"experimentalDecorators": true,
"newLine": "LF"
"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
"allowJs": true,
"checkJs": true
},
"exclude": [
"node_modules/**"

View File

@@ -9,5 +9,6 @@
"always"
],
"triple-equals": true
}
},
"defaultSeverity": "warning"
}

1794
build/win32/OSSREADME.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@ OutputDir={#OutputDir}
OutputBaseFilename=SqlOpsStudioSetup
Compression=lzma
SolidCompression=yes
AppMutex={#AppMutex}
AppMutex={code:GetAppMutex}
SetupMutex={#AppMutex}setup
WizardImageFile={#RepoDir}\resources\win32\inno-big.bmp
WizardSmallImageFile={#RepoDir}\resources\win32\inno-small.bmp
@@ -52,8 +52,13 @@ Type: filesandordirs; Name: "{app}\resources\app\out"; Check: IsNotUpdate
Type: filesandordirs; Name: "{app}\resources\app\plugins"; Check: IsNotUpdate
Type: filesandordirs; Name: "{app}\resources\app\extensions"; Check: IsNotUpdate
Type: filesandordirs; Name: "{app}\resources\app\node_modules"; Check: IsNotUpdate
Type: filesandordirs; Name: "{app}\resources\app\node_modules.asar.unpacked"; Check: IsNotUpdate
Type: files; Name: "{app}\resources\app\node_modules.asar"; Check: IsNotUpdate
Type: files; Name: "{app}\resources\app\Credits_45.0.2454.85.html"; Check: IsNotUpdate
[UninstallDelete]
Type: filesandordirs; Name: "{app}\_"
[Tasks]
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
Name: "addtopath"; Description: "{cm:AddToPath}"; GroupDescription: "{cm:Other}"
@@ -138,6 +143,48 @@ begin
Result := True;
end;
function GetAppMutex(Value: string): string;
begin
if IsBackgroundUpdate() then
Result := ''
else
Result := '{#AppMutex}';
end;
function GetDestDir(Value: string): string;
begin
if IsBackgroundUpdate() then
Result := ExpandConstant('{app}\_')
else
Result := ExpandConstant('{app}');
end;
function BoolToStr(Value: Boolean): String;
begin
if Value then
Result := 'true'
else
Result := 'false';
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
UpdateResultCode: Integer;
begin
if IsBackgroundUpdate() and (CurStep = ssPostInstall) then
begin
CreateMutex('{#AppMutex}-ready');
while (CheckForMutexes('{#AppMutex}')) do
begin
Log('Application is still running, waiting');
Sleep(1000);
end;
Exec(ExpandConstant('{app}\tools\inno_updater.exe'), ExpandConstant('"{app}\{#ExeBasename}.exe" ' + BoolToStr(LockFileExists())), '', SW_SHOW, ewWaitUntilTerminated, UpdateResultCode);
end;
end;
// http://stackoverflow.com/a/23838239/261019
procedure Explode(var Dest: TArrayOfString; Text: String; Separator: String);
var

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
node_modules
lib
*.log

View File

@@ -1,9 +0,0 @@
.vscode/
lib/test/
lib/**/*.map
src/
test/
.eslintrc
.gitignore
gulpfile.js
tsd.json

View File

@@ -1,32 +0,0 @@
{
"name": "extensions-modules",
"version": "0.1.0",
"description": "Shared modules for SQL Operations Studio extensions",
"dependencies": {
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.1.5",
"decompress": "^4.2.0",
"fs-extra-promise": "^1.0.1",
"http-proxy-agent": "^2.0.0",
"https-proxy-agent": "^2.1.0",
"opener": "^1.4.3",
"tmp": "0.0.33",
"vscode-extension-telemetry": "0.0.8",
"vscode-languageclient": "3.5.0"
},
"devDependencies": {
"@types/node": "^6.0.61",
"vscode": "^1.1.10",
"sqlops": "github:anthonydresser/vscode-extension-vscode"
},
"scripts": {
"prepare": "node ./node_modules/vscode/bin/install && node ./node_modules/sqlops/bin/install && tsc -p ./src",
"compile": "tsc -p ./src",
"watch": "tsc -w -p ./src"
},
"engines": {
"vscode": "*",
"sqlops": "*"
},
"main": "./lib/main.js",
"typings": "./lib/main"
}

View File

@@ -1,89 +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';
const fs = require('fs');
import * as path from 'path';
import { IConfig } from '../languageservice/interfaces';
import { Constants } from '../models/constants';
/*
* Config class handles getting values from config.json.
*/
export default class Config implements IConfig {
private _configJsonContent: any = undefined;
private _extensionConfigSectionName: string = undefined;
private _fromBuild: boolean = undefined;
constructor(extensionConfigSectionName: string, private path: string, fromBuild?: boolean) {
this._extensionConfigSectionName = extensionConfigSectionName;
this._fromBuild = fromBuild;
}
public get configJsonContent(): any {
if (this._configJsonContent === undefined) {
this._configJsonContent = this.loadConfig();
}
return this._configJsonContent;
}
public getDownloadUrl(): string {
return this.getConfigValue(Constants.downloadUrlConfigKey);
}
public getInstallDirectory(): string {
return this.getConfigValue(Constants.installDirConfigKey);
}
public getExecutableFiles(): string[] {
return this.getConfigValue(Constants.executableFilesConfigKey);
}
public getPackageVersion(): string {
return this.getConfigValue(Constants.versionConfigKey);
}
public getConfigValue(configKey: string): any {
let json = this.configJsonContent;
let toolsConfig = json[Constants.serviceConfigKey];
let configValue: string = undefined;
if (toolsConfig !== undefined) {
configValue = toolsConfig[configKey];
}
return configValue;
}
public getExtensionConfig(key: string, defaultValue?: any): any {
let json = this.configJsonContent;
let extensionConfig = json[this._extensionConfigSectionName];
let configValue = extensionConfig[key];
if (!configValue) {
configValue = defaultValue;
}
return configValue;
}
public getWorkspaceConfig(key: string, defaultValue?: any): any {
let json = this.configJsonContent;
let configValue = json[key];
if (!configValue) {
configValue = defaultValue;
}
return configValue;
}
public loadConfig(): any {
let configContent = undefined;
if (this._fromBuild) {
let remainingPath = '../../../extensions/' + this._extensionConfigSectionName + '/client/out/config.json';
configContent = fs.readFileSync(path.join(__dirname, remainingPath));
}
else {
configContent = fs.readFileSync(this.path);
}
return JSON.parse(configContent);
}
}

View File

@@ -1,76 +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 Config from './config';
import { workspace, WorkspaceConfiguration } from 'vscode';
import { IConfig } from '../languageservice/interfaces';
import { Constants } from '../models/constants';
/*
* ExtConfig class handles getting values from workspace config or config.json.
*/
export default class ExtConfig implements IConfig {
constructor(private _extensionConfigSectionName: string, private _config?: IConfig,
path?: string,
private _extensionConfig?: WorkspaceConfiguration,
private _workspaceConfig?: WorkspaceConfiguration) {
if (this._config === undefined) {
this._config = new Config(_extensionConfigSectionName, path);
}
if (this._extensionConfig === undefined) {
this._extensionConfig = workspace.getConfiguration(_extensionConfigSectionName);
}
if (this._workspaceConfig === undefined) {
this._workspaceConfig = workspace.getConfiguration();
}
}
public getDownloadUrl(): string {
return this.getConfigValue(Constants.downloadUrlConfigKey);
}
public getInstallDirectory(): string {
return this.getConfigValue(Constants.installDirConfigKey);
}
public getExecutableFiles(): string[] {
return this.getConfigValue(Constants.executableFilesConfigKey);
}
public getPackageVersion(): string {
return this.getConfigValue(Constants.versionConfigKey);
}
public getConfigValue(configKey: string): any {
let configValue: string = <string>this.getExtensionConfig(`${Constants.serviceConfigKey}.${configKey}`);
if (!configValue) {
configValue = this._config.getConfigValue(configKey);
}
return configValue;
}
public getExtensionConfig(key: string, defaultValue?: any): any {
let configValue = this._extensionConfig.get(key);
if (configValue === undefined) {
configValue = defaultValue;
}
return configValue;
}
public getWorkspaceConfig(key: string, defaultValue?: any): any {
let configValue = this._workspaceConfig.get(key);
if (configValue === undefined) {
configValue = defaultValue;
}
return configValue;
}
public updateWorkspaceConfig(configKey: string, configValue: any) {
this._workspaceConfig.update(configKey, configValue, true);
}
}

View File

@@ -1,278 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import vscode = require('vscode');
import { IExtensionConstants } from '../models/contracts/contracts';
export class VscodeWrapper {
private _extensionConstants: IExtensionConstants;
/**
* Output channel for logging. Shared among all instances.
*/
private static _outputChannel: vscode.OutputChannel;
/**
* Default constructor.
*/
public constructor(constants: IExtensionConstants) {
this._extensionConstants = constants;
if (typeof VscodeWrapper._outputChannel === 'undefined') {
VscodeWrapper._outputChannel = this.createOutputChannel(this._extensionConstants.outputChannelName);
}
}
/**
* Get the current active text editor
*/
public get activeTextEditor(): vscode.TextEditor {
return vscode.window.activeTextEditor;
}
/**
* get the current textDocument; any that are open?
*/
public get textDocuments(): vscode.TextDocument[] {
return vscode.workspace.textDocuments;
}
/**
* Parse uri
*/
public parseUri(uri: string): vscode.Uri {
return vscode.Uri.parse(uri);
}
/**
* Get the URI string for the current active text editor
*/
public get activeTextEditorUri(): string {
if (typeof vscode.window.activeTextEditor !== 'undefined' &&
typeof vscode.window.activeTextEditor.document !== 'undefined') {
return vscode.window.activeTextEditor.document.uri.toString();
}
return undefined;
}
public get constants(): IExtensionConstants {
return this._extensionConstants;
}
/**
* Create an output channel in vscode.
*/
public createOutputChannel(channelName: string): vscode.OutputChannel {
return vscode.window.createOutputChannel(channelName);
}
/**
* Executes the command denoted by the given command identifier.
*
* When executing an editor command not all types are allowed to
* be passed as arguments. Allowed are the primitive types `string`, `boolean`,
* `number`, `undefined`, and `null`, as well as classes defined in this API.
* There are no restrictions when executing commands that have been contributed
* by extensions.
*
* @param command Identifier of the command to execute.
* @param rest Parameters passed to the command function.
* @return A thenable that resolves to the returned value of the given command. `undefined` when
* the command handler function doesn't return anything.
* @see vscode.commands.executeCommand
*/
public executeCommand<T>(command: string, ...rest: any[]): Thenable<T> {
return vscode.commands.executeCommand<T>(command, ...rest);
}
/**
* Get the configuration for a extensionName; NOT YET IMPLEMENTED
* @param extensionName The string name of the extension to get the configuration for
*/
public getConfiguration(extensionName: string): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(extensionName);
}
/**
* @return 'true' if the active editor window has a .sql file, false otherwise
*/
public get isEditingSqlFile(): boolean {
let sqlFile = false;
let editor = this.activeTextEditor;
if (editor) {
if (editor.document.languageId === this._extensionConstants.languageId) {
sqlFile = true;
}
}
return sqlFile;
}
/**
* An event that is emitted when a [text document](#TextDocument) is disposed.
*/
public get onDidCloseTextDocument(): vscode.Event<vscode.TextDocument> {
return vscode.workspace.onDidCloseTextDocument;
}
/**
* An event that is emitted when a [text document](#TextDocument) is opened.
*/
public get onDidOpenTextDocument(): vscode.Event<vscode.TextDocument> {
return vscode.workspace.onDidOpenTextDocument;
}
/**
* An event that is emitted when a [text document](#TextDocument) is saved to disk.
*/
public get onDidSaveTextDocument(): vscode.Event<vscode.TextDocument> {
return vscode.workspace.onDidSaveTextDocument;
}
/**
* Opens the denoted document from disk. Will return early if the
* document is already open, otherwise the document is loaded and the
* [open document](#workspace.onDidOpenTextDocument)-event fires.
* The document to open is denoted by the [uri](#Uri). Two schemes are supported:
*
* file: A file on disk, will be rejected if the file does not exist or cannot be loaded, e.g. `file:///Users/frodo/r.ini`.
* untitled: A new file that should be saved on disk, e.g. `untitled:c:\frodo\new.js`. The language will be derived from the file name.
*
* Uris with other schemes will make this method return a rejected promise.
*
* @param uri Identifies the resource to open.
* @return A promise that resolves to a [document](#TextDocument).
* @see vscode.workspace.openTextDocument
*/
public openTextDocument(uri: vscode.Uri): Thenable<vscode.TextDocument> {
return vscode.workspace.openTextDocument(uri);
}
/**
* Helper to log messages to output channel.
*/
public logToOutputChannel(msg: any): void {
let date: Date = new Date();
if (msg instanceof Array) {
msg.forEach(element => {
VscodeWrapper._outputChannel.appendLine('[' + date.toLocaleTimeString() + '] ' + element.toString());
});
} else {
VscodeWrapper._outputChannel.appendLine('[' + date.toLocaleTimeString() + '] ' + msg.toString());
}
}
/**
* Create a vscode.Range object
* @param start The start position for the range
* @param end The end position for the range
*/
public range(start: vscode.Position, end: vscode.Position): vscode.Range {
return new vscode.Range(start, end);
}
/**
* Create a vscode.Position object
* @param line The line for the position
* @param column The column for the position
*/
public position(line: number, column: number): vscode.Position {
return new vscode.Position(line, column);
}
/**
* Create a vscode.Selection object
* @param start The start postion of the selection
* @param end The end position of the selection
*/
public selection(start: vscode.Position, end: vscode.Position): vscode.Selection {
return new vscode.Selection(start, end);
}
/**
* Formats and shows a vscode error message
*/
public showErrorMessage(msg: string, ...items: string[]): Thenable<string> {
return vscode.window.showErrorMessage(this._extensionConstants.extensionName + ': ' + msg, ...items);
}
/**
* Formats and shows a vscode information message
*/
public showInformationMessage(msg: string, ...items: string[]): Thenable<string> {
return vscode.window.showInformationMessage(this._extensionConstants.extensionName + ': ' + msg, ...items);
}
/**
* Shows a selection list.
*
* @param items An array of items, or a promise that resolves to an array of items.
* @param options Configures the behavior of the selection list.
* @return A promise that resolves to the selected item or undefined.
*/
public showQuickPick<T extends vscode.QuickPickItem>(items: T[] | Thenable<T[]>, options?: vscode.QuickPickOptions): Thenable<T> {
return vscode.window.showQuickPick<T>(items, options);
}
/**
* Show the given document in a text editor. A [column](#ViewColumn) can be provided
* to control where the editor is being shown. Might change the [active editor](#window.activeTextEditor).
*
* @param document A text document to be shown.
* @param column A view column in which the editor should be shown. The default is the [one](#ViewColumn.One), other values
* are adjusted to be __Min(column, columnCount + 1)__.
* @param preserveFocus When `true` the editor will not take focus.
* @return A promise that resolves to an [editor](#TextEditor).
*/
public showTextDocument(document: vscode.TextDocument, column?: vscode.ViewColumn, preserveFocus?: boolean): Thenable<vscode.TextEditor> {
return vscode.window.showTextDocument(document, column, preserveFocus);
}
/**
* Formats and shows a vscode warning message
*/
public showWarningMessage(msg: string): Thenable<string> {
return vscode.window.showWarningMessage(this._extensionConstants.extensionName + ': ' + msg );
}
/**
* Returns a array of the text editors currently visible in the window
*/
public get visibleEditors(): vscode.TextEditor[] {
return vscode.window.visibleTextEditors;
}
/**
* Create an URI from a file system path. The [scheme](#Uri.scheme)
* will be `file`.
*
* @param path A file system or UNC path.
* @return A new Uri instance.
* @see vscode.Uri.file
*/
public uriFile(path: string): vscode.Uri {
return vscode.Uri.file(path);
}
/**
* Create an URI from a string. Will throw if the given value is not
* valid.
*
* @param value The string value of an Uri.
* @return A new Uri instance.
* @see vscode.Uri.parse
*/
public uriParse(value: string): vscode.Uri {
return vscode.Uri.parse(value);
}
/**
* The folder that is open in VS Code. `undefined` when no folder
* has been opened.
*
* @readonly
* @see vscode.workspace.rootPath
*/
public get workspaceRootPath(): string {
return vscode.workspace.rootPath;
}
}

View File

@@ -1,24 +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 { IDecompressProvider, IPackage } from './interfaces';
import { ILogger } from '../models/interfaces';
const decompress = require('decompress');
export default class DecompressProvider implements IDecompressProvider {
public decompress(pkg: IPackage, logger: ILogger): Promise<void> {
return new Promise<void>((resolve, reject) => {
decompress(pkg.tmpFile.name, pkg.installPath).then(files => {
logger.appendLine(`Done! ${files.length} files unpacked.\n`);
resolve();
}).catch(decompressErr => {
logger.appendLine(`[ERROR] ${decompressErr}`);
reject(decompressErr);
});
});
}
}

View File

@@ -1,146 +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 { IPackage, IStatusView, PackageError, IHttpClient } from './interfaces';
import { ILogger } from '../models/interfaces';
import { parse as parseUrl, Url } from 'url';
import * as https from 'https';
import * as http from 'http';
import { getProxyAgent } from './proxy';
const fs = require('fs');
/*
* Http client class to handle downloading files using http or https urls
*/
export default class HttpClient implements IHttpClient {
/*
* Downloads a file and stores the result in the temp file inside the package object
*/
public downloadFile(urlString: string, pkg: IPackage, logger: ILogger, statusView: IStatusView, proxy?: string, strictSSL?: boolean): Promise<void> {
const url = parseUrl(urlString);
let options = this.getHttpClientOptions(url, proxy, strictSSL);
let clientRequest = url.protocol === 'http:' ? http.request : https.request;
return new Promise<void>((resolve, reject) => {
if (!pkg.tmpFile || pkg.tmpFile.fd === 0) {
return reject(new PackageError('Temporary package file unavailable', pkg));
}
let request = clientRequest(options, response => {
if (response.statusCode === 301 || response.statusCode === 302) {
// Redirect - download from new location
return resolve(this.downloadFile(response.headers.location, pkg, logger, statusView, proxy, strictSSL));
}
if (response.statusCode !== 200) {
// Download failed - print error message
logger.appendLine(`failed (error code '${response.statusCode}')`);
return reject(new PackageError(response.statusCode.toString(), pkg));
}
// If status code is 200
this.handleSuccessfulResponse(pkg, response, logger, statusView).then(_ => {
resolve();
}).catch(err => {
reject(err);
});
});
request.on('error', error => {
// reject(new PackageError(`Request error: ${error.code || 'NONE'}`, pkg, error));
reject(new PackageError(`Request error: ${error.name || 'NONE'}`, pkg, error));
});
// Execute the request
request.end();
});
}
private getHttpClientOptions(url: Url, proxy?: string, strictSSL?: boolean): any {
const agent = getProxyAgent(url, proxy, strictSSL);
let options: http.RequestOptions = {
host: url.hostname,
path: url.path,
agent: agent,
port: +url.port
};
if (url.protocol === 'https:') {
let httpsOptions: https.RequestOptions = {
host: url.hostname,
path: url.path,
agent: agent,
port: +url.port
};
options = httpsOptions;
}
return options;
}
/*
* Calculate the download percentage and stores in the progress object
*/
public handleDataReceivedEvent(progress: IDownloadProgress, data: any, logger: ILogger, statusView: IStatusView): void {
progress.downloadedBytes += data.length;
// Update status bar item with percentage
if (progress.packageSize > 0) {
let newPercentage = Math.ceil(100 * (progress.downloadedBytes / progress.packageSize));
if (newPercentage !== progress.downloadPercentage) {
statusView.updateServiceDownloadingProgress(progress.downloadPercentage);
progress.downloadPercentage = newPercentage;
}
// Update dots after package name in output console
let newDots = Math.ceil(progress.downloadPercentage / 5);
if (newDots > progress.dots) {
logger.append('.'.repeat(newDots - progress.dots));
progress.dots = newDots;
}
}
return;
}
private handleSuccessfulResponse(pkg: IPackage, response: http.IncomingMessage, logger: ILogger, statusView: IStatusView): Promise<void> {
return new Promise<void>((resolve, reject) => {
let progress: IDownloadProgress = {
packageSize: parseInt(response.headers['content-length'], 10),
dots: 0,
downloadedBytes: 0,
downloadPercentage: 0
};
logger.append(`(${Math.ceil(progress.packageSize / 1024)} KB) `);
response.on('data', data => {
this.handleDataReceivedEvent(progress, data, logger, statusView);
});
let tmpFile = fs.createWriteStream(undefined, { fd: pkg.tmpFile.fd });
response.on('end', () => {
resolve();
});
response.on('error', err => {
reject(new PackageError(`Response error: ${err.name || 'NONE'}`, pkg, err));
});
// Begin piping data from the response to the package file
response.pipe(tmpFile, { end: false });
});
}
}
/*
* Interface to store the values needed to calculate download percentage
*/
export interface IDownloadProgress {
packageSize: number;
downloadedBytes: number;
downloadPercentage: number;
dots: number;
}

View File

@@ -1,46 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as tmp from 'tmp';
import { ILogger } from '../models/interfaces';
export interface IStatusView {
installingService(): void;
serviceInstalled(): void;
serviceInstallationFailed(): void;
updateServiceDownloadingProgress(downloadPercentage: number): void;
}
export interface IConfig {
getDownloadUrl(): string;
getInstallDirectory(): string;
getExecutableFiles(): string[];
getPackageVersion(): string;
getExtensionConfig(key: string, defaultValue?: any): any;
getWorkspaceConfig(key: string, defaultValue?: any): any;
getConfigValue(configKey: string): any;
}
export interface IPackage {
url: string;
installPath?: string;
tmpFile: tmp.SynchronousResult;
}
export class PackageError extends Error {
// Do not put PII (personally identifiable information) in the 'message' field as it will be logged to telemetry
constructor(public message: string,
public pkg: IPackage = undefined,
public innerError: any = undefined) {
super(message);
}
}
export interface IHttpClient {
downloadFile(urlString: string, pkg: IPackage, logger: ILogger, statusView: IStatusView, proxy: string, strictSSL: boolean): Promise<void>;
}
export interface IDecompressProvider {
decompress(pkg: IPackage, logger: ILogger): Promise<void>;
}

View File

@@ -1,48 +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 { Url, parse as parseUrl } from 'url';
const HttpProxyAgent = require('http-proxy-agent');
const HttpsProxyAgent = require('https-proxy-agent');
function getSystemProxyURL(requestURL: Url): string {
if (requestURL.protocol === 'http:') {
return process.env.HTTP_PROXY || process.env.http_proxy || undefined;
} else if (requestURL.protocol === 'https:') {
return process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || undefined;
}
return undefined;
}
/*
* Returns the proxy agent using the proxy url in the parameters or the system proxy. Returns null if no proxy found
*/
export function getProxyAgent(requestURL: Url, proxy?: string, strictSSL?: boolean): any {
const proxyURL = proxy || getSystemProxyURL(requestURL);
if (!proxyURL) {
return undefined;
}
const proxyEndpoint = parseUrl(proxyURL);
if (!/^https?:$/.test(proxyEndpoint.protocol)) {
return undefined;
}
strictSSL = strictSSL || true;
const opts = {
host: proxyEndpoint.hostname,
port: Number(proxyEndpoint.port),
auth: proxyEndpoint.auth,
rejectUnauthorized: strictSSL
};
return requestURL.protocol === 'http:' ? new HttpProxyAgent(opts) : new HttpsProxyAgent(opts);
}

View File

@@ -1,112 +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 path from 'path';
import { Runtime } from '../models/platform';
import ServiceDownloadProvider from './serviceDownloadProvider';
import { IConfig, IStatusView } from './interfaces';
const fs = require('fs-extra-promise');
/*
* Service Provider class finds the SQL tools service executable file or downloads it if doesn't exist.
*/
export default class ServerProvider {
constructor(private _downloadProvider: ServiceDownloadProvider,
private _config: IConfig,
private _statusView: IStatusView,
private _extensionConfigSectionName: string) {
}
/**
* Public get method for downloadProvider
*/
public get downloadProvider(): ServiceDownloadProvider {
return this._downloadProvider;
}
/**
* Given a file path, returns the path to the SQL Tools service file.
*/
public findServerPath(filePath: string, executableFiles: string[] = undefined): Promise<string> {
return fs.lstatAsync(filePath).then(stats => {
// If a file path was passed, assume its the launch file.
if (stats.isFile()) {
return filePath;
}
// Otherwise, search the specified folder.
let candidate: string;
if (executableFiles === undefined && this._config !== undefined) {
executableFiles = this._config.getExecutableFiles();
}
if (executableFiles !== undefined) {
executableFiles.forEach(element => {
let executableFile = path.join(filePath, element);
if (candidate === undefined && fs.existsSync(executableFile)) {
candidate = executableFile;
return candidate;
}
});
}
return candidate;
});
}
/**
* Download the service if doesn't exist and returns the file path.
*/
public getOrDownloadServer(runtime: Runtime): Promise<string> {
// Attempt to find launch file path first from options, and then from the default install location.
// If SQL tools service can't be found, download it.
return new Promise<string>((resolve, reject) => {
return this.getServerPath(runtime).then(result => {
if (result === undefined) {
return this.downloadServerFiles(runtime).then ( downloadResult => {
resolve(downloadResult);
});
} else {
return resolve(result);
}
}).catch(err => {
return reject(err);
});
}).catch(err => {
throw err;
});
}
/**
* Returns the path of the installed service
*/
public getServerPath(runtime: Runtime): Promise<string> {
const installDirectory = this._downloadProvider.getInstallDirectory(runtime, this._extensionConfigSectionName);
return this.findServerPath(installDirectory);
}
/**
* Downloads the service and returns the path of the installed service
*/
public downloadServerFiles(runtime: Runtime): Promise<string> {
return new Promise<string>((resolve, reject) => {
const installDirectory = this._downloadProvider.getInstallDirectory(runtime, this._extensionConfigSectionName);
return this._downloadProvider.installService(runtime).then( _ => {
return this.findServerPath(installDirectory).then ( result => {
return resolve(result);
});
}).catch(err => {
this._statusView.serviceInstallationFailed();
reject(err);
});
});
}
}

View File

@@ -1,125 +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 { IStatusView } from './interfaces';
import vscode = require('vscode');
import { IExtensionConstants } from '../models/contracts/contracts';
import { Constants } from '../models/constants';
/*
* The status class which includes the service initialization result.
*/
export class ServerInitializationResult {
public constructor(
public installedBeforeInitializing: Boolean = false,
public isRunning: Boolean = false,
public serverPath: string = undefined
) {
}
public Clone(): ServerInitializationResult {
return new ServerInitializationResult(this.installedBeforeInitializing, this.isRunning, this.serverPath);
}
public WithRunning(isRunning: Boolean): ServerInitializationResult {
return new ServerInitializationResult(this.installedBeforeInitializing, isRunning, this.serverPath);
}
}
/*
* The status class shows service installing progress in UI
*/
export class ServerStatusView implements IStatusView, vscode.Disposable {
private _numberOfSecondsBeforeHidingMessage = 5000;
private _statusBarItem: vscode.StatusBarItem = undefined;
private _progressTimerId: NodeJS.Timer;
private _constants: IExtensionConstants;
constructor(constants: IExtensionConstants) {
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
vscode.window.onDidChangeActiveTextEditor((params) => this.onDidChangeActiveTextEditor(params));
vscode.workspace.onDidCloseTextDocument((params) => this.onDidCloseTextDocument(params));
this._constants = constants;
}
public installingService(): void {
this._statusBarItem.command = undefined;
this._statusBarItem.show();
this.showProgress('$(desktop-download) ' + Constants.serviceInstalling);
}
public updateServiceDownloadingProgress(downloadPercentage: number): void {
this._statusBarItem.text = '$(cloud-download) ' + `${Constants.serviceDownloading} ... ${downloadPercentage}%`;
this._statusBarItem.show();
}
public serviceInstalled(): void {
this._statusBarItem.command = undefined;
this._statusBarItem.text = this._constants.serviceInstalled;
this._statusBarItem.show();
// Cleat the status bar after 2 seconds
setTimeout(() => {
this._statusBarItem.hide();
}, this._numberOfSecondsBeforeHidingMessage);
}
public serviceInstallationFailed(): void {
this._statusBarItem.command = undefined;
this._statusBarItem.text = this._constants.serviceInstallationFailed;
this._statusBarItem.show();
}
private showProgress(statusText: string): void {
let index = 0;
let progressTicks = [ '|', '/', '-', '\\'];
this._progressTimerId = setInterval(() => {
index++;
if (index > 3) {
index = 0;
}
let progressTick = progressTicks[index];
if (this._statusBarItem.text !== this._constants.serviceInstalled) {
this._statusBarItem.text = statusText + ' ' + progressTick;
this._statusBarItem.show();
}
}, 200);
}
dispose(): void {
this.destroyStatusBar();
}
private hideLastShownStatusBar(): void {
if (typeof this._statusBarItem !== 'undefined') {
this._statusBarItem.hide();
}
}
private onDidChangeActiveTextEditor(editor: vscode.TextEditor): void {
// Hide the most recently shown status bar
this.hideLastShownStatusBar();
}
private onDidCloseTextDocument(doc: vscode.TextDocument): void {
// Remove the status bar associated with the document
this.destroyStatusBar();
}
private destroyStatusBar(): void {
if (typeof this._statusBarItem !== 'undefined') {
this._statusBarItem.dispose();
}
}
}

View File

@@ -1,535 +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 { ExtensionContext, workspace, window, OutputChannel, languages } from 'vscode';
import * as SqlopsClient from 'dataprotocol-client';
import { CloseAction, ErrorAction, ServerOptions, NotificationHandler, NotificationType, RequestType, TransportKind } from 'vscode-languageclient';
import { VscodeWrapper } from '../controllers/vscodeWrapper';
import { Telemetry } from '../models/telemetry';
import { Utils } from '../models/utils';
import { VersionRequest, IExtensionConstants } from '../models/contracts/contracts';
import { Logger } from '../models/logger';
import ServerProvider from './server';
import ServiceDownloadProvider from './serviceDownloadProvider';
import DecompressProvider from './decompressProvider';
import HttpClient from './httpClient';
import ExtConfig from '../configurations/extConfig';
import { PlatformInformation, Runtime } from '../models/platform';
import { ServerInitializationResult, ServerStatusView } from './serverStatus';
import StatusView from '../views/statusView';
import * as LanguageServiceContracts from '../models/contracts/languageService';
import { Constants } from '../models/constants';
import ServiceStatus from './serviceStatus';
const opener = require('opener');
const path = require('path');
let _channel: OutputChannel = undefined;
/**
* @interface IMessage
*/
interface IMessage {
jsonrpc: string;
}
/**
* Handle Language Service client errors
* @class LanguageClientErrorHandler
*/
class LanguageClientErrorHandler {
private vscodeWrapper: VscodeWrapper;
/**
* Creates an instance of LanguageClientErrorHandler.
* @memberOf LanguageClientErrorHandler
*/
constructor(constants: IExtensionConstants) {
if (!this.vscodeWrapper) {
this.vscodeWrapper = new VscodeWrapper(constants);
}
Telemetry.getRuntimeId = this.vscodeWrapper.constants.getRuntimeId;
}
/**
* Show an error message prompt with a link to known issues wiki page
* @memberOf LanguageClientErrorHandler
*/
showOnErrorPrompt(): void {
let extensionConstants = this.vscodeWrapper.constants;
Telemetry.sendTelemetryEvent(extensionConstants.serviceName + 'Crash');
this.vscodeWrapper.showErrorMessage(
extensionConstants.serviceCrashMessage,
Constants.serviceCrashButton).then(action => {
if (action && action === Constants.serviceCrashButton) {
opener(extensionConstants.serviceCrashLink);
}
});
}
/**
* Callback for language service client error
*
* @param {Error} error
* @param {Message} message
* @param {number} count
* @returns {ErrorAction}
*
* @memberOf LanguageClientErrorHandler
*/
error(error: Error, message: IMessage, count: number): ErrorAction {
this.showOnErrorPrompt();
// we don't retry running the service since crashes leave the extension
// in a bad, unrecovered state
return ErrorAction.Shutdown;
}
/**
* Callback for language service client closed
*
* @returns {CloseAction}
*
* @memberOf LanguageClientErrorHandler
*/
closed(): CloseAction {
this.showOnErrorPrompt();
// we don't retry running the service since crashes leave the extension
// in a bad, unrecovered state
return CloseAction.DoNotRestart;
}
}
// The Service Client class handles communication with the VS Code LanguageClient
export class SqlToolsServiceClient {
// singleton instance
private static _instance: SqlToolsServiceClient = undefined;
private static _constants: IExtensionConstants = undefined;
public static get constants(): IExtensionConstants {
return this._constants;
}
public static set constants(constantsObject: IExtensionConstants) {
this._constants = constantsObject;
Telemetry.getRuntimeId = this._constants.getRuntimeId;
}
private static _helper: LanguageServiceContracts.ILanguageClientHelper = undefined;
public static get helper(): LanguageServiceContracts.ILanguageClientHelper {
return this._helper;
}
public static set helper(helperObject: LanguageServiceContracts.ILanguageClientHelper) {
this._helper = helperObject;
}
// VS Code Language Client
private _client: SqlopsClient.SqlOpsDataClient = undefined;
// getter method for the Language Client
private get client(): SqlopsClient.SqlOpsDataClient {
return this._client;
}
private set client(client: SqlopsClient.SqlOpsDataClient) {
this._client = client;
}
public installDirectory: string;
private _downloadProvider: ServiceDownloadProvider;
private _vscodeWrapper: VscodeWrapper;
private _serviceStatus: ServiceStatus;
private _languageClientStartTime: number = undefined;
private _installationTime: number = undefined;
constructor(
private _server: ServerProvider,
private _logger: Logger,
private _statusView: StatusView,
private _config: ExtConfig) {
this._downloadProvider = _server.downloadProvider;
if (!this._vscodeWrapper) {
this._vscodeWrapper = new VscodeWrapper(SqlToolsServiceClient.constants);
}
this._serviceStatus = new ServiceStatus(SqlToolsServiceClient._constants.serviceName);
}
// gets or creates the singleton service client instance
public static getInstance(path: string): SqlToolsServiceClient {
if (this._instance === undefined) {
let constants = this._constants;
let config = new ExtConfig(constants.extensionConfigSectionName, undefined, path);
_channel = window.createOutputChannel(constants.serviceInitializingOutputChannelName);
let logger = new Logger(text => _channel.append(text), constants);
let serverStatusView = new ServerStatusView(constants);
let httpClient = new HttpClient();
let decompressProvider = new DecompressProvider();
let downloadProvider = new ServiceDownloadProvider(config, logger, serverStatusView, httpClient,
decompressProvider, constants, false);
let serviceProvider = new ServerProvider(downloadProvider, config, serverStatusView, constants.extensionConfigSectionName);
let statusView = new StatusView();
this._instance = new SqlToolsServiceClient(serviceProvider, logger, statusView, config);
}
return this._instance;
}
// initialize the Service Client instance by launching
// out-of-proc server through the LanguageClient
public initialize(context: ExtensionContext): Promise<any> {
this._logger.appendLine(SqlToolsServiceClient._constants.serviceInitializing);
this._languageClientStartTime = Date.now();
return PlatformInformation.getCurrent(SqlToolsServiceClient._constants.getRuntimeId, SqlToolsServiceClient._constants.extensionName).then(platformInfo => {
return this.initializeForPlatform(platformInfo, context);
}).catch(err => {
this._vscodeWrapper.showErrorMessage(err);
});
}
public initializeForPlatform(platformInfo: PlatformInformation, context: ExtensionContext): Promise<ServerInitializationResult> {
return new Promise<ServerInitializationResult>((resolve, reject) => {
this._logger.appendLine(SqlToolsServiceClient._constants.commandsNotAvailableWhileInstallingTheService);
this._logger.appendLine();
this._logger.append(`Platform: ${platformInfo.toString()}`);
if (!platformInfo.isValidRuntime()) {
// if it's an unknown Linux distro then try generic Linux x64 and give a warning to the user
if (platformInfo.isLinux()) {
this._logger.appendLine(Constants.usingDefaultPlatformMessage);
platformInfo.runtimeId = Runtime.Linux_64;
}
let ignoreWarning: boolean = this._config.getWorkspaceConfig(Constants.ignorePlatformWarning, false);
if (!ignoreWarning) {
this._vscodeWrapper.showErrorMessage(
Constants.unsupportedPlatformErrorMessage,
Constants.neverShowAgain)
.then(action => {
if (action === Constants.neverShowAgain) {
this._config.updateWorkspaceConfig(Constants.ignorePlatformWarning, true);
}
});
}
Telemetry.sendTelemetryEvent('UnsupportedPlatform', { platform: platformInfo.toString() });
}
if (platformInfo.runtimeId) {
this._logger.appendLine(` (${platformInfo.getRuntimeDisplayName()})`);
} else {
this._logger.appendLine();
}
this._logger.appendLine();
this._server.getServerPath(platformInfo.runtimeId).then(serverPath => {
if (serverPath === undefined) {
// Check if the service already installed and if not open the output channel to show the logs
if (_channel !== undefined) {
_channel.show();
}
let installationStartTime = Date.now();
this._server.downloadServerFiles(platformInfo.runtimeId).then(installedServerPath => {
this._installationTime = Date.now() - installationStartTime;
this.initializeLanguageClient(installedServerPath, context, platformInfo.runtimeId);
resolve(new ServerInitializationResult(true, true, installedServerPath));
}).catch(downloadErr => {
reject(downloadErr);
});
} else {
this.initializeLanguageClient(serverPath, context, platformInfo.runtimeId);
resolve(new ServerInitializationResult(false, true, serverPath));
}
}).catch(err => {
Utils.logDebug(SqlToolsServiceClient._constants.serviceLoadingFailed + ' ' + err, SqlToolsServiceClient._constants.extensionConfigSectionName);
Utils.showErrorMsg(SqlToolsServiceClient._constants.serviceLoadingFailed, SqlToolsServiceClient._constants.extensionName);
Telemetry.sendTelemetryEvent('ServiceInitializingFailed');
reject(err);
});
});
}
/**
* Initializes the SQL language configuration
*
* @memberOf SqlToolsServiceClient
*/
private initializeLanguageConfiguration(): void {
languages.setLanguageConfiguration('sql', {
comments: {
lineComment: '--',
blockComment: ['/*', '*/']
},
brackets: [
['{', '}'],
['[', ']'],
['(', ')']
],
__characterPairSupport: {
autoClosingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: '"', close: '"', notIn: ['string'] },
{ open: '\'', close: '\'', notIn: ['string', 'comment'] }
]
}
});
}
private initializeLanguageClient(serverPath: string, context: ExtensionContext, runtimeId: Runtime): void {
if (serverPath === undefined) {
Utils.logDebug(SqlToolsServiceClient._constants.invalidServiceFilePath, SqlToolsServiceClient._constants.extensionConfigSectionName);
throw new Error(SqlToolsServiceClient._constants.invalidServiceFilePath);
} else {
let self = this;
if (SqlToolsServiceClient._constants.languageId === 'sql') {
self.initializeLanguageConfiguration();
}
// Use default createServerOptions if one isn't specified
let serverOptions: ServerOptions = SqlToolsServiceClient._helper ?
SqlToolsServiceClient._helper.createServerOptions(serverPath, runtimeId) : self.createServerOptions(serverPath);
this.client = this.createLanguageClient(serverOptions);
this.installDirectory = this._downloadProvider.getInstallDirectory(runtimeId, SqlToolsServiceClient._constants.extensionConfigSectionName);
if (context !== undefined) {
// Create the language client and start the client.
let disposable = this.client.start();
// Push the disposable to the context's subscriptions so that the
// client can be deactivated on extension deactivation
context.subscriptions.push(disposable);
}
}
}
public createClient(context: ExtensionContext, runtimeId: Runtime, languageClientHelper: LanguageServiceContracts.ILanguageClientHelper, executableFiles: string[]): Promise<SqlopsClient.SqlOpsDataClient> {
return new Promise<SqlopsClient.SqlOpsDataClient>((resolve, reject) => {
let client: SqlopsClient.SqlOpsDataClient;
this._server.findServerPath(this.installDirectory, executableFiles).then(serverPath => {
if (serverPath === undefined) {
reject(new Error(SqlToolsServiceClient._constants.invalidServiceFilePath));
} else {
let serverOptions: ServerOptions = languageClientHelper ?
languageClientHelper.createServerOptions(serverPath, runtimeId) : this.createServerOptions(serverPath);
// Options to control the language client
let clientOptions: SqlopsClient.ClientOptions = {
documentSelector: [SqlToolsServiceClient._constants.languageId],
providerId: '',
synchronize: {
configurationSection: SqlToolsServiceClient._constants.extensionConfigSectionName
},
errorHandler: new LanguageClientErrorHandler(SqlToolsServiceClient._constants),
outputChannel: {
append: () => {
},
appendLine: () => {
},
dispose: () => {
},
clear: () => {
},
hide: () => {
},
name: '',
show: () => {
}
},
// pass in no features so we don't register features we don't want
features: []
};
this._serviceStatus.showServiceLoading();
// cache the client instance for later use
client = new SqlopsClient.SqlOpsDataClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions);
if (context !== undefined) {
// Create the language client and start the client.
let disposable = client.start();
// Push the disposable to the context's subscriptions so that the
// client can be deactivated on extension deactivation
context.subscriptions.push(disposable);
}
client.onReady().then(this._serviceStatus.showServiceLoaded);
resolve(client);
}
}, error => {
reject(error);
});
});
}
private createServerOptions(servicePath): ServerOptions {
let serverArgs = [];
let serverCommand: string = servicePath;
if (servicePath.endsWith('.dll')) {
serverArgs = [servicePath];
serverCommand = 'dotnet';
}
// Enable diagnostic logging in the service if it is configured
let config = workspace.getConfiguration(SqlToolsServiceClient._constants.extensionConfigSectionName);
if (config) {
let logDebugInfo = config[Constants.configLogDebugInfo];
if (logDebugInfo) {
serverArgs.push('--enable-logging');
}
}
serverArgs.push('--log-dir');
let logFileLocation = path.join(Utils.getDefaultLogLocation(), SqlToolsServiceClient.constants.extensionName);
serverArgs.push(logFileLocation);
// run the service host using dotnet.exe from the path
let serverOptions: ServerOptions = { command: serverCommand, args: serverArgs, transport: TransportKind.stdio };
return serverOptions;
}
private createLanguageClient(serverOptions: ServerOptions): SqlopsClient.SqlOpsDataClient {
// Options to control the language client
let clientOptions: SqlopsClient.ClientOptions = {
documentSelector: [SqlToolsServiceClient._constants.languageId],
providerId: SqlToolsServiceClient._constants.providerId,
synchronize: {
configurationSection: SqlToolsServiceClient._constants.extensionConfigSectionName
},
errorHandler: new LanguageClientErrorHandler(SqlToolsServiceClient._constants),
outputChannel: {
append: () => {
},
appendLine: () => {
},
dispose: () => {
},
clear: () => {
},
hide: () => {
},
name: '',
show: () => {
}
},
features: [
SqlopsClient.AdminServicesFeature,
SqlopsClient.BackupFeature,
SqlopsClient.CapabilitiesFeature,
SqlopsClient.ConnectionFeature,
SqlopsClient.FileBrowserFeature,
SqlopsClient.MetadataFeature,
SqlopsClient.ObjectExplorerFeature,
SqlopsClient.ProfilerFeature,
SqlopsClient.QueryFeature,
SqlopsClient.RestoreFeature,
SqlopsClient.ScriptingFeature,
SqlopsClient.TaskServicesFeature,
// heres the important bit
LanguageServiceContracts.AgentServicesFeature
]
};
this._serviceStatus.showServiceLoading();
// cache the client instance for later use
let client = new SqlopsClient.SqlOpsDataClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions);
client.onReady().then(() => {
this.checkServiceCompatibility();
this._serviceStatus.showServiceLoaded();
client.onNotification(LanguageServiceContracts.TelemetryNotification.type, this.handleLanguageServiceTelemetryNotification());
client.onNotification(LanguageServiceContracts.StatusChangedNotification.type, this.handleLanguageServiceStatusNotification());
// Report the language client startup time
let endTime = Date.now();
let installationTime = this._installationTime || 0;
let totalTime = endTime - this._languageClientStartTime;
let processStartupTime = totalTime - installationTime;
Telemetry.sendTelemetryEvent('startup/LanguageClientStarted', {
installationTime: String(installationTime),
processStartupTime: String(processStartupTime),
totalTime: String(totalTime),
beginningTimestamp: String(this._languageClientStartTime)
});
this._languageClientStartTime = undefined;
this._installationTime = undefined;
});
return client;
}
private handleLanguageServiceTelemetryNotification(): NotificationHandler<LanguageServiceContracts.TelemetryParams> {
return (event: LanguageServiceContracts.TelemetryParams): void => {
Telemetry.sendTelemetryEvent(event.params.eventName, event.params.properties, event.params.measures);
};
}
/**
* Public for testing purposes only.
*/
public handleLanguageServiceStatusNotification(): NotificationHandler<LanguageServiceContracts.StatusChangeParams> {
return (event: LanguageServiceContracts.StatusChangeParams): void => {
this._statusView.languageServiceStatusChanged(event.ownerUri, event.status);
};
}
/**
* Send a request to the service client
* @param type The of the request to make
* @param params The params to pass with the request
* @returns A thenable object for when the request receives a response
*/
public sendRequest<P, R, E, RO>(type: RequestType<P, R, E, RO>, params?: P, client: SqlopsClient.SqlOpsDataClient = undefined): Thenable<R> {
if (client === undefined) {
client = this._client;
}
if (client !== undefined) {
return client.sendRequest(type, params);
}
}
/**
* Register a handler for a notification type
* @param type The notification type to register the handler for
* @param handler The handler to register
*/
public onNotification<P, RO>(type: NotificationType<P, RO>, handler: NotificationHandler<P>, client: SqlopsClient.SqlOpsDataClient = undefined): void {
if (client === undefined) {
client = this._client;
}
if (client !== undefined) {
return client.onNotification(type, handler);
}
}
public checkServiceCompatibility(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
this._client.sendRequest(VersionRequest.type, undefined).then((result) => {
Utils.logDebug(SqlToolsServiceClient._constants.extensionName + ' service client version: ' + result, SqlToolsServiceClient._constants.extensionConfigSectionName);
if (result === undefined || !result.startsWith(SqlToolsServiceClient._constants.serviceCompatibleVersion)) {
Utils.showErrorMsg(Constants.serviceNotCompatibleError, SqlToolsServiceClient._constants.extensionName);
Utils.logDebug(Constants.serviceNotCompatibleError, SqlToolsServiceClient._constants.extensionConfigSectionName);
resolve(false);
} else {
resolve(true);
}
});
});
}
}

View File

@@ -1,186 +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 { Runtime, getRuntimeDisplayName } from '../models/platform';
import * as path from 'path';
import { IConfig, IStatusView, IPackage, PackageError, IHttpClient, IDecompressProvider } from './interfaces';
import { ILogger } from '../models/interfaces';
import { Constants } from '../models/constants';
import * as tmp from 'tmp';
import { IExtensionConstants } from '../models/contracts/contracts';
const fse = require('fs-extra');
/*
* Service Download Provider class which handles downloading the SQL Tools service.
*/
export default class ServiceDownloadProvider {
constructor(private _config: IConfig,
private _logger: ILogger,
private _statusView: IStatusView,
private _httpClient: IHttpClient,
private _decompressProvider: IDecompressProvider,
private _extensionConstants: IExtensionConstants,
private _fromBuild: boolean) {
// Ensure our temp files get cleaned up in case of error.
tmp.setGracefulCleanup();
}
/**
* Returns the download url for given platform
*/
public getDownloadFileName(platform: Runtime): string {
let fileNamesJson = this._config.getConfigValue('downloadFileNames');
console.info('Platform: ', platform.toString());
let fileName = fileNamesJson[platform.toString()];
console.info('Filename: ', fileName);
if (fileName === undefined) {
if (process.platform === 'linux') {
throw new Error('Unsupported linux distribution');
} else {
throw new Error(`Unsupported platform: ${process.platform}`);
}
}
return fileName;
}
/**
* Returns SQL tools service installed folder.
*/
public getInstallDirectory(platform: Runtime, extensionConfigSectionName: string): string {
let basePath = this.getInstallDirectoryRoot(platform, extensionConfigSectionName);
let versionFromConfig = this._config.getPackageVersion();
basePath = basePath.replace('{#version#}', versionFromConfig);
basePath = basePath.replace('{#platform#}', getRuntimeDisplayName(platform));
if (!fse.existsSync(basePath)) {
fse.mkdirsSync(basePath);
}
return basePath;
}
private getLocalUserFolderPath(platform: Runtime): string {
if (platform) {
switch (platform) {
case Runtime.Windows_64:
case Runtime.Windows_86:
return process.env.APPDATA;
case Runtime.OSX:
return process.env.HOME + '/Library/Preferences';
default:
return process.env.HOME;
}
}
}
/**
* Returns SQL tools service installed folder root.
*/
public getInstallDirectoryRoot(platform: Runtime, extensionConfigSectionName: string): string {
let installDirFromConfig : string;
installDirFromConfig = this._config.getInstallDirectory();
if (!installDirFromConfig || installDirFromConfig === '') {
let rootFolderName: string = '.sqlops';
if (platform === Runtime.Windows_64 || platform === Runtime.Windows_86) {
rootFolderName = 'sqlops';
}
installDirFromConfig = path.join(this.getLocalUserFolderPath(platform), `/${rootFolderName}/${this._extensionConstants.installFolderName}/{#version#}/{#platform#}`);
}
let basePath: string;
if (path.isAbsolute(installDirFromConfig)) {
basePath = installDirFromConfig;
} else if (this._fromBuild) {
basePath = path.join(__dirname, '../../../extensions/' + extensionConfigSectionName + '/' + installDirFromConfig);
} else {
// The path from config is relative to the out folder
basePath = path.join(__dirname, '../../../../' + installDirFromConfig);
}
return basePath;
}
private getGetDownloadUrl(fileName: string): string {
let baseDownloadUrl = this._config.getDownloadUrl();
let version = this._config.getPackageVersion();
baseDownloadUrl = baseDownloadUrl.replace('{#version#}', version);
baseDownloadUrl = baseDownloadUrl.replace('{#fileName#}', fileName);
return baseDownloadUrl;
}
/**
* Downloads the service and decompress it in the install folder.
*/
public installService(platform: Runtime): Promise<boolean> {
const proxy = <string>this._config.getWorkspaceConfig('http.proxy');
const strictSSL = this._config.getWorkspaceConfig('http.proxyStrictSSL', true);
return new Promise<boolean>((resolve, reject) => {
const fileName = this.getDownloadFileName(platform);
const installDirectory = this.getInstallDirectory(platform, this._extensionConstants.extensionConfigSectionName);
this._logger.appendLine(`${this._extensionConstants.serviceInstallingTo} ${installDirectory}.`);
const urlString = this.getGetDownloadUrl(fileName);
this._logger.appendLine(`${Constants.serviceDownloading} ${urlString}`);
let pkg: IPackage = {
installPath: installDirectory,
url: urlString,
tmpFile: undefined
};
this.createTempFile(pkg).then(tmpResult => {
pkg.tmpFile = tmpResult;
this._httpClient.downloadFile(pkg.url, pkg, this._logger, this._statusView, proxy, strictSSL).then(_ => {
this._logger.logDebug(`Downloaded to ${pkg.tmpFile.name}...`);
this._logger.appendLine(' Done!');
this.install(pkg).then(result => {
resolve(true);
}).catch(installError => {
reject(installError);
});
}).catch(downloadError => {
this._logger.appendLine(`[ERROR] ${downloadError}`);
reject(downloadError);
});
});
});
}
private createTempFile(pkg: IPackage): Promise<tmp.SynchronousResult> {
return new Promise<tmp.SynchronousResult>((resolve, reject) => {
tmp.file({ prefix: 'package-' }, (err, path, fd, cleanupCallback) => {
if (err) {
return reject(new PackageError('Error from tmp.file', pkg, err));
}
resolve(<tmp.SynchronousResult>{ name: path, fd: fd, removeCallback: cleanupCallback });
});
});
}
private install(pkg: IPackage): Promise<void> {
this._logger.appendLine('Installing ...');
this._statusView.installingService();
return new Promise<void>((resolve, reject) => {
this._decompressProvider.decompress(pkg, this._logger).then(_ => {
this._statusView.serviceInstalled();
resolve();
}).catch(err => {
reject(err);
});
});
}
}

View File

@@ -1,130 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Runtime, PlatformInformation } from '../models/platform';
import Config from '../configurations/config';
import ServiceDownloadProvider from './serviceDownloadProvider';
import DecompressProvider from './decompressProvider';
import HttpClient from './httpClient';
import ServerProvider from './server';
import { IStatusView } from './interfaces';
import { ILogger } from '../models/interfaces';
import { IExtensionConstants } from '../models/contracts/contracts';
class StubStatusView implements IStatusView {
installingService(): void {
console.log('...');
}
serviceInstalled(): void {
console.log('Service installed');
}
serviceInstallationFailed(): void {
console.log('Service installation failed');
}
updateServiceDownloadingProgress(downloadPercentage: number): void {
if (downloadPercentage === 100) {
process.stdout.write('100%');
}
}
}
class StubLogger implements ILogger {
logDebug(message: string): void {
console.log(message);
}
increaseIndent(): void {
console.log('increaseIndent');
}
decreaseIndent(): void {
console.log('decreaseIndent');
}
append(message?: string): void {
process.stdout.write(message);
}
appendLine(message?: string): void {
console.log(message);
}
}
export class ServiceInstaller {
private _config = undefined;
private _logger = new StubLogger();
private _statusView = new StubStatusView();
private _httpClient = new HttpClient();
private _decompressProvider = new DecompressProvider();
private _downloadProvider = undefined;
private _serverProvider = undefined;
private _extensionConstants = undefined;
constructor(extensionConstants: IExtensionConstants, path?: string) {
this._extensionConstants = extensionConstants;
this._config = new Config(extensionConstants.extensionConfigSectionName, path, true);
this._downloadProvider = new ServiceDownloadProvider(this._config, this._logger, this._statusView, this._httpClient, this._decompressProvider, extensionConstants, true);
this._serverProvider = new ServerProvider(this._downloadProvider, this._config, this._statusView, extensionConstants.extensionConfigSectionName);
}
/*
* Installs the service for the given platform if it's not already installed.
*/
public installService(): Promise<String> {
return PlatformInformation.getCurrent(this._extensionConstants.getRuntimeId, this._extensionConstants.extensionName).then(platformInfo => {
if (platformInfo.isValidRuntime()) {
return this._serverProvider.getOrDownloadServer(platformInfo.runtimeId);
} else {
throw new Error('unsupported runtime');
}
});
}
/*
* Returns the install folder path for given platform.
*/
public getServiceInstallDirectory(runtime: Runtime): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (runtime === undefined) {
PlatformInformation.getCurrent(this._extensionConstants.getRuntimeId, this._extensionConstants.extensionName).then(platformInfo => {
if (platformInfo.isValidRuntime()) {
resolve(this._downloadProvider.getInstallDirectory(platformInfo.runtimeId));
} else {
reject('unsupported runtime');
}
}).catch(error => {
reject(error);
});
} else {
resolve(this._downloadProvider.getInstallDirectory(runtime));
}
});
}
/*
* Returns the path to the root folder of service install location.
*/
public getServiceInstallDirectoryRoot(runtime: Runtime): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (runtime === undefined) {
PlatformInformation.getCurrent(this._extensionConstants.getRuntimeId, this._extensionConstants.extensionName).then(platformInfo => {
if (platformInfo.isValidRuntime()) {
let directoryPath: string = this._downloadProvider.getInstallDirectoryRoot(platformInfo, this._extensionConstants.extensionName);
directoryPath = directoryPath.replace('\\{#version#}', '');
directoryPath = directoryPath.replace('\\{#platform#}', '');
directoryPath = directoryPath.replace('/{#platform#}', '');
directoryPath = directoryPath.replace('/{#version#}', '');
resolve(directoryPath);
} else {
reject('unsupported runtime');
}
}).catch(error => {
reject(error);
});
} else {
resolve(this._downloadProvider.getInstallDirectory(runtime));
}
});
}
}

View File

@@ -1,80 +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 vscode = require('vscode');
export default class ServiceStatus implements vscode.Disposable {
private _progressTimerId: NodeJS.Timer;
private _statusBarItem: vscode.StatusBarItem = undefined;
private durationStatusInMs: number = 1500;
// These need localization
private _serviceStartingMessage: string = `Starting ${this._serviceName}`;
private _serviceStartedMessage: string = `${this._serviceName} started`;
constructor(private _serviceName: string) {
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
}
public showServiceLoading(): Promise<void> {
return this === undefined ?
Promise.resolve() :
Promise.resolve(this.updateStatusView(this._serviceStartingMessage, true));
}
public showServiceLoaded(): Promise<void> {
return this === undefined ?
Promise.resolve() :
Promise.resolve(this.updateStatusView(this._serviceStartedMessage, false, this.durationStatusInMs));
}
//TODO: This can be merged with the serverStatus code
private showProgress(statusText: string): void {
let index: number = 0;
let progressTicks: string[] = ['.', '..', '...', '....'];
this._progressTimerId = setInterval(() => {
index = (index + 1) % progressTicks.length;
let progressTick = progressTicks[index];
if (this._statusBarItem.text !== this._serviceStartedMessage) {
this._statusBarItem.text = statusText + ' ' + progressTick;
this._statusBarItem.show();
}
}, 400);
}
private updateStatusView(message: string, showAsProgress: boolean = false, disposeAfter: number = -1): Promise<void> {
return new Promise<void>((resolve, reject) => {
if (showAsProgress) {
this.showProgress(message);
}
else {
this._statusBarItem.text = message;
this._statusBarItem.show();
if (this._progressTimerId !== undefined) {
clearInterval(this._progressTimerId);
}
}
if (disposeAfter !== -1) {
setInterval(() => {
this._statusBarItem.hide();
}, disposeAfter);
}
resolve();
});
}
dispose(): void {
if (this._progressTimerId !== undefined) {
clearInterval(this._progressTimerId);
}
this._statusBarItem.dispose();
}
}

View File

@@ -1,15 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export * from './controllers/vscodeWrapper';
export * from './models/constants';
export * from './models/utils';
export { SqlToolsServiceClient } from './languageservice/serviceClient';
export { IExtensionConstants } from './models/contracts/contracts';
export { ILanguageClientHelper } from './models/contracts/languageService';
export { Runtime, PlatformInformation } from './models/platform';
export { Telemetry } from './models/telemetry';
export { LinuxDistribution } from './models/platform';
export { ServiceInstaller } from './languageservice/serviceInstallerUtil';

View File

@@ -1,25 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export namespace Constants {
//constants
export const configLogDebugInfo: string = 'logDebugInfo';
export const serviceNotCompatibleError: string = 'Client is not compatible with the service layer';
export const serviceDownloading: string = 'Downloading';
export const serviceInstalling: string = 'Installing';
export const unsupportedPlatformErrorMessage: string = 'This platform is unsupported and application services may not function correctly';
export const serviceConfigKey = 'service';
export const executableFilesConfigKey = 'executableFiles';
export const versionConfigKey = 'version';
export const downloadUrlConfigKey = 'downloadUrl';
export const installDirConfigKey = 'installDir';
export const serviceCrashButton = 'View Known Issues';
export const neverShowAgain = 'Do not show again';
export const ignorePlatformWarning = 'ignorePlatformWarning';
export const usingDefaultPlatformMessage = 'Unknown platform detected, defaulting to Linux_x64 platform';
export const serverConnectionMetadata = 'serverConnectionMetadata';
export const extensionDeactivated: string = 'de-activated.';
export const extensionActivated: string = 'activated.';
}

View File

@@ -1,50 +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 { RequestType } from 'vscode-languageclient';
import { Runtime, LinuxDistribution } from '../platform';
// --------------------------------- < Version Request > -------------------------------------------------
// Version request message callback declaration
export namespace VersionRequest {
export const type = new RequestType<void, VersionResult, void, void>('version');
}
// Version response format
export type VersionResult = string;
// ------------------------------- </ Version Request > --------------------------------------------------
// Constants interface for each extension
export interface IExtensionConstants {
// TODO: Fill in interface
// Definitely dependent on the extension
extensionName: string;
invalidServiceFilePath: string;
serviceName: string;
extensionConfigSectionName: string;
serviceCompatibleVersion: string;
outputChannelName: string;
languageId: string;
serviceInstallingTo: string;
serviceInitializing: string;
serviceInstalled: string;
serviceLoadingFailed: string;
serviceInstallationFailed: string;
serviceInitializingOutputChannelName: string;
commandsNotAvailableWhileInstallingTheService: string;
providerId: string;
serviceCrashMessage: string;
serviceCrashLink: string;
installFolderName: string;
telemetryExtensionName: string;
getRuntimeId(platform: string, architecture: string, distribution: LinuxDistribution): Runtime;
}

View File

@@ -1,179 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { NotificationType, ServerOptions, RequestType, RPCMessageType, ClientCapabilities, ServerCapabilities } from 'vscode-languageclient';
import { ITelemetryEventProperties, ITelemetryEventMeasures } from '../telemetry';
import { Runtime } from '../platform';
import { SqlOpsFeature, SqlOpsDataClient } from 'dataprotocol-client';
import * as sqlops from 'sqlops';
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
import { Disposable } from 'vscode';
// ------------------------------- < Telemetry Sent Event > ------------------------------------
/**
* Event sent when the language service send a telemetry event
*/
export namespace TelemetryNotification {
export const type = new NotificationType<TelemetryParams, void>('telemetry/sqlevent');
}
/**
* Update event parameters
*/
export class TelemetryParams {
public params: {
eventName: string;
properties: ITelemetryEventProperties;
measures: ITelemetryEventMeasures;
};
}
// ------------------------------- </ Telemetry Sent Event > ----------------------------------
// ------------------------------- < Status Event > ------------------------------------
/**
* Event sent when the language service send a status change event
*/
export namespace StatusChangedNotification {
export const type = new NotificationType<StatusChangeParams, void>('textDocument/statusChanged');
}
/**
* Update event parameters
*/
export class StatusChangeParams {
/**
* URI identifying the text document
*/
public ownerUri: string;
/**
* The new status of the document
*/
public status: string;
}
// ------------------------------- </ Status Sent Event > ----------------------------------
export interface ILanguageClientHelper {
createServerOptions(servicePath: string, runtimeId?: Runtime): ServerOptions;
}
// Job Management types
export interface AgentJobsParams {
ownerUri: string;
jobId: string;
}
export interface AgentJobsResult {
succeeded: boolean;
errorMessage: string;
jobs: sqlops.AgentJobInfo[];
}
export interface AgentJobHistoryParams {
ownerUri: string;
jobId: string;
}
export interface AgentJobHistoryResult {
succeeded: boolean;
errorMessage: string;
jobs: sqlops.AgentJobHistoryInfo[];
}
export interface AgentJobActionParams {
ownerUri: string;
jobName: string;
action: string;
}
export interface AgentJobActionResult {
succeeded: boolean;
errorMessage: string;
}
export namespace AgentJobsRequest {
export const type = new RequestType<AgentJobsParams, AgentJobsResult, void, void>('agent/jobs');
}
export namespace AgentJobHistoryRequest {
export const type = new RequestType<AgentJobHistoryParams, AgentJobHistoryResult, void, void>('agent/jobhistory');
}
export namespace AgentJobActionRequest {
export const type = new RequestType<AgentJobActionParams, AgentJobActionResult, void, void>('agent/jobaction');
}
export class AgentServicesFeature extends SqlOpsFeature<undefined> {
private static readonly messagesTypes: RPCMessageType[] = [
AgentJobsRequest.type,
AgentJobHistoryRequest.type,
AgentJobActionRequest.type
];
constructor(client: SqlOpsDataClient) {
super(client, AgentServicesFeature.messagesTypes);
}
public fillClientCapabilities(capabilities: ClientCapabilities): void {
// this isn't explicitly necessary
// ensure(ensure(capabilities, 'connection')!, 'agentServices')!.dynamicRegistration = true;
}
public initialize(capabilities: ServerCapabilities): void {
this.register(this.messages, {
id: UUID.generateUuid(),
registerOptions: undefined
});
}
protected registerProvider(options: undefined): Disposable {
const client = this._client;
let getJobs = (ownerUri: string): Thenable<sqlops.AgentJobsResult> => {
let params: AgentJobsParams = { ownerUri: ownerUri, jobId: null };
return client.sendRequest(AgentJobsRequest.type, params).then(
r => r,
e => {
client.logFailedRequest(AgentJobsRequest.type, e);
return Promise.resolve(undefined);
}
);
};
let getJobHistory = (connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> => {
let params: AgentJobHistoryParams = { ownerUri: connectionUri, jobId: jobID };
return client.sendRequest(AgentJobHistoryRequest.type, params).then(
r => r,
e => {
client.logFailedRequest(AgentJobHistoryRequest.type, e);
return Promise.resolve(undefined);
}
);
};
let jobAction = (connectionUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> => {
let params: AgentJobActionParams = { ownerUri: connectionUri, jobName: jobName, action: action };
return client.sendRequest(AgentJobActionRequest.type, params).then(
r => r,
e => {
client.logFailedRequest(AgentJobActionRequest.type, e);
return Promise.resolve(undefined);
}
);
};
return sqlops.dataprotocol.registerAgentServicesProvider({
providerId: client.providerId,
getJobs,
getJobHistory,
jobAction
});
}
}

View File

@@ -1,69 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
import { ILogger } from './interfaces';
import { Utils } from './utils';
import { IExtensionConstants } from './contracts/contracts';
/*
* Logger class handles logging messages using the Util functions.
*/
export class Logger implements ILogger {
private _writer: (message: string) => void;
private _prefix: string;
private _extensionConstants: IExtensionConstants;
private _indentLevel: number = 0;
private _indentSize: number = 4;
private _atLineStart: boolean = false;
constructor(writer: (message: string) => void, extensionConstants: IExtensionConstants, prefix?: string) {
this._writer = writer;
this._prefix = prefix;
this._extensionConstants = extensionConstants;
}
public logDebug(message: string): void {
Utils.logDebug(message, this._extensionConstants.extensionConfigSectionName);
}
private _appendCore(message: string): void {
if (this._atLineStart) {
if (this._indentLevel > 0) {
const indent = ' '.repeat(this._indentLevel * this._indentSize);
this._writer(indent);
}
if (this._prefix) {
this._writer(`[${this._prefix}] `);
}
this._atLineStart = false;
}
this._writer(message);
}
public increaseIndent(): void {
this._indentLevel += 1;
}
public decreaseIndent(): void {
if (this._indentLevel > 0) {
this._indentLevel -= 1;
}
}
public append(message?: string): void {
message = message || '';
this._appendCore(message);
}
public appendLine(message?: string): void {
message = message || '';
this._appendCore(message + os.EOL);
this._atLineStart = true;
}
}

View File

@@ -1,314 +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 child_process from 'child_process';
import * as fs from 'fs';
import * as os from 'os';
const unknown = 'unknown';
export enum Runtime {
UnknownRuntime = <any>'Unknown',
UnknownVersion = <any>'Unknown',
Windows_86 = <any>'Windows_86',
Windows_64 = <any>'Windows_64',
OSX = <any>'OSX',
CentOS_7 = <any>'CentOS_7',
Debian_8 = <any>'Debian_8',
Fedora_23 = <any>'Fedora_23',
OpenSUSE_13_2 = <any>'OpenSUSE_13_2',
SLES_12_2 = <any>'SLES_12_2',
RHEL_7 = <any>'RHEL_7',
Ubuntu_14 = <any>'Ubuntu_14',
Ubuntu_16 = <any>'Ubuntu_16',
Linux_64 = <any>'Linux_64',
Linux_86 = <any>'Linux-86'
}
export function getRuntimeDisplayName(runtime: Runtime): string {
switch (runtime) {
case Runtime.Windows_64:
return 'Windows';
case Runtime.Windows_86:
return 'Windows';
case Runtime.OSX:
return 'OSX';
case Runtime.CentOS_7:
return 'Linux';
case Runtime.Debian_8:
return 'Linux';
case Runtime.Fedora_23:
return 'Linux';
case Runtime.OpenSUSE_13_2:
return 'Linux';
case Runtime.SLES_12_2:
return 'Linux';
case Runtime.RHEL_7:
return 'Linux';
case Runtime.Ubuntu_14:
return 'Linux';
case Runtime.Ubuntu_16:
return 'Linux';
case Runtime.Linux_64:
return 'Linux';
case Runtime.Linux_86:
return 'Linux';
default:
return 'Unknown';
}
}
export class PlatformInformation {
public runtimeId: Runtime;
public constructor(
public platform: string,
public architecture: string,
public distribution: LinuxDistribution = undefined,
public getRuntimeId: (platform: string, architecture: string, distribution: LinuxDistribution) => Runtime) {
try {
this.runtimeId = this.getRuntimeId(platform, architecture, distribution);
} catch (err) {
this.runtimeId = undefined;
}
}
public isWindows(): boolean {
return this.platform === 'win32';
}
public isMacOS(): boolean {
return this.platform === 'darwin';
}
public isLinux(): boolean {
return this.platform === 'linux';
}
public isValidRuntime(): boolean {
return this.runtimeId !== undefined && this.runtimeId !== Runtime.UnknownRuntime && this.runtimeId !== Runtime.UnknownVersion;
}
public getRuntimeDisplayName(): string {
return getRuntimeDisplayName(this.runtimeId);
}
public toString(): string {
let result = this.platform;
if (this.architecture) {
if (result) {
result += ', ';
}
result += this.architecture;
}
if (this.distribution) {
if (result) {
result += ', ';
}
result += this.distribution.toString();
}
return result;
}
public static getCurrent(getRuntimeId: (platform: string, architecture: string, distribution: LinuxDistribution) => Runtime,
extensionName: string): Promise<any> {
let platform = os.platform();
let architecturePromise: Promise<string>;
let distributionPromise: Promise<LinuxDistribution>;
switch (platform) {
case 'win32':
architecturePromise = PlatformInformation.getWindowsArchitecture();
distributionPromise = Promise.resolve(undefined);
break;
case 'darwin':
let osVersion = os.release();
if (parseFloat(osVersion) < 16.0 && extensionName === 'mssql') {
return Promise.reject('The current version of macOS is not supported. Only macOS Sierra and above (>= 10.12) are supported.');
}
architecturePromise = PlatformInformation.getUnixArchitecture();
distributionPromise = Promise.resolve(undefined);
break;
case 'linux':
architecturePromise = PlatformInformation.getUnixArchitecture();
distributionPromise = LinuxDistribution.getCurrent();
break;
default:
return Promise.reject(`Unsupported platform: ${platform}`);
}
return architecturePromise.then(arch => {
return distributionPromise.then(distro => {
return new PlatformInformation(platform, arch, distro, getRuntimeId);
});
});
}
private static getWindowsArchitecture(): Promise<string> {
return new Promise<string>((resolve, reject) => {
// try to get the architecture from WMIC
PlatformInformation.getWindowsArchitectureWmic().then(architecture => {
if (architecture && architecture !== unknown) {
resolve(architecture);
} else {
// sometimes WMIC isn't available on the path so then try to parse the envvar
PlatformInformation.getWindowsArchitectureEnv().then(architecture => {
resolve(architecture);
});
}
});
});
}
private static getWindowsArchitectureWmic(): Promise<string> {
return this.execChildProcess('wmic os get osarchitecture')
.then(architecture => {
if (architecture) {
let archArray: string[] = architecture.split(os.EOL);
if (archArray.length >= 2) {
let arch = archArray[1].trim();
// Note: This string can be localized. So, we'll just check to see if it contains 32 or 64.
if (arch.indexOf('64') >= 0) {
return 'x86_64';
} else if (arch.indexOf('32') >= 0) {
return 'x86';
}
}
}
return unknown;
}).catch((error) => {
return unknown;
});
}
private static getWindowsArchitectureEnv(): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (process.env.PROCESSOR_ARCHITECTURE === 'x86' && process.env.PROCESSOR_ARCHITEW6432 === undefined) {
resolve('x86');
}
else {
resolve('x86_64');
}
});
}
private static getUnixArchitecture(): Promise<string> {
return this.execChildProcess('uname -m')
.then(architecture => {
if (architecture) {
return architecture.trim();
}
return undefined;
});
}
private static execChildProcess(process: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
child_process.exec(process, { maxBuffer: 500 * 1024 }, (error: Error, stdout: string, stderr: string) => {
if (error) {
reject(error);
return;
}
if (stderr && stderr.length > 0) {
reject(new Error(stderr));
return;
}
resolve(stdout);
});
});
}
}
/**
* There is no standard way on Linux to find the distribution name and version.
* Recently, systemd has pushed to standardize the os-release file. This has
* seen adoption in "recent" versions of all major distributions.
* https://www.freedesktop.org/software/systemd/man/os-release.html
*/
export class LinuxDistribution {
public constructor(
public name: string,
public version: string,
public idLike?: string[]) { }
public static getCurrent(): Promise<LinuxDistribution> {
// Try /etc/os-release and fallback to /usr/lib/os-release per the synopsis
// at https://www.freedesktop.org/software/systemd/man/os-release.html.
return LinuxDistribution.fromFilePath('/etc/os-release')
.catch(() => LinuxDistribution.fromFilePath('/usr/lib/os-release'))
.catch(() => Promise.resolve(new LinuxDistribution(unknown, unknown)));
}
public toString(): string {
return `name=${this.name}, version=${this.version}`;
}
private static fromFilePath(filePath: string): Promise<LinuxDistribution> {
return new Promise<LinuxDistribution>((resolve, reject) => {
fs.readFile(filePath, 'utf8', (error, data) => {
if (error) {
reject(error);
} else {
resolve(LinuxDistribution.fromReleaseInfo(data));
}
});
});
}
public static fromReleaseInfo(releaseInfo: string, eol: string = os.EOL): LinuxDistribution {
let name = unknown;
let version = unknown;
let idLike: string[] = undefined;
const lines = releaseInfo.split(eol);
for (let line of lines) {
line = line.trim();
let equalsIndex = line.indexOf('=');
if (equalsIndex >= 0) {
let key = line.substring(0, equalsIndex);
let value = line.substring(equalsIndex + 1);
// Strip quotes if necessary
if (value.length > 1 && value.startsWith('"') && value.endsWith('"')) {
value = value.substring(1, value.length - 1);
} else if (value.length > 1 && value.startsWith('\'') && value.endsWith('\'')) {
value = value.substring(1, value.length - 1);
}
if (key === 'ID') {
name = value;
} else if (key === 'VERSION_ID') {
version = value;
} else if (key === 'ID_LIKE') {
idLike = value.split(' ');
}
if (name !== unknown && version !== unknown && idLike !== undefined) {
break;
}
}
}
return new LinuxDistribution(name, version, idLike);
}
}

View File

@@ -1,130 +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 crypto from 'crypto';
import * as os from 'os';
import vscode = require('vscode');
import { Constants } from './constants';
import { ExtensionContext } from 'vscode';
var path = require('path');
export namespace Utils {
// INTERFACES /////////////////////////////////////////////////////////////////////////////////////
// Interface for package.json information
export interface IPackageInfo {
name: string;
version: string;
aiKey: string;
}
// FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////
// Get information from the extension's package.json file
export function getPackageInfo(context: ExtensionContext): IPackageInfo {
let extensionPackage = require(context.asAbsolutePath('./package.json'));
if (extensionPackage) {
return {
name: extensionPackage.name,
version: extensionPackage.version,
aiKey: extensionPackage.aiKey
};
}
}
// Generate a new GUID
export function generateGuid(): string {
let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
// c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
let oct: string = '';
let tmp: number;
/* tslint:disable:no-bitwise */
for (let a: number = 0; a < 4; a++) {
tmp = (4294967296 * Math.random()) | 0;
oct += hexValues[tmp & 0xF] +
hexValues[tmp >> 4 & 0xF] +
hexValues[tmp >> 8 & 0xF] +
hexValues[tmp >> 12 & 0xF] +
hexValues[tmp >> 16 & 0xF] +
hexValues[tmp >> 20 & 0xF] +
hexValues[tmp >> 24 & 0xF] +
hexValues[tmp >> 28 & 0xF];
}
// 'Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively'
let clockSequenceHi: string = hexValues[8 + (Math.random() * 4) | 0];
return oct.substr(0, 8) + '-' + oct.substr(9, 4) + '-4' + oct.substr(13, 3) + '-' + clockSequenceHi + oct.substr(16, 3) + '-' + oct.substr(19, 12);
/* tslint:enable:no-bitwise */
}
// Generate a unique, deterministic ID for the current user of the extension
export function generateUserId(): Promise<string> {
return new Promise<string>(resolve => {
try {
let interfaces = os.networkInterfaces();
let mac;
for (let key of Object.keys(interfaces)) {
let item = interfaces[key][0];
if (!item.internal) {
mac = item.mac;
break;
}
}
if (mac) {
resolve(crypto.createHash('sha256').update(mac + os.homedir(), 'utf8').digest('hex'));
} else {
resolve(generateGuid());
}
} catch (err) {
resolve(generateGuid()); // fallback
}
});
}
// Retrieve the URI for the currently open file if there is one; otherwise return the empty string
export function getActiveTextEditorUri(): string {
if (typeof vscode.window.activeTextEditor !== 'undefined' &&
typeof vscode.window.activeTextEditor.document !== 'undefined') {
return vscode.window.activeTextEditor.document.uri.toString();
}
return '';
}
// Helper to log debug messages
export function logDebug(msg: any, extensionConfigSectionName: string): void {
let config = vscode.workspace.getConfiguration(extensionConfigSectionName);
let logDebugInfo = config[Constants.configLogDebugInfo];
if (logDebugInfo === true) {
let currentTime = new Date().toLocaleTimeString();
let outputMsg = '[' + currentTime + ']: ' + msg ? msg.toString() : '';
console.log(outputMsg);
}
}
// Helper to show an error message
export function showErrorMsg(msg: string, extensionName: string): void {
vscode.window.showErrorMessage(extensionName + ': ' + msg);
}
export function isEmpty(str: any): boolean {
return (!str || '' === str);
}
// The function is a duplicate of \src\paths.js. IT would be better to import path.js but it doesn't
// work for now because the extension is running in different process.
export function getAppDataPath() {
var platform = process.platform;
switch (platform) {
case 'win32': return process.env['APPDATA'] || path.join(process.env['USERPROFILE'], 'AppData', 'Roaming');
case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support');
case 'linux': return process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config');
default: throw new Error('Platform not supported');
}
}
export function getDefaultLogLocation() {
return path.join(getAppDataPath(), 'sqlops');
}
}

View File

@@ -1,146 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import vscode = require('vscode');
import { Utils } from '../models/utils';
// Status bar element for each file in the editor
class FileStatusBar {
// Item for the connection status
public statusConnection: vscode.StatusBarItem;
// Item for the query status
public statusQuery: vscode.StatusBarItem;
// Item for language service status
public statusLanguageService: vscode.StatusBarItem;
// Timer used for displaying a progress indicator on queries
public progressTimerId: NodeJS.Timer;
public currentLanguageServiceStatus: string;
}
export default class StatusView implements vscode.Disposable {
private _statusBars: { [fileUri: string]: FileStatusBar };
private _lastShownStatusBar: FileStatusBar;
constructor() {
this._statusBars = {};
vscode.window.onDidChangeActiveTextEditor((params) => this.onDidChangeActiveTextEditor(params));
vscode.workspace.onDidCloseTextDocument((params) => this.onDidCloseTextDocument(params));
}
dispose(): void {
for (let bar in this._statusBars) {
if (this._statusBars.hasOwnProperty(bar)) {
this._statusBars[bar].statusConnection.dispose();
this._statusBars[bar].statusQuery.dispose();
this._statusBars[bar].statusLanguageService.dispose();
clearInterval(this._statusBars[bar].progressTimerId);
delete this._statusBars[bar];
}
}
}
// Create status bar item if needed
private createStatusBar(fileUri: string): void {
let bar = new FileStatusBar();
bar.statusConnection = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
bar.statusQuery = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
bar.statusLanguageService = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
this._statusBars[fileUri] = bar;
}
private destroyStatusBar(fileUri: string): void {
let bar = this._statusBars[fileUri];
if (bar) {
if (bar.statusConnection) {
bar.statusConnection.dispose();
}
if (bar.statusQuery) {
bar.statusQuery.dispose();
}
if (bar.statusLanguageService) {
bar.statusLanguageService.dispose();
}
if (bar.progressTimerId) {
clearInterval(bar.progressTimerId);
}
delete this._statusBars[fileUri];
}
}
private getStatusBar(fileUri: string): FileStatusBar {
if (!(fileUri in this._statusBars)) {
// Create it if it does not exist
this.createStatusBar(fileUri);
}
let bar = this._statusBars[fileUri];
if (bar.progressTimerId) {
clearInterval(bar.progressTimerId);
}
return bar;
}
public languageServiceStatusChanged(fileUri: string, status: string): void {
let bar = this.getStatusBar(fileUri);
bar.currentLanguageServiceStatus = status;
this.updateStatusMessage(status,
() => { return bar.currentLanguageServiceStatus; }, (message) => {
bar.statusLanguageService.text = message;
this.showStatusBarItem(fileUri, bar.statusLanguageService);
});
}
public updateStatusMessage(
newStatus: string,
getCurrentStatus: () => string,
updateMessage: (message: string) => void): void {
}
private hideLastShownStatusBar(): void {
if (typeof this._lastShownStatusBar !== 'undefined') {
this._lastShownStatusBar.statusConnection.hide();
this._lastShownStatusBar.statusQuery.hide();
this._lastShownStatusBar.statusLanguageService.hide();
}
}
private onDidChangeActiveTextEditor(editor: vscode.TextEditor): void {
// Hide the most recently shown status bar
this.hideLastShownStatusBar();
// Change the status bar to match the open file
if (typeof editor !== 'undefined') {
const fileUri = editor.document.uri.toString();
const bar = this._statusBars[fileUri];
if (bar) {
this.showStatusBarItem(fileUri, bar.statusConnection);
this.showStatusBarItem(fileUri, bar.statusLanguageService);
}
}
}
private onDidCloseTextDocument(doc: vscode.TextDocument): void {
// Remove the status bar associated with the document
this.destroyStatusBar(doc.uri.toString());
}
private showStatusBarItem(fileUri: string, statusBarItem: vscode.StatusBarItem): void {
let currentOpenFile = Utils.getActiveTextEditorUri();
// Only show the status bar if it matches the currently open file and is not empty
if (fileUri === currentOpenFile && !Utils.isEmpty(statusBarItem.text)) {
statusBarItem.show();
if (fileUri in this._statusBars) {
this._lastShownStatusBar = this._statusBars[fileUri];
}
} else {
statusBarItem.hide();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
"dependencies": {
"adal-node": "0.1.25",
"request": "2.63.0",
"vscode-nls": "2.0.2"
"vscode-nls": "^3.2.1"
},
"devDependencies": {
"@types/node": "^8.0.24"
@@ -19,8 +19,8 @@
"contributes": {
"commands": [
{
"command": "extension.clearTokenCache",
"title": "%extension.clearTokenCache%",
"command": "accounts.clearTokenCache",
"title": "%accounts.clearTokenCache%",
"category": "Azure Accounts"
}
],

View File

@@ -1,5 +1,5 @@
{
"extension.clearTokenCache": "Clear Azure Account Token Cache",
"accounts.clearTokenCache": "Clear Azure Account Token Cache",
"config.enablePublicCloudDescription": "Should Azure public cloud integration be enabled",
"config.enableUsGovCloudDescription": "Should US Government Azure cloud (Fairfax) integration be enabled",
"config.enableChinaCloudDescription": "Should Azure China integration be enabled",

View File

@@ -20,7 +20,7 @@ let localize = nls.loadMessageBundle();
export class AzureAccountProviderService implements vscode.Disposable {
// CONSTANTS ///////////////////////////////////////////////////////////////
private static CommandClearTokenCache = 'extension.clearTokenCache';
private static CommandClearTokenCache = 'accounts.azure.clearTokenCache';
private static ConfigurationSection = 'accounts.azure';
private static CredentialNamespace = 'azureAccountProviderCredentials';

View File

@@ -591,9 +591,9 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
vscode-nls@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"
vscode-nls@^3.2.1:
version "3.2.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
"xmldom@>= 0.1.x":
version "0.1.27"

View File

@@ -2,7 +2,7 @@
"name": "agent",
"displayName": "SQL Server Agent",
"description": "Manage and troubleshoot SQL Server Agent jobs (early preview)",
"version": "0.27.1",
"version": "0.28.1",
"publisher": "Microsoft",
"preview": true,
"license": "https://raw.githubusercontent.com/Microsoft/sqlopsstudio/master/LICENSE.txt",
@@ -32,6 +32,7 @@
"description": "Manage and troubleshoot SQL Agent jobs",
"provider": "MSSQL",
"title": "SQL Agent",
"when": "connectionProvider == 'MSSQL' && !mssql:iscloud",
"container": {
"controlhost-container": {
"type": "agent"

View File

@@ -1,6 +1,8 @@
{
"name": "bat",
"version": "0.1.0",
"displayName": "%displayName%",
"description": "%description%",
"version": "1.0.0",
"publisher": "vscode",
"engines": { "vscode": "*" },
"scripts": {

View File

@@ -0,0 +1,4 @@
{
"displayName": "Windows Bat Language Basics",
"description": "Provides snippets, syntax highlighting, bracket matching and folding in Windows batch files."
}

View File

@@ -1,169 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>uuid</key>
<string>E07EC438-7B75-4437-8AA1-DA94C1E6EACC</string>
<key>patterns</key>
<array>
<dict>
<key>name</key>
<string>keyword.command.dosbatch</string>
<key>match</key>
<string>\b(?i)(?:append|assoc|at|attrib|break|cacls|cd|chcp|chdir|chkdsk|chkntfs|cls|cmd|color|comp|compact|convert|copy|date|del|dir|diskcomp|diskcopy|doskey|echo|endlocal|erase|fc|find|findstr|format|ftype|graftabl|help|keyb|label|md|mkdir|mode|more|move|path|pause|popd|print|prompt|pushd|rd|recover|ren|rename|replace|restore|rmdir|set|setlocal|shift|sort|start|subst|time|title|tree|type|ver|verify|vol|xcopy)\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.control.statement.dosbatch</string>
<key>match</key>
<string>\b(?i)(?:goto|call|exit)\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.control.conditional.if.dosbatch</string>
<key>match</key>
<string>\b(?i)if\s+((not)\s+)(exist|defined|errorlevel|cmdextversion)\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.control.conditional.dosbatch</string>
<key>match</key>
<string>\b(?i)(?:if|else)\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.control.repeat.dosbatch</string>
<key>match</key>
<string>\b(?i)for\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.operator.dosbatch</string>
<key>match</key>
<string>\b(?:EQU|NEQ|LSS|LEQ|GTR|GEQ)\b</string>
</dict>
<dict>
<key>name</key>
<string>comment.line.rem.dosbatch</string>
<key>match</key>
<string>\b(?i)rem(?:$|\s.*$)</string>
</dict>
<dict>
<key>name</key>
<string>comment.line.colons.dosbatch</string>
<key>match</key>
<string>\s*:\s*:.*$</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>variable.parameter.function.begin.shell</string>
</dict>
</dict>
<key>name</key>
<string>variable.parameter.function.dosbatch</string>
<key>match</key>
<string>(?i)(%)(~(?:f|d|p|n|x|s|a|t|z|\$[^:]*:)*)?\d</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>variable.other.parsetime.begin.shell</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>variable.other.parsetime.end.shell</string>
</dict>
</dict>
<key>name</key>
<string>variable.other.parsetime.dosbatch</string>
<key>match</key>
<string>(%)[^%]+(%)|(%%)[^%]+(%%)</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>variable.parameter.loop.begin.shell</string>
</dict>
</dict>
<key>name</key>
<string>variable.parameter.loop.dosbatch</string>
<key>match</key>
<string>(?i)(%%)(~(?:f|d|p|n|x|s|a|t|z|\$[^:]*:)*)?[a-z]</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>variable.other.delayed.begin.shell</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>variable.other.delayed.end.shell</string>
</dict>
</dict>
<key>name</key>
<string>variable.other.delayed.dosbatch</string>
<key>match</key>
<string>(!)[^!]+(!)</string>
</dict>
<dict>
<key>begin</key>
<string>"</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.shell</string>
</dict>
</dict>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.shell</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.double.dosbatch</string>
<key>end</key>
<string>"|$</string>
</dict>
<dict>
<key>name</key>
<string>keyword.operator.pipe.dosbatch</string>
<key>match</key>
<string>[|]</string>
</dict>
<dict>
<key>name</key>
<string>keyword.operator.redirect.shell</string>
<key>match</key>
<string>&amp;&gt;|\d*&gt;&amp;\d*|\d*(&gt;&gt;|&gt;|&lt;)|\d*&lt;&amp;|\d*&lt;&gt;</string>
</dict>
</array>
<key>name</key>
<string>Batch File</string>
<key>scopeName</key>
<string>source.dosbatch</string>
<key>fileTypes</key>
<array>
<string>bat</string>
</array>
</dict>
</plist>

View File

@@ -4,13 +4,9 @@
"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/40b605c75db3967a24b7015f6d3a885360b84e28",
"scopeName": "source.batchfile",
"version": "https://github.com/mmims/language-batchfile/commit/3dd105c31484e5975144478dac1aa91d8f51e528",
"name": "Batch File",
"fileTypes": [
"bat",
"cmd"
],
"scopeName": "source.batchfile",
"patterns": [
{
"include": "#commands"
@@ -454,11 +450,15 @@
{
"begin": "\\(",
"beginCaptures": {
"0": "punctuation.section.group.begin.batchfile"
"0": {
"name": "punctuation.section.group.begin.batchfile"
}
},
"end": "\\)",
"endCaptures": {
"0": "punctuation.section.group.end.batchfile"
"0": {
"name": "punctuation.section.group.end.batchfile"
}
},
"name": "meta.group.batchfile",
"patterns": [

View File

@@ -1,15 +0,0 @@
{
"name": "configuration-editing",
"version": "0.0.1",
"dependencies": {
"jsonc-parser": {
"version": "0.3.1",
"from": "jsonc-parser@0.3.1"
},
"vscode-nls": {
"version": "2.0.2",
"from": "vscode-nls@>=2.0.2 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
}
}
}

View File

@@ -1,6 +1,8 @@
{
"name": "configuration-editing",
"version": "0.0.1",
"displayName": "%displayName%",
"description": "%description%",
"version": "1.0.0",
"publisher": "vscode",
"engines": {
"vscode": "^1.0.0"
@@ -10,7 +12,8 @@
"Other"
],
"activationEvents": [
"onLanguage:json", "onLanguage:jsonc"
"onLanguage:json",
"onLanguage:jsonc"
],
"main": "./out/extension",
"scripts": {
@@ -18,8 +21,8 @@
"watch": "gulp watch-extension:configuration-editing"
},
"dependencies": {
"jsonc-parser": "^0.3.1",
"vscode-nls": "^2.0.1"
"jsonc-parser": "^1.0.0",
"vscode-nls": "^3.2.1"
},
"contributes": {
"jsonValidation": [
@@ -67,6 +70,10 @@
"fileMatch": "%APP_SETTINGS_HOME%/snippets/*.json",
"url": "vscode://schemas/snippets"
},
{
"fileMatch": "**/*.code-snippets",
"url": "vscode://schemas/global-snippets"
},
{
"fileMatch": "/.vscode/extensions.json",
"url": "vscode://schemas/extensions"
@@ -76,4 +83,4 @@
"devDependencies": {
"@types/node": "7.0.4"
}
}
}

View File

@@ -0,0 +1,4 @@
{
"displayName": "Configuration Editing",
"description": "Provides capabilities (advanced IntelliSense, auto-fixing) in configuration files like settings, launch and extension recommendation files."
}

View File

@@ -2,16 +2,14 @@
* 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';
const localize = nls.loadMessageBundle();
import * as vscode from 'vscode';
import { getLocation, visit, parse } from 'jsonc-parser';
import { getLocation, visit, parse, ParseErrorCode } from 'jsonc-parser';
import * as path from 'path';
import { SettingsDocument } from './settingsDocumentHelper';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
const decoration = vscode.window.createTextEditorDecorationType({
color: '#9e9e9e'
@@ -20,7 +18,6 @@ const decoration = vscode.window.createTextEditorDecorationType({
let pendingLaunchJsonDecoration: NodeJS.Timer;
export function activate(context: vscode.ExtensionContext): void {
//keybindings.json command-suggestions
context.subscriptions.push(registerKeybindingsCompletions());
@@ -41,6 +38,45 @@ export function activate(context: vscode.ExtensionContext): void {
}
}, null, context.subscriptions));
updateLaunchJsonDecorations(vscode.window.activeTextEditor);
context.subscriptions.push(vscode.workspace.onWillSaveTextDocument(e => {
if (!e.document.fileName.endsWith('/settings.json')) {
return;
}
autoFixSettingsJSON(e);
}));
}
function autoFixSettingsJSON(willSaveEvent: vscode.TextDocumentWillSaveEvent): void {
const document = willSaveEvent.document;
const text = document.getText();
const edit = new vscode.WorkspaceEdit();
let lastEndOfSomething = -1;
visit(text, {
onArrayEnd(offset: number, length: number): void {
lastEndOfSomething = offset + length;
},
onLiteralValue(value: any, offset: number, length: number): void {
lastEndOfSomething = offset + length;
},
onObjectEnd(offset: number, length: number): void {
lastEndOfSomething = offset + length;
},
onError(error: ParseErrorCode, offset: number, length: number): void {
if (error === ParseErrorCode.CommaExpected && lastEndOfSomething > -1) {
const fixPosition = document.positionAt(lastEndOfSomething);
edit.insert(document.uri, fixPosition, ',');
}
}
});
willSaveEvent.waitUntil(
vscode.workspace.applyEdit(edit));
}
function registerKeybindingsCompletions(): vscode.Disposable {

Some files were not shown because too many files have changed in this diff Show More