Merge pull request #146 from detro/dev-commonjs_fileio

99% with the FS API
1.3
Ariya Hidayat 2011-09-01 00:08:24 -07:00
commit 4a6154b5bd
9 changed files with 242 additions and 103 deletions

View File

@ -189,17 +189,12 @@ bool FileSystem::makeTree(const QString &path) const
return QDir().mkpath(path);
}
bool FileSystem::remove(const QString &path) const
{
return QFile::remove(path);
}
bool FileSystem::removeDirectory(const QString &path) const
bool FileSystem::_removeDirectory(const QString &path) const
{
return QDir().rmdir(path);
}
bool FileSystem::removeTree(const QString &path) const
bool FileSystem::_removeTree(const QString &path) const
{
QDir dir(path);
bool res = false;
@ -207,16 +202,16 @@ bool FileSystem::removeTree(const QString &path) const
if (dir.exists()) {
foreach(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
if (info.isDir()) {
res = removeTree(info.absoluteFilePath());
res = _removeTree(info.absoluteFilePath());
} else {
res = remove(info.absoluteFilePath());
res = _remove(info.absoluteFilePath());
}
if (!res) {
return res;
}
}
res = removeDirectory(path);
res = _removeDirectory(path);
}
return res;
@ -303,3 +298,12 @@ QObject *FileSystem::_open(const QString &path, const QString &mode) const
qDebug() << "FileSystem::open - " << "Couldn't be opened:" << path;
return NULL;
}
bool FileSystem::_remove(const QString &path) const
{
return QFile::remove(path);
}
bool FileSystem::_copy(const QString &source, const QString &destination) const {
return QFile(source).copy(destination);
}

View File

@ -72,16 +72,10 @@ public:
public slots:
// Attributes
// 'size(path)' implemented in "bootstrap.js" JavaScript shim, using '_size(path)'
// 'size(path)' implemented in "fs-shim.js" using '_size(path)'
int _size(const QString &path) const;
QVariant lastModified(const QString &path) const;
// Files / Directories
// - copy()
// - move()
// - touch(path, date)
// - rename()
// Directory
// - copyTree(source, target) //< copies files from a source path to a target path,
// copying the files of the source tree to the corresponding locations
@ -89,16 +83,22 @@ public slots:
// symbolic links to directories.
bool makeDirectory(const QString &path) const;
bool makeTree(const QString &path) const;
bool removeDirectory(const QString &path) const;
bool removeTree(const QString &path) const;
// 'removeDirectory(path)' implemented in "fs-shim.js" using '_removeDirectory(path)'
bool _removeDirectory(const QString &path) const;
// 'removeTree(path)' implemented in "fs-shim.js" using '_removeTree(path)'
bool _removeTree(const QString &path) const;
// Files
// 'open(path, mode)' implemented in "bootstrap.js" JavaScript shim, using '_open(path, mode)'
// 'open(path, mode)' implemented in "fs-shim.js" using '_open(path, mode)'
QObject *_open(const QString &path, const QString &mode) const;
// 'read(path)' implemented in "bootstrap.js" JavaScript shim
// 'write(path, mode)' implemented in the "bootstrap.js" JavaScript shim
bool remove(const QString &path) const;
// 'read(path)' implemented in "fs-shim.js"
// 'write(path, mode)' implemented in the "fs-shim.js"
// 'remove(path)' implemented in "fs-shim.js" using '_remove(path)'
bool _remove(const QString &path) const;
// 'copy(source, destination)' implemented in "fs-shim.js" using '_copy(source, destination)'
bool _copy(const QString &source, const QString &destination) const;
// 'move(source, destination)' implemented in "fs-shim.js"
// 'touch(path)' implemented in "fs-shim.js"
// Listing
QStringList list(const QString &path) const;

151
src/fs-shim.js Normal file
View File

@ -0,0 +1,151 @@
/*jslint sloppy: true, nomen: true */
/*global window:true,phantom:true,fs:true */
/*
This file is part of the PhantomJS project from Ofi Labs.
Copyright (C) 2011 Ivan De Marino <ivan.de.marino@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// window.fs
// JavaScript "shim" to throw exceptions in case a critical operation fails.
/** Open and return a "file" object.
* It will throw exception if it fails.
*
* @param path Path of the file to open
* @param mode Open Mode. A string made of 'r', 'w', 'a/+' characters.
* @return "file" object
*/
window.fs.open = function (path, mode) {
var file = window.fs._open(path, mode);
if (file) {
return file;
}
throw "Unable to open file '" + path + "'";
};
/** Open, read and return content of a file.
* It will throw an exception if it fails.
*
* @param path Path of the file to read from
* @return file content
*/
window.fs.read = function (path) {
var f = fs.open(path, 'r'),
content = f.read();
f.close();
return content;
};
/** Open and write content to a file
* It will throw an exception if it fails.
*
* @param path Path of the file to read from
* @param content Content to write to the file
* @param mode Open Mode. A string made of 'w' or 'a / +' characters.
*/
window.fs.write = function (path, content, mode) {
var f = fs.open(path, mode);
f.write(content);
f.close();
};
/** Return the size of a file, in bytes.
* It will throw an exception if it fails.
*
* @param path Path of the file to read the size of
* @return File size in bytes
*/
window.fs.size = function (path) {
var size = fs._size(path);
if (size !== -1) {
return size;
}
throw "Unable to read file '" + path + "' size";
};
/** Copy a file.
* It will throw an exception if it fails.
*
* @param source Path of the source file
* @param destination Path of the destination file
*/
window.fs.copy = function (source, destination) {
if (!fs._copy(source, destination)) {
throw "Unable to copy file '" + source + "' at '" + destination + "'";
}
};
/** Move a file.
* It will throw an exception if it fails.
*
* @param source Path of the source file
* @param destination Path of the destination file
*/
window.fs.move = function (source, destination) {
fs.copy(source, destination);
fs.remove(source);
};
/** Removes a file.
* It will throw an exception if it fails.
*
* @param path Path of the file to remove
*/
window.fs.remove = function (path) {
if (!fs._remove(path)) {
throw "Unable to remove file '" + path + "'";
}
};
/** Removes a directory.
* It will throw an exception if it fails.
*
* @param path Path of the directory to remove
*/
window.fs.removeDirectory = function (path) {
if (!fs._removeDirectory(path)) {
throw "Unable to remove directory '" + path + "'";
}
};
/** Removes a directory tree.
* It will throw an exception if it fails.
*
* @param path Path of the directory tree to remove
*/
window.fs.removeTree = function (path) {
if (!fs._removeTree(path)) {
throw "Unable to remove directory tree '" + path + "'";
}
};
window.fs.touch = function (path) {
fs.write(path, "", 'a');
};

View File

@ -107,21 +107,20 @@ Phantom::Phantom(QObject *parent)
setLibraryPath(QFileInfo(m_config.scriptFile()).dir().absolutePath());
// Add 'phantom' and 'fs' object to the global scope
m_page->mainFrame()->addToJavaScriptWindowObject("phantom", this);
m_page->mainFrame()->addToJavaScriptWindowObject("fs", &m_filesystem);
QFile file(":/bootstrap.js");
if (!file.open(QFile::ReadOnly)) {
Terminal::instance()->cerr("Can not bootstrap!");
exit(1);
// Load all the required JavaScript 'shims'
QString jsShims[2] = {
":/webpage-shim.js",
":/fs-shim.js"
};
for (int i = 0, len = 2; i < len; ++i) {
QFile f(jsShims[i]);
f.open(QFile::ReadOnly); //< It's OK to assume this succeed. If it doesn't, we have a bigger problem.
m_page->mainFrame()->evaluateJavaScript(QString::fromUtf8(f.readAll()));
}
QString bootstrapper = QString::fromUtf8(file.readAll());
file.close();
if (bootstrapper.isEmpty()) {
Terminal::instance()->cerr("Can not bootstrap!");
exit(1);
}
m_page->mainFrame()->evaluateJavaScript(bootstrapper);
}
QStringList Phantom::args() const

View File

@ -3,7 +3,8 @@
<file>phantomjs-icon.png</file>
<file>coffee-script.js</file>
<file>usage.txt</file>
<file>bootstrap.js</file>
<file>webpage-shim.js</file>
<file>fs-shim.js</file>
<file>configurator.js</file>
</qresource>
</RCC>

View File

@ -179,63 +179,3 @@ window.WebPage = function (opts) {
return page;
};
// window.fs
// JavaScript "shim" to throw exceptions in case a critical operation fails.
/** Open and return a "file" object.
* It will throw exception if it fails.
*
* @param path Path of the file to open
* @param mode Open Mode. A string made of 'r', 'w', 'a/+' characters.
* @return "file" object
*/
window.fs.open = function (path, mode) {
var file = window.fs._open(path, mode);
if (file) {
return file;
}
throw "Unable to open file '" + path + "'";
};
/** Open, read and return content of a file.
* It will throw an exception if it fails.
*
* @param path Path of the file to read from
* @return file content
*/
window.fs.read = function (path) {
var f = fs.open(path, 'r'),
content = f.read();
f.close();
return content;
};
/** Open and write content to a file
* It will throw an exception if it fails.
*
* @param path Path of the file to read from
* @param content Content to write to the file
* @param mode Open Mode. A string made of 'w' or 'a / +' characters.
*/
window.fs.write = function (path, content, mode) {
var f = fs.open(path, mode);
f.write(content);
f.close();
};
/** Return the size of a file, in bytes.
* It will throw an exception if it fails.
*
* @param path Path fo the file to read the size of
* @return File size in bytes
*/
window.fs.size = function (path) {
var size = fs._size(path);
if (size !== -1) {
return size;
}
throw "Unable to read file '" + path + "' size";
};

View File

@ -1,5 +1,8 @@
describe("Basic Files API (read, write, remove, ...)", function() {
var FILENAME = "temp-01.test",
FILENAME_COPY = FILENAME + ".copy",
FILENAME_MOVED = FILENAME + ".moved",
FILENAME_EMPTY = FILENAME + ".empty",
ABSENT = "absent-01.test";
it("should be able to create and write a file", function() {
@ -13,6 +16,13 @@ describe("Basic Files API (read, write, remove, ...)", function() {
} catch (e) { }
expect(fs.exists(FILENAME)).toBeTruthy();
});
it("should be able to create (touch) an empty file", function() {
expect(fs.exists(FILENAME_EMPTY)).toBeFalsy();
fs.touch(FILENAME_EMPTY);
expect(fs.exists(FILENAME_EMPTY)).toBeTruthy();
expect(fs.size(FILENAME_EMPTY)).toEqual(0);
});
it("should be able to read content from a file", function() {
var content = "";
@ -25,15 +35,49 @@ describe("Basic Files API (read, write, remove, ...)", function() {
expect(content).toEqual("hello\nworld\n");
});
it("should be able to remove a file", function() {
expect(fs.exists(FILENAME)).toBeTruthy();
expect(fs.remove(FILENAME)).toBeTruthy();
expect(fs.exists(FILENAME)).toBeFalsy();
it("should be able to copy a file", function() {
expect(fs.exists(FILENAME_COPY)).toBeFalsy();
fs.copy(FILENAME, FILENAME_COPY);
expect(fs.exists(FILENAME_COPY)).toBeTruthy();
expect(fs.read(FILENAME)).toEqual(fs.read(FILENAME_COPY));
});
it("should be able to move a file", function() {
expect(fs.exists(FILENAME)).toBeTruthy();
var contentBeforeMove = fs.read(FILENAME);
fs.move(FILENAME, FILENAME_MOVED);
expect(fs.exists(FILENAME)).toBeFalsy();
expect(fs.exists(FILENAME_MOVED)).toBeTruthy();
expect(fs.read(FILENAME_MOVED)).toEqual(contentBeforeMove);
});
it("should be able to remove a (moved) file", function() {
expect(fs.exists(FILENAME_MOVED)).toBeTruthy();
fs.remove(FILENAME_MOVED);
expect(fs.exists(FILENAME_MOVED)).toBeFalsy();
});
it("should be able to remove a (copied) file", function() {
expect(fs.exists(FILENAME_COPY)).toBeTruthy();
fs.remove(FILENAME_COPY);
expect(fs.exists(FILENAME_COPY)).toBeFalsy();
});
it("should be able to remove an empty file", function() {
expect(fs.exists(FILENAME_EMPTY)).toBeTruthy();
fs.remove(FILENAME_EMPTY);
expect(fs.exists(FILENAME_EMPTY)).toBeFalsy();
});
it("should throw an exception when trying to open for read a non existing file", function(){
expect(function(){
fs.open(ABSENT, "r");
}).toThrow("Unable to open file '"+ ABSENT +"'");
});
it("should throw an exception when trying to copy a non existing file", function() {
expect(function(){
fs.copy(ABSENT, FILENAME_COPY);
}).toThrow("Unable to copy file '" + ABSENT + "' at '" + FILENAME_COPY + "'");
});
});

View File

@ -6,7 +6,7 @@ describe("Attributes Files API", function() {
it("should throw an exception when trying to read the size of a non existing file", function(){
expect(function(){
fs.size(ABSENT, "r");
fs.size(ABSENT);
}).toThrow("Unable to read file '"+ ABSENT +"' size");
});
@ -41,6 +41,6 @@ describe("Attributes Files API", function() {
});
it("should remove temporary file '"+ FILENAME +"'", function(){
expect(fs.remove(FILENAME)).toBeTruthy();
fs.remove(FILENAME);
});
});

View File

@ -20,6 +20,6 @@ describe("Paths Files API", function() {
it("shoudl return to previous Current Working Directory and remove temporary directory", function() {
expect(fs.changeWorkingDirectory(START_CWD)).toBeTruthy();
expect(fs.removeTree(TEST_DIR)).toBeTruthy();
fs.removeTree(TEST_DIR);
});
});