From c4c4152cb8ea8e6e7879ead4aef7f08b3081e9db Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 8 Nov 2017 10:01:28 +0200 Subject: [PATCH] Use profileDir from settingsService Currently CLI's configuration directory is used from `$options.profileDir`. When user passes `--profileDir `, the `$options.profileDir` value is populated. In case user does not pass anything, a default value is set. All services that require configuration directory use the `$options.profileDir`. However, this causes several issues: - `$options` is intended for use only when CLI is used as a standalone command line. In case you are using it as a library, the `$options` object will not be populated. - Unable to test local installations of extensions when CLI is used as library - there's no way to set the custom profileDir when using CLI as a library. So the extensions are always loaded from the default location. In order to resolve these issues, move the logic for profileDir in `settingsService` and introduce a new method to get the profileDir. In order to ensure code is backwards compatible (i.e. extensions that use `$options.profileDir` should still work), modify `$options` to set the value of `profileDir` in `settingsService`. Whenever you want to test local extensions you can use: ```JavaScript const tns = require("nativescript"); tns.settingsService.setSettings({ profileDir: "my custom dir" }); Promise.all(tns.extensibilityService.loadExtensions()) .then((result) => { console.log("Loaded extensions:", result); // write your code here }); ``` Replace all places where `$options.profileDir` is used with `$settingsService.getProfileDir()`. --- PublicAPI.md | 2 +- lib/commands/post-install.ts | 4 ++-- lib/common | 2 +- lib/config.ts | 3 +++ lib/npm-installation-manager.ts | 3 ++- lib/options.ts | 24 +++------------------- lib/services/extensibility-service.ts | 4 ++-- lib/services/user-settings-service.ts | 4 ++-- test/android-project-properties-manager.ts | 2 ++ test/commands/post-install.ts | 3 +++ test/debug.ts | 3 +++ test/ios-project-service.ts | 3 +++ test/npm-installation-manager.ts | 2 ++ test/npm-support.ts | 3 ++- test/platform-commands.ts | 2 ++ test/platform-service.ts | 2 ++ test/plugin-variables-service.ts | 2 ++ test/plugins-service.ts | 2 ++ test/project-service.ts | 3 +++ test/services/extensibility-service.ts | 21 ++++++++++--------- 20 files changed, 53 insertions(+), 41 deletions(-) diff --git a/PublicAPI.md b/PublicAPI.md index 0b3b3547bd..8501addc33 100644 --- a/PublicAPI.md +++ b/PublicAPI.md @@ -273,7 +273,7 @@ interface ISettingsService { * Usage: ```JavaScript -tns.settingsService.setSettings({ userAgentName: "myUserAgent" }); +tns.settingsService.setSettings({ userAgentName: "myUserAgent", profileDir: "customProfileDir" }); ``` ## npm diff --git a/lib/commands/post-install.ts b/lib/commands/post-install.ts index f574171789..53d1c5f9a4 100644 --- a/lib/commands/post-install.ts +++ b/lib/commands/post-install.ts @@ -6,11 +6,11 @@ export class PostInstallCliCommand extends PostInstallCommand { $staticConfig: Config.IStaticConfig, $commandsService: ICommandsService, $helpService: IHelpService, - $options: ICommonOptions, + $settingsService: ISettingsService, $doctorService: IDoctorService, $analyticsService: IAnalyticsService, $logger: ILogger) { - super($fs, $staticConfig, $commandsService, $helpService, $options, $doctorService, $analyticsService, $logger); + super($fs, $staticConfig, $commandsService, $helpService, $settingsService, $doctorService, $analyticsService, $logger); } public async execute(args: string[]): Promise { diff --git a/lib/common b/lib/common index 06d4f68052..c80e999c70 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 06d4f680523cf79ecc7df47feeb61cf6acc7a2a7 +Subproject commit c80e999c7009dd9e649484cd3230b6da1eba45a2 diff --git a/lib/config.ts b/lib/config.ts index dd4fcc8d13..707ca1e3a2 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -28,6 +28,9 @@ export class StaticConfig extends StaticConfigBase implements IStaticConfig { public ERROR_REPORT_SETTING_NAME = "TrackExceptions"; public ANALYTICS_INSTALLATION_ID_SETTING_NAME = "AnalyticsInstallationID"; public INSTALLATION_SUCCESS_MESSAGE = "Installation successful. You are good to go. Connect with us on `http://twitter.com/NativeScript`."; + public get PROFILE_DIR_NAME(): string { + return ".nativescript-cli"; + } constructor($injector: IInjector) { super($injector); diff --git a/lib/npm-installation-manager.ts b/lib/npm-installation-manager.ts index 0911fcecd5..3c44556873 100644 --- a/lib/npm-installation-manager.ts +++ b/lib/npm-installation-manager.ts @@ -7,6 +7,7 @@ export class NpmInstallationManager implements INpmInstallationManager { private $childProcess: IChildProcess, private $logger: ILogger, private $options: IOptions, + private $settingsService: ISettingsService, private $fs: IFileSystem, private $staticConfig: IStaticConfig) { } @@ -59,7 +60,7 @@ export class NpmInstallationManager implements INpmInstallationManager { // local installation takes precedence over cache if (!this.inspectorAlreadyInstalled(inspectorPath)) { - const cachePath = path.join(this.$options.profileDir, constants.INSPECTOR_CACHE_DIRNAME); + const cachePath = path.join(this.$settingsService.getProfileDir(), constants.INSPECTOR_CACHE_DIRNAME); this.prepareCacheDir(cachePath); const pathToPackageInCache = path.join(cachePath, constants.NODE_MODULES_FOLDER_NAME, inspectorNpmPackageName); diff --git a/lib/options.ts b/lib/options.ts index 36c03e136e..8e10776b76 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -1,11 +1,10 @@ import * as commonOptionsLibPath from "./common/options"; -import * as osenv from "osenv"; -import * as path from "path"; export class Options extends commonOptionsLibPath.OptionsBase { constructor($errors: IErrors, $staticConfig: IStaticConfig, - $hostInfo: IHostInfo) { + $hostInfo: IHostInfo, + $settingsService: ISettingsService) { super({ ipa: { type: OptionType.String }, frameworkPath: { type: OptionType.String }, @@ -40,24 +39,7 @@ export class Options extends commonOptionsLibPath.OptionsBase { clean: { type: OptionType.Boolean }, watch: { type: OptionType.Boolean, default: true } }, - path.join($hostInfo.isWindows ? process.env.AppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"), - $errors, $staticConfig); - - // On Windows we moved settings from LocalAppData to AppData. Move the existing file to keep the existing settings - // I guess we can remove this code after some grace period, say after 1.7 is out - if ($hostInfo.isWindows) { - try { - const shelljs = require("shelljs"), - oldSettings = path.join(process.env.LocalAppData, ".nativescript-cli", "user-settings.json"), - newSettings = path.join(process.env.AppData, ".nativescript-cli", "user-settings.json"); - if (shelljs.test("-e", oldSettings) && !shelljs.test("-e", newSettings)) { - shelljs.mkdir(path.join(process.env.AppData, ".nativescript-cli")); - shelljs.mv(oldSettings, newSettings); - } - } catch (err) { - // ignore the error - it is too early to use $logger here - } - } + $errors, $staticConfig, $settingsService); const that = (this); // if justlaunch is set, it takes precedence over the --watch flag and the default true value diff --git a/lib/services/extensibility-service.ts b/lib/services/extensibility-service.ts index 0ed6c3a8eb..c96df2117a 100644 --- a/lib/services/extensibility-service.ts +++ b/lib/services/extensibility-service.ts @@ -4,7 +4,7 @@ import * as constants from "../constants"; export class ExtensibilityService implements IExtensibilityService { private get pathToExtensions(): string { - return path.join(path.resolve(this.$options.profileDir), "extensions"); + return path.join(this.$settingsService.getProfileDir(), "extensions"); } private get pathToPackageJson(): string { @@ -14,7 +14,7 @@ export class ExtensibilityService implements IExtensibilityService { constructor(private $fs: IFileSystem, private $logger: ILogger, private $npm: INodePackageManager, - private $options: IOptions, + private $settingsService: ISettingsService, private $requireService: IRequireService) { } diff --git a/lib/services/user-settings-service.ts b/lib/services/user-settings-service.ts index a89c8495e1..ec0c0ca670 100644 --- a/lib/services/user-settings-service.ts +++ b/lib/services/user-settings-service.ts @@ -3,9 +3,9 @@ import * as userSettingsServiceBaseLib from "../common/services/user-settings-se class UserSettingsService extends userSettingsServiceBaseLib.UserSettingsServiceBase { constructor($fs: IFileSystem, - $options: IOptions, + $settingsService: ISettingsService, $lockfile: ILockFile) { - const userSettingsFilePath = path.join($options.profileDir, "user-settings.json"); + const userSettingsFilePath = path.join($settingsService.getProfileDir(), "user-settings.json"); super(userSettingsFilePath, $fs, $lockfile); } diff --git a/test/android-project-properties-manager.ts b/test/android-project-properties-manager.ts index a92ab97f40..1c51a3a75b 100644 --- a/test/android-project-properties-manager.ts +++ b/test/android-project-properties-manager.ts @@ -8,6 +8,7 @@ import * as LoggerLib from "../lib/common/logger"; import * as ConfigLib from "../lib/config"; import * as OptionsLib from "../lib/options"; import * as yok from "../lib/common/yok"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; import * as path from "path"; import temp = require("temp"); temp.track(); @@ -23,6 +24,7 @@ function createTestInjector(): IInjector { testInjector.register("logger", LoggerLib.Logger); testInjector.register("config", ConfigLib.Configuration); testInjector.register("options", OptionsLib.Options); + testInjector.register("settingsService", SettingsService); return testInjector; } diff --git a/test/commands/post-install.ts b/test/commands/post-install.ts index 51f4dd8e02..81505cde77 100644 --- a/test/commands/post-install.ts +++ b/test/commands/post-install.ts @@ -1,6 +1,7 @@ import { Yok } from "../../lib/common/yok"; import { assert } from "chai"; import { PostInstallCliCommand } from "../../lib/commands/post-install"; +import { SettingsService } from "../../lib/common/test/unit-tests/stubs"; const createTestInjector = (): IInjector => { const testInjector = new Yok(); @@ -38,6 +39,8 @@ const createTestInjector = (): IInjector => { printMarkdown: (...args: any[]): void => undefined }); + testInjector.register("settingsService", SettingsService); + testInjector.registerCommand("post-install-cli", PostInstallCliCommand); return testInjector; diff --git a/test/debug.ts b/test/debug.ts index a5753a12c6..0d529a6f9b 100644 --- a/test/debug.ts +++ b/test/debug.ts @@ -11,6 +11,8 @@ import { AndroidDebugBridge } from "../lib/common/mobile/android/android-debug-b import { AndroidDebugBridgeResultHandler } from "../lib/common/mobile/android/android-debug-bridge-result-handler"; import { DebugCommandErrors } from "../lib/constants"; import { CONNECTED_STATUS, UNREACHABLE_STATUS } from "../lib/common/constants"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; + const helpers = require("../lib/common/helpers"); const originalIsInteracive = helpers.isInteractive; @@ -73,6 +75,7 @@ function createTestInjector(): IInjector { return null; } }); + testInjector.register("settingsService", SettingsService); return testInjector; } diff --git a/test/ios-project-service.ts b/test/ios-project-service.ts index 30b7e58629..dfccaaf237 100644 --- a/test/ios-project-service.ts +++ b/test/ios-project-service.ts @@ -33,6 +33,7 @@ import * as constants from "../lib/constants"; import { assert } from "chai"; import { IOSProvisionService } from "../lib/services/ios-provision-service"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; import temp = require("temp"); temp.track(); @@ -114,6 +115,8 @@ function createTestInjector(projectPath: string, projectName: string): IInjector testInjector.register("npmInstallationManager", NpmInstallationManager); testInjector.register("npm", NodePackageManager); testInjector.register("xCConfigService", XCConfigService); + testInjector.register("settingsService", SettingsService); + return testInjector; } diff --git a/test/npm-installation-manager.ts b/test/npm-installation-manager.ts index fa06505ca0..1c35146e37 100644 --- a/test/npm-installation-manager.ts +++ b/test/npm-installation-manager.ts @@ -9,6 +9,7 @@ import * as OptionsLib from "../lib/options"; import * as StaticConfigLib from "../lib/config"; import * as yok from "../lib/common/yok"; import ChildProcessLib = require("../lib/common/child-process"); +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; function createTestInjector(): IInjector { const testInjector = new yok.Yok(); @@ -21,6 +22,7 @@ function createTestInjector(): IInjector { testInjector.register("hostInfo", HostInfoLib.HostInfo); testInjector.register("staticConfig", StaticConfigLib.StaticConfig); testInjector.register("childProcess", ChildProcessLib.ChildProcess); + testInjector.register("settingsService", SettingsService); testInjector.register("npmInstallationManager", NpmInstallationManagerLib.NpmInstallationManager); diff --git a/test/npm-support.ts b/test/npm-support.ts index 4f5f08d0a0..e7ea09d444 100644 --- a/test/npm-support.ts +++ b/test/npm-support.ts @@ -28,6 +28,7 @@ import { XmlValidator } from "../lib/xml-validator"; import ProjectChangesLib = require("../lib/services/project-changes-service"); import { Messages } from "../lib/common/messages/messages"; import { NodeModulesDependenciesBuilder } from "../lib/tools/node-modules/node-modules-dependencies-builder"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; import path = require("path"); import temp = require("temp"); @@ -86,7 +87,7 @@ function createTestInjector(): IInjector { }); testInjector.register("messages", Messages); testInjector.register("nodeModulesDependenciesBuilder", NodeModulesDependenciesBuilder); - + testInjector.register("settingsService", SettingsService); testInjector.register("devicePathProvider", {}); return testInjector; diff --git a/test/platform-commands.ts b/test/platform-commands.ts index 2a08302440..ec46eb4cac 100644 --- a/test/platform-commands.ts +++ b/test/platform-commands.ts @@ -21,6 +21,7 @@ import { XmlValidator } from "../lib/xml-validator"; import * as ChildProcessLib from "../lib/common/child-process"; import ProjectChangesLib = require("../lib/services/project-changes-service"); import { Messages } from "../lib/common/messages/messages"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; let isCommandExecuted = true; @@ -151,6 +152,7 @@ function createTestInjector() { testInjector.register("helpService", { showCommandLineHelp: async (): Promise => (undefined) }); + testInjector.register("settingsService", SettingsService); return testInjector; } diff --git a/test/platform-service.ts b/test/platform-service.ts index 1db73a785b..ecf13dd7e6 100644 --- a/test/platform-service.ts +++ b/test/platform-service.ts @@ -21,6 +21,7 @@ import { PreparePlatformJSService } from "../lib/services/prepare-platform-js-se import * as ChildProcessLib from "../lib/common/child-process"; import ProjectChangesLib = require("../lib/services/project-changes-service"); import { Messages } from "../lib/common/messages/messages"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; require("should"); const temp = require("temp"); @@ -94,6 +95,7 @@ function createTestInjector() { testInjector.register("helpService", { showCommandLineHelp: async (): Promise => (undefined) }); + testInjector.register("settingsService", SettingsService); return testInjector; } diff --git a/test/plugin-variables-service.ts b/test/plugin-variables-service.ts index 2beb1737e0..6e51f32899 100644 --- a/test/plugin-variables-service.ts +++ b/test/plugin-variables-service.ts @@ -11,6 +11,7 @@ import { ProjectHelper } from "../lib/common/project-helper"; import { StaticConfig } from "../lib/config"; import { MessagesService } from "../lib/common/services/messages-service"; import { Yok } from '../lib/common/yok'; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; import * as stubs from './stubs'; import * as path from "path"; import * as temp from "temp"; @@ -37,6 +38,7 @@ function createTestInjector(): IInjector { } }); testInjector.register("staticConfig", StaticConfig); + testInjector.register("settingsService", SettingsService); return testInjector; } diff --git a/test/plugins-service.ts b/test/plugins-service.ts index 1f5953cec1..7a07e480a1 100644 --- a/test/plugins-service.ts +++ b/test/plugins-service.ts @@ -30,6 +30,7 @@ import { ProjectFilesProvider } from "../lib/providers/project-files-provider"; import { MobilePlatformsCapabilities } from "../lib/mobile-platforms-capabilities"; import { DevicePlatformsConstants } from "../lib/common/mobile/device-platforms-constants"; import { XmlValidator } from "../lib/xml-validator"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; import StaticConfigLib = require("../lib/config"); import * as path from "path"; import * as temp from "temp"; @@ -101,6 +102,7 @@ function createTestInjector() { testInjector.register("helpService", { showCommandLineHelp: async (): Promise => (undefined) }); + testInjector.register("settingsService", SettingsService); return testInjector; } diff --git a/test/project-service.ts b/test/project-service.ts index 2ed5961274..94add49581 100644 --- a/test/project-service.ts +++ b/test/project-service.ts @@ -18,6 +18,7 @@ import { assert } from "chai"; import { Options } from "../lib/options"; import { HostInfo } from "../lib/common/host-info"; import { ProjectTemplatesService } from "../lib/services/project-templates-service"; +import { SettingsService } from "../lib/common/test/unit-tests/stubs"; const mockProjectNameValidator = { validate: () => true @@ -156,6 +157,7 @@ class ProjectIntegrationTest { } }); this.testInjector.register("npmInstallationManager", NpmInstallationManager); + this.testInjector.register("settingsService", SettingsService); } } @@ -429,6 +431,7 @@ describe("Project Service Tests", () => { testInjector.register("staticConfig", {}); testInjector.register("projectHelper", {}); testInjector.register("npmInstallationManager", {}); + testInjector.register("settingsService", SettingsService); return testInjector; }; diff --git a/test/services/extensibility-service.ts b/test/services/extensibility-service.ts index 26746cdf31..87978b60c3 100644 --- a/test/services/extensibility-service.ts +++ b/test/services/extensibility-service.ts @@ -3,6 +3,7 @@ import { Yok } from "../../lib/common/yok"; import * as stubs from "../stubs"; import { assert } from "chai"; import * as constants from "../../lib/constants"; +import { SettingsService } from "../../lib/common/test/unit-tests/stubs"; const path = require("path"); const originalResolve = path.resolve; @@ -20,9 +21,7 @@ describe("extensibilityService", () => { testInjector.register("fs", {}); testInjector.register("logger", stubs.LoggerStub); testInjector.register("npm", {}); - testInjector.register("options", { - profileDir: "profileDir" - }); + testInjector.register("settingsService", SettingsService); testInjector.register("requireService", { require: (pathToRequire: string): any => undefined }); @@ -121,10 +120,11 @@ describe("extensibilityService", () => { it("passes full path to extensions dir for installation", async () => { const extensionName = "extension1"; const testInjector = getTestInjector(); - const options: IOptions = testInjector.resolve("options"); - options.profileDir = "my-profile-dir"; + const settingsService: ISettingsService = testInjector.resolve("settingsService"); + const profileDir = "my-profile-dir"; + settingsService.getProfileDir = () => profileDir; - const expectedDirForInstallation = path.join(options.profileDir, "extensions"); + const expectedDirForInstallation = path.join(profileDir, "extensions"); const argsPassedToNpmInstall = await getArgsPassedToNpmInstallDuringInstallExtensionCall(extensionName, testInjector); assert.deepEqual(argsPassedToNpmInstall.pathToSave, expectedDirForInstallation); }); @@ -514,12 +514,13 @@ describe("extensibilityService", () => { it("passes full path to extensions dir for uninstallation", async () => { const extensionName = "extension1"; const testInjector = getTestInjector(); - const options: IOptions = testInjector.resolve("options"); - options.profileDir = "my-profile-dir"; + const settingsService: ISettingsService = testInjector.resolve("settingsService"); + const profileDir = "my-profile-dir"; + settingsService.getProfileDir = () => profileDir; - const expectedDirForInstallation = path.join(options.profileDir, "extensions"); + const expectedDirForUninstall = path.join(profileDir, "extensions"); const argsPassedToNpmUninstall = await getArgsPassedToNpmUninstallDuringUninstallExtensionCall(extensionName, testInjector); - assert.deepEqual(argsPassedToNpmUninstall.pathToSave, expectedDirForInstallation); + assert.deepEqual(argsPassedToNpmUninstall.pathToSave, expectedDirForUninstall); }); });