77
88import * as fs from "fs" ;
99import * as path from "path" ;
10- import * as process from "process" ;
1110import * as vscode from "vscode" ;
1211
1312import {
@@ -29,10 +28,7 @@ import {
2928 GenericResult ,
3029 IPQTestService ,
3130} from "../common/PQTestService" ;
32- import {
33- ExtensionConfigurations ,
34- promptWarningMessageForExternalDependency ,
35- } from "../constants/PowerQuerySdkConfiguration" ;
31+ import { extensionI18n , resolveI18nTemplate } from "../i18n/extension" ;
3632import {
3733 getAnyPqFileBeneathTheFirstWorkspace ,
3834 getCurrentWorkspaceSettingPath ,
@@ -44,17 +40,15 @@ import {
4440import { InputStep , MultiStepInput } from "../common/MultiStepInput" ;
4541import { PqServiceHostClient , PqServiceHostServerNotReady } from "../pqTestConnector/PqServiceHostClient" ;
4642import { PqTestResultViewPanel , SimplePqTestResultViewBroker } from "../panels/PqTestResultViewPanel" ;
47-
48- import { extensionI18n , resolveI18nTemplate } from "../i18n/extension" ;
4943import { prettifyJson , resolveTemplateSubstitutedValues } from "../utils/strings" ;
44+
5045import { debounce } from "../utils/debounce" ;
46+ import { ExtensionConfigurations } from "../constants/PowerQuerySdkConfiguration" ;
5147import { ExtensionConstants } from "../constants/PowerQuerySdkExtension" ;
5248import { getCtimeOfAFile } from "../utils/files" ;
5349import { IDisposable } from "../common/Disposable" ;
54- import { NugetHttpService } from "../common/NugetHttpService" ;
55- import { NugetVersions } from "../utils/NugetVersions" ;
50+ import { PqSdkNugetPackageService } from "../common/PqSdkNugetPackageService" ;
5651import { PqSdkOutputChannel } from "../features/PqSdkOutputChannel" ;
57- import { SpawnedProcess } from "../common/SpawnedProcess" ;
5852
5953const CommandPrefix : string = `powerquery.sdk.tools` ;
6054
@@ -81,7 +75,7 @@ export class LifecycleCommands implements IDisposable {
8175 constructor (
8276 private readonly vscExtCtx : ExtensionContext ,
8377 readonly globalEventBus : GlobalEventBus ,
84- private readonly nugetHttpService : NugetHttpService ,
78+ private readonly pqSdkNugetPackageService : PqSdkNugetPackageService ,
8579 private readonly pqTestService : IPQTestService ,
8680 private readonly outputChannel : PqSdkOutputChannel ,
8781 ) {
@@ -490,191 +484,23 @@ export class LifecycleCommands implements IDisposable {
490484 return folder ;
491485 }
492486
493- private expectedPqTestPath ( maybeNextVersion ?: string ) : string {
494- const baseNugetFolder : string = path . resolve ( this . vscExtCtx . extensionPath , ExtensionConstants . NugetBaseFolder ) ;
495-
496- const pqTestSubPath : string [ ] = maybeNextVersion
497- ? ExtensionConstants . buildPqTestSubPath ( maybeNextVersion )
498- : ExtensionConstants . PqTestSubPath ;
499-
500- return path . resolve ( baseNugetFolder , ...pqTestSubPath ) ;
501- }
502-
503- private nugetPqTestExistsSync ( maybeNextVersion ?: string ) : boolean {
504- const expectedPqTestPath : string = this . expectedPqTestPath ( maybeNextVersion ) ;
505-
506- return fs . existsSync ( expectedPqTestPath ) ;
507- }
508-
509- private async doListPqTestFromNuget ( ) : Promise < string > {
510- await promptWarningMessageForExternalDependency ( Boolean ( ExtensionConfigurations . nugetPath ) , true , true ) ;
511-
512- const baseNugetFolder : string = path . resolve ( this . vscExtCtx . extensionPath , ExtensionConstants . NugetBaseFolder ) ;
513-
514- if ( ! fs . existsSync ( baseNugetFolder ) ) {
515- fs . mkdirSync ( baseNugetFolder ) ;
516- }
517-
518- const args : string [ ] = [ "list" , ExtensionConstants . InternalMsftPqSdkToolsNugetName ] ;
519-
520- if ( ExtensionConfigurations . nugetFeed ) {
521- args . push ( "-Source" , ExtensionConfigurations . nugetFeed ) ;
522- }
523-
524- const command : string = ExtensionConfigurations . nugetPath ?? "nuget" ;
525-
526- this . outputChannel . appendDebugLine ( `Listing nuget packages using nuget.exe` ) ;
527- this . outputChannel . appendInfoLine ( `Running ${ command } ${ args . join ( " " ) } ` ) ;
528-
529- const seizingProcess : SpawnedProcess = new SpawnedProcess ( command , args , {
530- cwd : baseNugetFolder ,
531- env : {
532- ...process . env ,
533- FORCE_NUGET_EXE_INTERACTIVE : "true" ,
534- } ,
535- } ) ;
536-
537- await seizingProcess . deferred$ ;
538-
539- return seizingProcess . stdOut ;
540- }
541-
542- private async doUpdatePqTestFromNuget ( maybeNextVersion ?: string | undefined ) : Promise < string | undefined > {
543- if ( ExtensionConfigurations . nugetPath ) {
544- // use nuget.exe to check the configured feed location
545- await promptWarningMessageForExternalDependency ( Boolean ( ExtensionConfigurations . nugetPath ) , true , true ) ;
546-
547- const baseNugetFolder : string = path . resolve (
548- this . vscExtCtx . extensionPath ,
549- ExtensionConstants . NugetBaseFolder ,
550- ) ;
551-
552- const pqTestFullPath : string = this . expectedPqTestPath ( maybeNextVersion ) ;
553-
554- if ( ! fs . existsSync ( baseNugetFolder ) ) {
555- fs . mkdirSync ( baseNugetFolder ) ;
556- }
557-
558- const args : string [ ] = [
559- "install" ,
560- ExtensionConstants . InternalMsftPqSdkToolsNugetName ,
561- "-Version" ,
562- maybeNextVersion ?? ExtensionConstants . SuggestedPqTestNugetVersion ,
563- "-OutputDirectory" ,
564- baseNugetFolder ,
565- ] ;
566-
567- if ( ExtensionConfigurations . nugetFeed ) {
568- args . push ( "-Source" , ExtensionConfigurations . nugetFeed ) ;
569- }
570-
571- const command : string = ExtensionConfigurations . nugetPath ?? "nuget" ;
572-
573- this . outputChannel . appendDebugLine ( `Installing nuget packages using nuget.exe` ) ;
574- this . outputChannel . appendInfoLine ( `Running ${ command } ${ args . join ( " " ) } ` ) ;
575-
576- const seizingProcess : SpawnedProcess = new SpawnedProcess (
577- command ,
578- args ,
579- {
580- cwd : baseNugetFolder ,
581- env : {
582- ...process . env ,
583- FORCE_NUGET_EXE_INTERACTIVE : "true" ,
584- } ,
585- } ,
586- {
587- onStdOut : ( data : Buffer ) : void => {
588- this . outputChannel . appendInfoLine ( data . toString ( "utf8" ) ) ;
589- } ,
590- onStdErr : ( data : Buffer ) : void => {
591- this . outputChannel . appendErrorLine ( data . toString ( "utf8" ) ) ;
592- } ,
593- } ,
594- ) ;
595-
596- await seizingProcess . deferred$ ;
597-
598- return fs . existsSync ( pqTestFullPath ) ? pqTestFullPath : undefined ;
599- } else {
600- // we gonna seize the pqSkdTools from the public feed
601- const baseNugetFolder : string = path . resolve (
602- this . vscExtCtx . extensionPath ,
603- ExtensionConstants . NugetBaseFolder ,
604- ) ;
605-
606- const pqTestFullPath : string = this . expectedPqTestPath ( maybeNextVersion ) ;
607-
608- if ( ! fs . existsSync ( baseNugetFolder ) ) {
609- fs . mkdirSync ( baseNugetFolder ) ;
610- }
611-
612- if ( fs . existsSync ( pqTestFullPath ) ) return pqTestFullPath ;
613-
614- await this . nugetHttpService . downloadAndExtractNugetPackage (
615- ExtensionConstants . PublicMsftPqSdkToolsNugetName ,
616- maybeNextVersion ?? ExtensionConstants . SuggestedPqTestNugetVersion ,
617- path . join (
618- baseNugetFolder ,
619- `${ ExtensionConstants . PublicMsftPqSdkToolsNugetName } .${
620- maybeNextVersion ?? ExtensionConstants . SuggestedPqTestNugetVersion
621- } `,
622- ) ,
623- ) ;
624-
625- return fs . existsSync ( pqTestFullPath ) ? pqTestFullPath : undefined ;
626- }
627- }
628-
629- private async findMaybeNewPqSdkVersion ( ) : Promise < string | undefined > {
630- if ( ExtensionConfigurations . nugetPath ) {
631- // use nuget.exe to check the configured feed location
632- const pqTestLocation : string | undefined = ExtensionConfigurations . PQTestLocation ;
633- const curVersion : NugetVersions = NugetVersions . createFromPath ( pqTestLocation ) ;
634-
635- const latestVersion : NugetVersions = NugetVersions . createFromNugetListOutput (
636- await this . doListPqTestFromNuget ( ) ,
637- ) ;
638-
639- const sortedVersions : [ NugetVersions , NugetVersions ] = [ curVersion , latestVersion ] . sort (
640- NugetVersions . compare ,
641- ) as [ NugetVersions , NugetVersions ] ;
642-
643- if ( ! sortedVersions [ 1 ] . isZero ( ) ) {
644- // we found a new version, thus we need to check with users first and update to the latest
645- return sortedVersions [ 1 ] . toString ( ) ;
646- } else {
647- return undefined ;
648- }
649- } else {
650- // we gonna use http endpoint to query the public feed
651- const sortedNugetVersions : NugetVersions [ ] = (
652- await this . nugetHttpService . getPackageReleasedVersions ( ExtensionConstants . PublicMsftPqSdkToolsNugetName )
653- ) . versions
654- . map ( ( releasedVersion : string ) => NugetVersions . createFromReleasedVersionString ( releasedVersion ) )
655- . sort ( NugetVersions . compare ) ;
656-
657- if ( sortedNugetVersions . length && ! sortedNugetVersions [ sortedNugetVersions . length - 1 ] . isZero ( ) ) {
658- return sortedNugetVersions [ sortedNugetVersions . length - 1 ] . toString ( ) ;
659- } else {
660- return undefined ;
661- }
662- }
663- }
664-
665487 private async doCheckAndTryToUpdatePqTest ( skipQueryDialog : boolean = false ) : Promise < string | undefined > {
666488 try {
667489 let pqTestLocation : string | undefined = ExtensionConfigurations . PQTestLocation ;
668490
669- const maybeNewVersion : string | undefined = await this . findMaybeNewPqSdkVersion ( ) ;
491+ const maybeNewVersion : string | undefined =
492+ await this . pqSdkNugetPackageService . findNullableNewPqSdkVersion ( ) ;
670493
671494 // we should not update to the latest unless the latest nuget doesn't exist on start
672495 // users might just want to use the previous one purposely
673496 // therefore do not try to update when, like, pqTestLocation.indexOf(maybeNewVersion) === -1
674- if ( ! pqTestLocation || ! this . pqTestService . pqTestReady || ! this . nugetPqTestExistsSync ( maybeNewVersion ) ) {
675- const pqTestExecutableFullPath : string | undefined = await this . doUpdatePqTestFromNuget (
676- maybeNewVersion ,
677- ) ;
497+ if (
498+ ! pqTestLocation ||
499+ ! this . pqTestService . pqTestReady ||
500+ ! this . pqSdkNugetPackageService . nugetPqSdkExistsSync ( maybeNewVersion )
501+ ) {
502+ const pqTestExecutableFullPath : string | undefined =
503+ await this . pqSdkNugetPackageService . updatePqSdkFromNuget ( maybeNewVersion ) ;
678504
679505 if ( ! pqTestExecutableFullPath && ! skipQueryDialog ) {
680506 const pqTestLocationUrls : Uri [ ] | undefined = await vscode . window . showOpenDialog ( {
@@ -744,24 +570,23 @@ export class LifecycleCommands implements IDisposable {
744570 public async manuallyUpdatePqTest ( maybeNextVersion ?: string ) : Promise < string | undefined > {
745571 try {
746572 if ( ! maybeNextVersion ) {
747- maybeNextVersion = await this . findMaybeNewPqSdkVersion ( ) ;
573+ maybeNextVersion = await this . pqSdkNugetPackageService . findNullableNewPqSdkVersion ( ) ;
748574 }
749575
750576 let pqTestLocation : string | undefined = ExtensionConfigurations . PQTestLocation ;
751577
752578 // determine whether we should trigger to seize or not
753579 if (
754- ! this . nugetPqTestExistsSync ( maybeNextVersion ) ||
580+ ! this . pqSdkNugetPackageService . nugetPqSdkExistsSync ( maybeNextVersion ) ||
755581 ! pqTestLocation ||
756582 // when manually update, we should eagerly update as long as current path is not of the latest version
757583 // like,
758584 // users might want to switch back to the latest some time after
759585 // they temporarily switch back to the previous version
760586 ( maybeNextVersion && pqTestLocation . indexOf ( maybeNextVersion ) === - 1 )
761587 ) {
762- const pqTestExecutableFullPath : string | undefined = await this . doUpdatePqTestFromNuget (
763- maybeNextVersion ,
764- ) ;
588+ const pqTestExecutableFullPath : string | undefined =
589+ await this . pqSdkNugetPackageService . updatePqSdkFromNuget ( maybeNextVersion ) ;
765590
766591 if ( pqTestExecutableFullPath ) {
767592 pqTestLocation = path . dirname ( pqTestExecutableFullPath ) ;
@@ -778,8 +603,9 @@ export class LifecycleCommands implements IDisposable {
778603 }
779604
780605 // check whether it got seized or not
781- if ( this . nugetPqTestExistsSync ( maybeNextVersion ) ) {
782- const pqTestExecutableFullPath : string = this . expectedPqTestPath ( maybeNextVersion ) ;
606+ if ( this . pqSdkNugetPackageService . nugetPqSdkExistsSync ( maybeNextVersion ) ) {
607+ const pqTestExecutableFullPath : string =
608+ this . pqSdkNugetPackageService . expectedPqSdkPath ( maybeNextVersion ) ;
783609
784610 this . outputChannel . appendInfoLine (
785611 resolveI18nTemplate ( "PQSdk.lifecycle.command.pqtest.seized.from" , {
0 commit comments