summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-25 05:08:54 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-25 05:08:54 +0000
commitbdbc87ca87fda52c3262240705d974030e9ed4b4 (patch)
tree6ca34f4c2ba9fe4b340075206846c115a5400d27 /chrome/browser/extensions
parent1692ea885338dd799ae9f47151d2a7fd4d1b10c4 (diff)
downloadchromium_src-bdbc87ca87fda52c3262240705d974030e9ed4b4.zip
chromium_src-bdbc87ca87fda52c3262240705d974030e9ed4b4.tar.gz
chromium_src-bdbc87ca87fda52c3262240705d974030e9ed4b4.tar.bz2
Add user script support to extensions.
This is implemented mostly by relying on the existing user script code. But since extension user scripts are declared, not discovered in a directory, I had to add support for adding 'lone' user scripts to UserScriptMaster. This led to a bit of refactoring. Note that this CL relies on: http://codereview.chromium.org/18352 Review URL: http://codereview.chromium.org/18198 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8614 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/extensions_service.cc25
-rw-r--r--chrome/browser/extensions/extensions_service.h7
-rw-r--r--chrome/browser/extensions/user_script_master.cc120
-rw-r--r--chrome/browser/extensions/user_script_master.h52
-rw-r--r--chrome/browser/extensions/user_script_master_unittest.cc2
5 files changed, 140 insertions, 66 deletions
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index 85d4fe8..e103821 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -9,6 +9,7 @@
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_service.h"
@@ -17,10 +18,12 @@
const FilePath::CharType* ExtensionsService::kInstallDirectoryName =
FILE_PATH_LITERAL("Extensions");
-ExtensionsService::ExtensionsService(const FilePath& profile_directory)
+ExtensionsService::ExtensionsService(const FilePath& profile_directory,
+ UserScriptMaster* user_script_master)
: message_loop_(MessageLoop::current()),
backend_(new ExtensionsServiceBackend),
- install_directory_(profile_directory.Append(kInstallDirectoryName)) {
+ install_directory_(profile_directory.Append(kInstallDirectoryName)),
+ user_script_master_(user_script_master) {
}
ExtensionsService::~ExtensionsService() {
@@ -53,6 +56,24 @@ void ExtensionsService::OnExtensionsLoadedFromDirectory(
extensions_.insert(extensions_.end(), new_extensions->begin(),
new_extensions->end());
+ // Tell UserScriptMaster about any scripts in the loaded extensions.
+ for (ExtensionList::iterator extension = extensions_.begin();
+ extension != extensions_.end(); ++extension) {
+ const UserScriptList& scripts = (*extension)->user_scripts();
+ for (UserScriptList::const_iterator script = scripts.begin();
+ script != scripts.end(); ++script) {
+ user_script_master_->AddLoneScript(*script);
+ }
+ }
+
+ // Tell UserScriptMaster to also watch the extensions directory for changes
+ // and then kick off the first scan.
+ // TODO(aa): This should go away when we implement the --extension flag, since
+ // developing scripts in the Extensions directory will no longer be a common
+ // use-case.
+ user_script_master_->AddWatchedPath(install_directory_);
+ user_script_master_->StartScan();
+
NotificationService::current()->Notify(NOTIFY_EXTENSIONS_LOADED,
NotificationService::AllSources(),
Details<ExtensionList>(new_extensions));
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index ed5a81c..1a78d0a 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -15,6 +15,7 @@
typedef std::vector<Extension*> ExtensionList;
class ExtensionsServiceBackend;
+class UserScriptMaster;
// Interface for the frontend to implement. Typically, this will be
// ExtensionsService, but it can also be a test harness.
@@ -38,7 +39,8 @@ class ExtensionsServiceFrontendInterface
// Manages installed and running Chromium extensions.
class ExtensionsService : public ExtensionsServiceFrontendInterface {
public:
- ExtensionsService(const FilePath& profile_directory);
+ ExtensionsService(const FilePath& profile_directory,
+ UserScriptMaster* user_script_master);
~ExtensionsService();
// Gets the list of currently installed extensions.
@@ -71,6 +73,9 @@ class ExtensionsService : public ExtensionsServiceFrontendInterface {
// The full path to the directory where extensions are installed.
FilePath install_directory_;
+ // The user script master for this profile.
+ scoped_refptr<UserScriptMaster> user_script_master_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionsService);
};
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 6efb577..66a8d70 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -13,7 +13,7 @@
#include "base/pickle.h"
#include "base/string_util.h"
#include "chrome/common/notification_service.h"
-#include "googleurl/src/gurl.h"
+#include "chrome/common/stl_util-inl.h"
#include "net/base/net_util.h"
// Defined in extension.h.
@@ -74,15 +74,15 @@ void UserScriptMaster::ScriptReloader::ParseMetadataHeader(
}
void UserScriptMaster::ScriptReloader::StartScan(
- MessageLoop* work_loop,
- const FilePath& script_dir) {
+ MessageLoop* work_loop, const FilePath& script_dir,
+ const UserScriptList& lone_scripts) {
// Add a reference to ourselves to keep ourselves alive while we're running.
// Balanced by NotifyMaster().
AddRef();
work_loop->PostTask(FROM_HERE,
NewRunnableMethod(this,
&UserScriptMaster::ScriptReloader::RunScan,
- script_dir));
+ script_dir, lone_scripts));
}
void UserScriptMaster::ScriptReloader::NotifyMaster(
@@ -99,8 +99,9 @@ void UserScriptMaster::ScriptReloader::NotifyMaster(
Release();
}
-void UserScriptMaster::ScriptReloader::RunScan(const FilePath script_dir) {
- base::SharedMemory* shared_memory = GetNewScripts(script_dir);
+void UserScriptMaster::ScriptReloader::RunScan(
+ const FilePath script_dir, const UserScriptList lone_scripts) {
+ base::SharedMemory* shared_memory = GetNewScripts(script_dir, lone_scripts);
// Post the new scripts back to the master's message loop.
master_message_loop_->PostTask(FROM_HERE,
@@ -110,45 +111,47 @@ void UserScriptMaster::ScriptReloader::RunScan(const FilePath script_dir) {
}
base::SharedMemory* UserScriptMaster::ScriptReloader::GetNewScripts(
- const FilePath& script_dir) {
- std::vector<std::wstring> scripts;
-
- file_util::FileEnumerator enumerator(script_dir, false,
- file_util::FileEnumerator::FILES,
- FILE_PATH_LITERAL("*.user.js"));
- for (FilePath file = enumerator.Next(); !file.value().empty();
- file = enumerator.Next()) {
- scripts.push_back(file.ToWStringHack());
+ const FilePath& script_dir, const UserScriptList& lone_scripts) {
+ UserScriptList all_scripts;
+
+ // Find all the scripts in |script_dir|.
+ if (!script_dir.value().empty()) {
+ file_util::FileEnumerator enumerator(script_dir, false,
+ file_util::FileEnumerator::FILES,
+ FILE_PATH_LITERAL("*.user.js"));
+ for (FilePath file = enumerator.Next(); !file.value().empty();
+ file = enumerator.Next()) {
+ all_scripts.push_back(UserScriptInfo());
+ UserScriptInfo& info = all_scripts.back();
+ info.url = GURL(std::string(kUserScriptURLScheme) + ":/" +
+ net::FilePathToFileURL(file.ToWStringHack()).ExtractFileName());
+ info.path = file;
+ }
}
- if (scripts.empty())
+ if (all_scripts.empty() && lone_scripts.empty())
return NULL;
- // Pickle scripts data.
- Pickle pickle;
- pickle.WriteSize(scripts.size());
- for (std::vector<std::wstring>::iterator path = scripts.begin();
- path != scripts.end(); ++path) {
- std::string url(kUserScriptURLScheme);
- url += ":/";
- url += net::FilePathToFileURL(*path).ExtractFileName();
+ // Add all the lone scripts.
+ all_scripts.insert(all_scripts.end(), lone_scripts.begin(),
+ lone_scripts.end());
- std::string contents;
+ // Load and pickle each script. Look for a metadata header if there are no
+ // matches specified already.
+ Pickle pickle;
+ pickle.WriteSize(all_scripts.size());
+ for (UserScriptList::iterator iter = all_scripts.begin();
+ iter != all_scripts.end(); ++iter) {
// TODO(aa): Support unicode script files.
- file_util::ReadFileToString(*path, &contents);
-
- std::vector<std::string> includes;
- ParseMetadataHeader(contents, &includes);
-
- // Write scripts as 'data' so that we can read it out in the slave without
- // allocating a new string.
- pickle.WriteData(url.c_str(), url.length());
- pickle.WriteData(contents.c_str(), contents.length());
- pickle.WriteSize(includes.size());
- for (std::vector<std::string>::iterator iter = includes.begin();
- iter != includes.end(); ++iter) {
- pickle.WriteString(*iter);
+ std::string contents;
+ file_util::ReadFileToString(iter->path.ToWStringHack(), &contents);
+
+ if (iter->matches.empty()) {
+ // TODO(aa): Handle errors parsing header.
+ ParseMetadataHeader(contents, &iter->matches);
}
+
+ PickleScriptData(*iter, contents, &pickle);
}
// Create the shared memory object.
@@ -171,22 +174,45 @@ base::SharedMemory* UserScriptMaster::ScriptReloader::GetNewScripts(
return shared_memory.release();
}
+void UserScriptMaster::ScriptReloader::PickleScriptData(
+ const UserScriptInfo& script, const std::string& contents, Pickle* pickle) {
+ // Write scripts as 'data' so that we can read it out in the slave without
+ // allocating a new string.
+ pickle->WriteData(script.url.spec().c_str(), script.url.spec().length());
+ pickle->WriteData(contents.c_str(), contents.length());
+ pickle->WriteSize(script.matches.size());
+ for (std::vector<std::string>::const_iterator iter = script.matches.begin();
+ iter != script.matches.end(); ++iter) {
+ pickle->WriteString(*iter);
+ }
+}
+
UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
- const FilePath& script_dir)
- : user_script_dir_(new FilePath(script_dir)),
- dir_watcher_(new DirectoryWatcher),
+ const FilePath& script_dir)
+ : user_script_dir_(script_dir),
worker_loop_(worker_loop),
pending_scan_(false) {
- // Watch our scripts directory for modifications.
- if (dir_watcher_->Watch(script_dir, this)) {
- // (Asynchronously) scan for our initial set of scripts.
- StartScan();
- }
+ if (!user_script_dir_.value().empty())
+ AddWatchedPath(script_dir);
}
UserScriptMaster::~UserScriptMaster() {
if (script_reloader_)
script_reloader_->DisownMaster();
+
+// TODO(aa): Enable this when DirectoryWatcher is implemented for linux and mac.
+#if defined(OS_WIN)
+ STLDeleteElements(&dir_watchers_);
+#endif
+}
+
+void UserScriptMaster::AddWatchedPath(const FilePath& path) {
+// TODO(aa): Enable this when DirectoryWatcher is implemented for linux and mac.
+#if defined(OS_WIN)
+ DirectoryWatcher* watcher = new DirectoryWatcher();
+ watcher->Watch(path, this);
+ dir_watchers_.push_back(watcher);
+#endif
}
void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) {
@@ -225,5 +251,5 @@ void UserScriptMaster::StartScan() {
if (!script_reloader_)
script_reloader_ = new ScriptReloader(this);
- script_reloader_->StartScan(worker_loop_, *user_script_dir_);
+ script_reloader_->StartScan(worker_loop_, user_script_dir_, lone_scripts_);
}
diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h
index 5167a65..1c1b095 100644
--- a/chrome/browser/extensions/user_script_master.h
+++ b/chrome/browser/extensions/user_script_master.h
@@ -14,6 +14,8 @@
#include "base/string_piece.h"
#include "googleurl/src/gurl.h"
+class Pickle;
+
struct UserScriptInfo {
GURL url;
FilePath path;
@@ -32,6 +34,19 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
UserScriptMaster(MessageLoop* worker, const FilePath& script_dir);
~UserScriptMaster();
+ // Add a single user script that exists outside the script directory.
+ void AddLoneScript(const UserScriptInfo& script) {
+ lone_scripts_.push_back(script);
+ }
+
+ // Add a watched directory. All scripts will be reloaded when any file in
+ // this directory changes.
+ void AddWatchedPath(const FilePath& path);
+
+ // Kicks off a process on the file thread to reload scripts from disk
+ // into a new chunk of shared memory and notify renderers.
+ void StartScan();
+
// Gets the segment of shared memory for the scripts.
base::SharedMemory* GetSharedMemory() const {
return shared_memory_.get();
@@ -44,7 +59,7 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
bool ScriptsReady() const { return shared_memory_.get() != NULL; }
// Returns the path to the directory user scripts are stored in.
- FilePath user_script_dir() const { return *user_script_dir_; }
+ FilePath user_script_dir() const { return user_script_dir_; }
private:
FRIEND_TEST(UserScriptMasterTest, Parse1);
@@ -69,7 +84,8 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
// Start a scan for scripts.
// Will always send a message to the master upon completion.
- void StartScan(MessageLoop* work_loop, const FilePath& script_dir);
+ void StartScan(MessageLoop* work_loop, const FilePath& script_dir,
+ const UserScriptList &external_scripts);
// The master is going away; don't call it back.
void DisownMaster() {
@@ -89,15 +105,20 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
void NotifyMaster(base::SharedMemory* memory);
// Runs on the File thread.
- // Scan the script directory for scripts, calling NotifyMaster when done.
- // The path is intentionally passed by value so its lifetime isn't tied
- // to the caller.
- void RunScan(const FilePath script_dir);
+ // Scan the specified directory and lone scripts, calling NotifyMaster when
+ // done. The parameters are intentionally passed by value so their lifetimes
+ // aren't tied to the caller.
+ void RunScan(const FilePath script_dir, const UserScriptList lone_scripts);
// Runs on the File thread.
- // Scan the script directory for scripts, returning either a
- // new SharedMemory or NULL on error.
- base::SharedMemory* GetNewScripts(const FilePath& script_dir);
+ // Scan the script directory and lone scripts, returning either a new
+ // SharedMemory or NULL on error.
+ base::SharedMemory* GetNewScripts(const FilePath& script_dir,
+ const UserScriptList& lone_scripts);
+
+ // Serialize script metadata and contents into the specified pickle.
+ void PickleScriptData(const UserScriptInfo& script,
+ const std::string& contents, Pickle* pickle);
// A pointer back to our master.
// May be NULL if DisownMaster() is called.
@@ -113,15 +134,11 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
// DirectoryWatcher::Delegate implementation.
virtual void OnDirectoryChanged(const FilePath& path);
- // Kicks off a process on the file thread to reload scripts from disk
- // into a new chunk of shared memory and notify renderers.
- void StartScan();
-
- // The directory containing user scripts.
- scoped_ptr<FilePath> user_script_dir_;
+ // The directories containing user scripts.
+ FilePath user_script_dir_;
// The watcher watches the profile's user scripts directory for new scripts.
- scoped_ptr<DirectoryWatcher> dir_watcher_;
+ std::vector<DirectoryWatcher*> dir_watchers_;
// The MessageLoop that the scanner worker runs on.
// Typically the file thread; configurable for testing.
@@ -134,6 +151,9 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
// Contains the scripts that were found the last time scripts were updated.
scoped_ptr<base::SharedMemory> shared_memory_;
+ // List of scripts outside of script directories we should also load.
+ UserScriptList lone_scripts_;
+
// If the script directory is modified while we're rescanning it, we note
// that we're currently mid-scan and then start over again once the scan
// finishes. This boolean tracks whether another scan is pending.
diff --git a/chrome/browser/extensions/user_script_master_unittest.cc b/chrome/browser/extensions/user_script_master_unittest.cc
index 0fa1932..f0f2dc2 100644
--- a/chrome/browser/extensions/user_script_master_unittest.cc
+++ b/chrome/browser/extensions/user_script_master_unittest.cc
@@ -74,6 +74,7 @@ TEST_F(UserScriptMasterTest, NoScripts) {
scoped_refptr<UserScriptMaster> master(
new UserScriptMaster(MessageLoop::current(), script_dir_));
+ master->StartScan();
message_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask);
message_loop_.Run();
@@ -110,6 +111,7 @@ TEST_F(UserScriptMasterTest, ExistingScripts) {
scoped_refptr<UserScriptMaster> master(
new UserScriptMaster(MessageLoop::current(), script_dir_));
+ master->StartScan();
message_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask);
message_loop_.Run();