Skip to content

Commit

Permalink
Move vscode hosting functionality to disposable pattern (#6343)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjlav5 authored Sep 8, 2023
1 parent cc2d7ed commit b79fd2b
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 113 deletions.
18 changes: 9 additions & 9 deletions firebase-vscode/src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ import { FirebaseConfig } from "../../../src/firebaseConfig";
import { RC, RCData } from "../../../src/rc";
import { Config } from "../../../src/config";

export const firebaseRC = signal<RCData | undefined>(undefined);
export const firebaseRC = signal<RC | undefined>(undefined);

export const firebaseJSON = signal<FirebaseConfig | undefined>(undefined);
export const firebaseConfig = signal<Config | undefined>(undefined);

export function registerConfig(broker: ExtensionBrokerImpl): Disposable {
firebaseRC.value = readRC();
firebaseJSON.value = readJSON();
firebaseConfig.value = readConfig();

effect(() => {
broker.send("notifyFirebaseConfig", {
firebaseJson: firebaseJSON.value,
firebaseRC: firebaseRC.value,
firebaseJson: firebaseConfig.value.data,
firebaseRC: firebaseRC.value.data,
});
});

Expand All @@ -32,7 +32,7 @@ export function registerConfig(broker: ExtensionBrokerImpl): Disposable {

const jsonWatcher = createWatcher("firebase.json");
jsonWatcher.onDidChange(() => {
firebaseJSON.value = readJSON();
firebaseConfig.value = readConfig();
});

return {
Expand All @@ -48,20 +48,20 @@ function readRC() {
try {
const rc = RC.loadFile(path.join(configPath, ".firebaserc"));
// RC.loadFile doesn't throw if not found, it just returns an empty object
return isEmpty(rc.data) ? undefined : rc.data;
return isEmpty(rc.data) ? undefined : rc;
} catch (e) {
pluginLogger.error(e.message);
throw e;
}
}

function readJSON() {
function readConfig() {
const configPath = getConfigPath();
try {
const json = Config.load({
configPath: path.join(configPath, "firebase.json"),
});
return json.data;
return json;
} catch (e) {
if (e.status === 404) {
return undefined;
Expand Down
17 changes: 14 additions & 3 deletions firebase-vscode/src/core/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { ExtensionBrokerImpl } from "../extension-broker";
import { computed, effect, signal } from "@preact/signals-react";
import { firebaseRC } from "./config";
import { FirebaseProjectMetadata } from "../types/project";
import { currentUserId } from "./user";
import { currentUser } from "./user";
import { listProjects } from "../cli";
import { debuglog } from "util";
import { pluginLogger } from "../logger-wrapper";

/** Available projects */
Expand All @@ -17,14 +16,26 @@ export const currentProjectId = signal("");
/** Gets the currently selected project, fallback to first default project in RC file */
export const currentProject = computed<FirebaseProjectMetadata | undefined>(
() => {
const userProjects = projects.value[currentUserId.value] ?? [];
const userProjects = projects.value[currentUser.value?.email ?? ""] ?? [];
const wantProjectId =
currentProjectId.value || firebaseRC.value.projects["default"];
return userProjects.find((p) => p.projectId === wantProjectId);
}
);

export function registerProject(broker: ExtensionBrokerImpl): Disposable {
effect(async () => {
const user = currentUser.value;
if (user) {
pluginLogger.info("(Core:Project) New user detected, fetching projects");
const userProjects = await listProjects();
projects.value = {
...projects.value,
[user.email]: userProjects,
};
}
});

effect(() => {
broker.send("notifyProjectChanged", {
projectId: currentProject.value?.projectId ?? "",
Expand Down
4 changes: 3 additions & 1 deletion firebase-vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { logSetup, pluginLogger } from "./logger-wrapper";
import { registerWebview } from "./webview";
import { registerCore } from "./core";
import { getSettings } from "./utils/settings";
import { registerHosting } from "./hosting";

// This method is called when your extension is activated
export function activate(context: vscode.ExtensionContext) {
Expand All @@ -34,6 +35,7 @@ export function activate(context: vscode.ExtensionContext) {
name: "sidebar",
broker,
context,
})
}),
registerHosting(broker)
);
}
116 changes: 116 additions & 0 deletions firebase-vscode/src/hosting/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import vscode, { Disposable } from "vscode";
import { ExtensionBrokerImpl } from "../extension-broker";
import { effect, signal } from "@preact/signals-react";
import { ChannelWithId } from "../messaging/types";
import { deployToHosting, getChannels, initHosting } from "../cli";
import { firebaseConfig } from "../core/config";
import { pluginLogger, showOutputChannel } from "../logger-wrapper";
import { currentOptions } from "../options";
import { currentProject, currentProjectId } from "../core/project";
import { getSettings } from "../utils/settings";
import { discover } from "../../../src/frameworks";

const channels = signal<ChannelWithId[]>([]);

export function registerHosting(broker: ExtensionBrokerImpl): Disposable {
// Refresh channels when project changes
effect(async () => {
if (currentProject.value) {
pluginLogger.info("(Hosting) New project detected, fetching channels");
channels.value = await getChannels(firebaseConfig.peek());
}
});

effect(() => {
pluginLogger.info("(Hosting) New channels loaded", channels.value);
broker.send("notifyChannels", { channels: channels.value });
});

broker.on("selectAndInitHostingFolder", async ({ singleAppSupport }) => {
showOutputChannel();

let currentFramework: string | undefined = undefined;
// Note: discover() takes a few seconds. No need to block users that don't
// have frameworks support enabled.
const { useFrameworks } = getSettings();
if (useFrameworks) {
currentFramework = await discover(currentOptions.cwd, false);
pluginLogger.debug(
"(Hosting) Searching for a web framework in this project."
);
}

let success = false;
if (currentFramework) {
pluginLogger.debug(
"(Hosting) Detected web framework, launching frameworks init."
);
success = await initHosting({
spa: singleAppSupport,
useFrameworks: true,
});
} else {
const options: vscode.OpenDialogOptions = {
canSelectMany: false,
openLabel: `Select distribution/public folder for ${currentProject.value?.projectId}`,
canSelectFiles: false,
canSelectFolders: true,
};
const fileUri = await vscode.window.showOpenDialog(options);
if (fileUri && fileUri[0] && fileUri[0].fsPath) {
const publicFolderFull = fileUri[0].fsPath;
const publicFolder = publicFolderFull.substring(
currentOptions.cwd.length + 1
);
success = await initHosting({
spa: singleAppSupport,
public: publicFolder,
useFrameworks: false,
});
}
}

broker.send("notifyHostingInitDone", {
success,
projectId: currentProject.value?.projectId,
folderPath: currentOptions.cwd,
framework: currentFramework,
});

if (success) {
channels.value = await getChannels(firebaseConfig.value);
}
});

broker.on("hostingDeploy", async ({ target: deployTarget }) => {
showOutputChannel();

pluginLogger.info(
`(Hosting) Starting deployment of project ` +
`${currentProject.value?.projectId} to channel: ${deployTarget}`
);

const deployResponse = await deployToHosting(
firebaseConfig.value,
deployTarget
);

if (deployResponse.success) {
pluginLogger.info("(Hosting) Refreshing channels");
channels.value = await getChannels(firebaseConfig.value);
}

broker.send("notifyHostingDeploy", deployResponse);
});

// TODO: this should be either more specific OR we should pass the title and prompt via the generic message
broker.on("promptUserForInput", async () => {
const response = await vscode.window.showInputBox({
title: "New Preview Channel",
prompt: "Enter a name for the new preview channel",
});
broker.send("notifyPreviewChannelResponse", { id: response });
});

return { dispose() {} };
}
101 changes: 1 addition & 100 deletions firebase-vscode/src/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,18 @@ import {
import { User } from "../../src/types/auth";
import { currentOptions } from "./options";
import { selectProjectInMonospace } from "../../src/monospace";
import { pluginLogger, showOutputChannel } from "./logger-wrapper";
import { discover } from "../../src/frameworks";
import { pluginLogger } from "./logger-wrapper";
import {
readAndSendFirebaseConfigs,
setupFirebaseJsonAndRcFileSystemWatcher,
updateFirebaseRCProject,
} from "./config-files";
import { ServiceAccountUser } from "../common/types";
import { getSettings } from "./utils/settings";

let users: Array<ServiceAccountUser | User> = [];
export let currentUser: User | ServiceAccountUser;
// Stores a mapping from user email to list of projects for that user
let projectsUserMapping = new Map<string, FirebaseProjectMetadata[]>();
let channels = null;

async function fetchUsers() {
const accounts = await getAccounts();
Expand Down Expand Up @@ -78,20 +75,9 @@ function updateCurrentUser(
}
}
broker.send("notifyUserChanged", { user: currentUser });
if (currentUser && previousCurrentUser?.email !== currentUser.email) {
fetchChannels(broker);
}
return currentUser;
}

async function fetchChannels(broker: ExtensionBrokerImpl, force = false) {
if (force || !channels) {
pluginLogger.debug("Fetching hosting channels");
channels = await getChannels(currentOptions.config);
}
broker.send("notifyChannels", { channels });
}

export async function setupWorkflow(
context: ExtensionContext,
broker: ExtensionBrokerImpl
Expand All @@ -104,9 +90,6 @@ export async function setupWorkflow(
await fetchUsers();
broker.send("notifyUsers", { users });
currentUser = updateCurrentUser(users, broker, currentUser);
if (users.length > 0) {
await fetchChannels(broker);
}

// Project
if (currentOptions.rc?.projects?.default) {
Expand Down Expand Up @@ -149,32 +132,6 @@ export async function setupWorkflow(

broker.on("selectProject", selectProject);

broker.on("selectAndInitHostingFolder", selectAndInitHosting);

broker.on("hostingDeploy", async ({ target: deployTarget }) => {
showOutputChannel();
pluginLogger.info(
`Starting deployment of project ` +
`${currentOptions.projectId} to channel: ${deployTarget}`
);
const { success, consoleUrl, hostingUrl } = await deployToHosting(
currentOptions.config,
deployTarget
);
broker.send("notifyHostingDeploy", { success, consoleUrl, hostingUrl });
if (success) {
fetchChannels(broker, true);
}
});

broker.on("promptUserForInput", async () => {
const response = await vscode.window.showInputBox({
title: "New Preview Channel",
prompt: "Enter a name for the new preview channel",
});
broker.send("notifyPreviewChannelResponse", { id: response });
});

context.subscriptions.push(
setupFirebaseJsonAndRcFileSystemWatcher(broker, context)
);
Expand Down Expand Up @@ -246,62 +203,6 @@ export async function setupWorkflow(
if (projectId) {
await updateFirebaseRCProject(context, "default", projectId);
broker.send("notifyProjectChanged", { projectId });
fetchChannels(broker, true);
}
}

async function selectAndInitHosting({ projectId, singleAppSupport }) {
showOutputChannel();
let currentFramework: string | undefined = undefined;
// Note: discover() takes a few seconds. No need to block users that don't
// have frameworks support enabled.
const { useFrameworks } = getSettings();
if (useFrameworks) {
currentFramework = await discover(currentOptions.cwd, false);
pluginLogger.debug("Searching for a web framework in this project.");
}
let success = false;
if (currentFramework) {
pluginLogger.debug("Detected web framework, launching frameworks init.");
success = await initHosting({
spa: singleAppSupport,
useFrameworks: true,
});
} else {
const options: vscode.OpenDialogOptions = {
canSelectMany: false,
openLabel: `Select distribution/public folder for ${projectId}`,
canSelectFiles: false,
canSelectFolders: true,
};
const fileUri = await vscode.window.showOpenDialog(options);
if (fileUri && fileUri[0] && fileUri[0].fsPath) {
const publicFolderFull = fileUri[0].fsPath;
const publicFolder = publicFolderFull.substring(
currentOptions.cwd.length + 1
);
success = await initHosting({
spa: singleAppSupport,
public: publicFolder,
useFrameworks: false,
});
}
}
if (success) {
readAndSendFirebaseConfigs(broker, context);
broker.send("notifyHostingInitDone", {
success,
projectId,
folderPath: currentOptions.cwd,
framework: currentFramework,
});
await fetchChannels(broker, true);
} else {
broker.send("notifyHostingInitDone", {
success,
projectId,
folderPath: currentOptions.cwd,
});
}
}
}

0 comments on commit b79fd2b

Please sign in to comment.