Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ test/thirdparty/jasmine-reporters
!/src/extensions/dev/README.*

/src/extensions/disabled
/src/extensions/registry

# ignore .disabled file for default extensions
/src/extensions/default/*/.disabled
Expand Down
32 changes: 27 additions & 5 deletions gulpfile.js/thirdparty-lib-copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,37 @@

const { src, dest, series } = require('gulp');
const fs = require("fs");
const path = require('path');

// removed require('merge-stream') node module. it gives wired glob behavior and some files goes missing
const rename = require("gulp-rename");


// individual third party copy
function copyLicence(path, name) {
function copyLicence(filePath, name) {
console.log(`Copying licence file ${name}.markdown`);
return src(path)
return src(filePath)
.pipe(rename(`${name}.markdown`))
.pipe(dest('src/thirdparty/licences/'));
}

function renameFile(path, newName, destPath) {
console.log(`Renaming file ${path} to ${newName}`);
return src(path)
function renameFile(filePath, newName, destPath) {
console.log(`Renaming file ${filePath} to ${newName}`);
return src(filePath)
.pipe(rename(newName))
.pipe(dest(destPath));
}

function ensureDirectoryExists(filePath) {
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}

function downloadFile(url, outputPath) {
console.log(`Downloading file ${url} to ${outputPath}`);
ensureDirectoryExists(outputPath);
return fetch(url)
.then(x => {
if(x.status !== 200){
Expand Down Expand Up @@ -76,6 +86,11 @@ function _createListDirJson(dirPath, jsonFileName) {
fs.writeFileSync(`${dirPath}/${jsonFileName}`, JSON.stringify(filenames));
}

function _getConfigJSON() {
let configPath = "src/config.json";
console.log("Reading phoenix Config :", configPath);
return JSON.parse(fs.readFileSync(configPath, "utf8"));
}

/**
* Add thirdparty libs copied to gitignore except the licence file.
Expand Down Expand Up @@ -107,6 +122,13 @@ let copyThirdPartyLibs = series(
'src/thirdparty/bugsnag-performance.min.js'),
downloadFile.bind(downloadFile, 'https://d2wy8f7a9ursnm.cloudfront.net/v2/bugsnag-performance.min.js.map',
'src/thirdparty/bugsnag-performance.min.js.map'),
// phoenix extension registry cache for first time load
downloadFile.bind(downloadFile, _getConfigJSON().config.extension_registry,
'src/extensions/registry/registry.json'),
downloadFile.bind(downloadFile, _getConfigJSON().config.extension_registry_version,
'src/extensions/registry/registry_version.json'),
downloadFile.bind(downloadFile, _getConfigJSON().config.extension_registry_popularity,
'src/extensions/registry/popularity.json'),
// tern js
copyFiles.bind(copyFiles, ['node_modules/tern/defs/**/*'], 'src/thirdparty/tern/defs'),
copyFiles.bind(copyFiles, ['node_modules/tern/lib/**/*'], 'src/thirdparty/tern/lib'),
Expand Down
51 changes: 50 additions & 1 deletion src/extensibility/ExtensionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ define(function (require, exports, module) {
Strings = require("strings"),
StringUtils = require("utils/StringUtils"),
ThemeManager = require("view/ThemeManager"),
TaskManager = require("features/TaskManager"),
Metrics = require("utils/Metrics");

const EXTENSION_REGISTRY_LOCAL_STORAGE_KEY = Phoenix.isTestWindow ?
Expand Down Expand Up @@ -338,11 +339,22 @@ define(function (require, exports, module) {
return filteredRegistry;
}

function _getTaskManager() {
if(Phoenix.isTestWindow){
return {
close: ()=>{}
};
}
return TaskManager.addNewTask(Strings.EXTENSIONS_REGISTRY_TASK_TITLE,
Strings.EXTENSIONS_REGISTRY_TASK_MESSAGE,
`<i class="fa-solid fa-list"></i>`);
}

/**
* Downloads the registry of Brackets extensions and stores the information in our
* extension info.
*
* @param {boolean} force - true to fetch registry from server fresh every time
* @param {boolean} [force] - true to fetch registry from server fresh every time
* @return {$.Promise} a promise that's resolved with the registry JSON data
* or rejected if the server can't be reached.
*/
Expand All @@ -355,6 +367,7 @@ define(function (require, exports, module) {

function _updateRegistry(newVersion) {
console.log("downloading extension registry: ", newVersion, brackets.config.extension_registry);
const downloadTask = _getTaskManager();
$.ajax({
url: brackets.config.extension_registry,
dataType: "json",
Expand All @@ -367,12 +380,15 @@ define(function (require, exports, module) {
if(!pendingDownloadRegistry.alreadyResolvedFromCache){
_populateExtensions(registry);
pendingDownloadRegistry.resolve();
pendingDownloadRegistry.alreadyResolvedFromCache = true;
}
}).finally(()=>{
pendingDownloadRegistry = null;
downloadTask.close();
});
})
.fail(function (err) {
downloadTask.close();
console.error("error Fetching Extension Registry", err);
if(!pendingDownloadRegistry.alreadyResolvedFromCache){
pendingDownloadRegistry.reject();
Expand All @@ -386,11 +402,31 @@ define(function (require, exports, module) {
return pendingDownloadRegistry.promise();
}

async function _getLocalRegistry() {
// the extension registry is like 1.5MB. A local copy is packaged in the src/extensions/registry/ folder
// so that on first launch, the user can see the extension manager instantly(though outdated).
// The local registry is created at build time and will get outdated if the user uses an old installer.
// but it will get updated when the user clicks on extension manager.
try {
const response = await fetch("extensions/registry/registry.json");
if (response.ok) {
return await response.json();
} else {
console.error(`Failed to fetch local registry: ${response.status} ${response.statusText}`);
return null;
}
} catch (error) {
console.error(`Error fetching local registry: ${error.message}`);
return null;
}
}

_getCachedRegistry() // never rejects
.then(registryJson => {
if(registryJson) {
// we always immediately but after the promise chain is setup after function return (some bug sigh)
// resolve for ui responsiveness and then check for updates.
console.log("Using cached extension registry");
setTimeout(()=>{
Metrics.countEvent(Metrics.EVENT_TYPE.EXTENSIONS, "registry", "cachedUse");
let registry = JSON.parse(registryJson);
Expand All @@ -399,6 +435,19 @@ define(function (require, exports, module) {
pendingDownloadRegistry.resolve();
}, 0);
pendingDownloadRegistry.alreadyResolvedFromCache = true;
} else {
_getLocalRegistry().then(localRegistry => {
if(!localRegistry ||
!pendingDownloadRegistry || pendingDownloadRegistry.alreadyResolvedFromCache) {
return;
}
console.log("Using outdated local extension registry as no cached registry found.");
Metrics.countEvent(Metrics.EVENT_TYPE.EXTENSIONS, "registry", "outdatedUse");
localRegistry = _filterIncompatibleEntries(localRegistry);
_populateExtensions(localRegistry);
pendingDownloadRegistry.resolve();
pendingDownloadRegistry.alreadyResolvedFromCache = true;
});
}
// check for latest updates even if we have cache
_shouldUpdateExtensionRegistry()
Expand Down
2 changes: 2 additions & 0 deletions src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,8 @@ define({
"EXTENSIONS_UPDATES_TITLE": "Updates",
"EXTENSIONS_LAST_UPDATED": "Last Updated",
"EXTENSIONS_DOWNLOADS": "Downloads",
"EXTENSIONS_REGISTRY_TASK_TITLE": "Updating Extension List",
"EXTENSIONS_REGISTRY_TASK_MESSAGE": "Downloading\u2026",

"INLINE_EDITOR_NO_MATCHES": "No matches available.",
"INLINE_EDITOR_HIDDEN_MATCHES": "All matches are collapsed. Expand the files listed at right to view matches.",
Expand Down
Loading