Introducing File I/O API in PhantomJS.

* This is the  squash of 30 commits, so it's meaty
* Inspired by HammerJS (see https://github.com/senchalabs/hammerjs)
* Not yet 100% complete
* Final aim is to provide a CommonJS/Filesystem compliant API (see http://wiki.commonjs.org/wiki/Filesystem)
1.3
Ivan De Marino 2011-06-14 11:28:51 +01:00
parent 1f2c80ba32
commit 6b04ee23c1
9 changed files with 430 additions and 41 deletions

View File

@ -0,0 +1,17 @@
# echoToFile.coffee - Write in a given file all the parameters passed on the CLI
if phantom.args.length < 2
console.log "Usage: echoToFile.js DESTINATION_FILE <arguments to echo...>"
phantom.exit()
else
content = ""
f = null
i = 1
while i < phantom.args.length
content += phantom.args[i] + (if i == phantom.args.length - 1 then "" else " ")
++i
f = phantom.fs.open(phantom.args[0], "w")
if f
f.writeLine content
f.close()
phantom.exit()

20
examples/echoToFile.js Normal file
View File

@ -0,0 +1,20 @@
// echoToFile.js - Write in a given file all the parameters passed on the CLI
if (phantom.args.length < 2) {
console.log("Usage: echoToFile.js DESTINATION_FILE <arguments to echo...>");
phantom.exit();
} else {
var content = '',
f = null;
for ( i= 1; i < phantom.args.length; ++i ) {
content += phantom.args[i] + (i === phantom.args.length-1 ? '' : ' ');
}
f = phantom.fs.open(phantom.args[0], "w");
if ( f ) {
f.writeLine(content);
f.close();
}
phantom.exit();
}

14
examples/scandir.coffee Normal file
View File

@ -0,0 +1,14 @@
# List all the files in a Tree of Directories
if phantom.args.length != 1
console.log "Usage: phantomjs scandir.js DIRECTORY_TO_SCAN"
phantom.exit()
scanDirectory = (path) ->
if phantom.fs.exists(path) and phantom.fs.isFile(path)
console.log path
else if phantom.fs.isDir(path)
phantom.fs.list(path).forEach (e) ->
scanDirectory path + "/" + e if e != "." and e != ".."
scanDirectory phantom.args[0]
phantom.exit()

20
examples/scandir.js Normal file
View File

@ -0,0 +1,20 @@
// List all the files in a Tree of Directories
if (phantom.args.length !== 1) {
console.log("Usage: phantomjs scandir.js DIRECTORY_TO_SCAN");
phantom.exit();
}
var scanDirectory = function (path) {
if (phantom.fs.exists(path) && phantom.fs.isFile(path)) {
console.log(path);
} else if (phantom.fs.isDir(path)) {
phantom.fs.list(path).forEach(function (e) {
if ( e !== "." && e !== ".." ) { //< Avoid loops
scanDirectory(path + '/' + e);
}
});
}
};
scanDirectory(phantom.args[0]);
phantom.exit();

218
src/filesystem.cpp Normal file
View File

@ -0,0 +1,218 @@
/*
This file is part of the PhantomJS project from Ofi Labs.
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@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.
*/
#include "filesystem.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
// File
// public:
File::File(QFile *openfile, QObject *parent) :
QObject(parent),
m_file(openfile)
{
m_fileStream.setDevice(m_file);
}
File::~File()
{
this->close();
}
// public slots:
QString File::read()
{
if ( m_file->isReadable() ) {
return m_fileStream.readAll();
}
qDebug() << "File::read - " << "Couldn't read:" << m_file->fileName();
return NULL;
}
bool File::write(const QString &data)
{
if ( m_file->isWritable() ) {
m_fileStream << data;
return true;
}
qDebug() << "File::write - " << "Couldn't write:" << m_file->fileName();
return false;
}
QString File::readLine()
{
if ( m_file->isReadable() ) {
return m_fileStream.readLine();
}
qDebug() << "File::readLine - " << "Couldn't read:" << m_file->fileName();
return NULL;
}
bool File::writeLine(const QString &data)
{
if ( write(data) && write("\n") ) {
return true;
}
qDebug() << "File::writeLine - " << "Couldn't write:" << m_file->fileName();
return false;
}
bool File::atEnd() const
{
if ( m_file->isReadable() ) {
return m_fileStream.atEnd();
}
qDebug() << "File::atEnd - " << "Couldn't read:" << m_file->fileName();
return false;
}
void File::flush()
{
if ( m_file ) {
m_fileStream.flush();
}
}
void File::close()
{
flush();
if ( m_file ) {
m_file->close();
delete m_file;
m_file = NULL;
}
deleteLater();
}
// FileSystem
// public:
FileSystem::FileSystem(QObject *parent) :
QObject(parent)
{ }
// public slots:
bool FileSystem::exists(const QString &path) const
{
return QFile::exists(path);
}
bool FileSystem::isDir(const QString &path) const
{
return QFileInfo(path).isDir();
}
bool FileSystem::isFile(const QString &path) const
{
return QFileInfo(path).isFile();
}
bool FileSystem::mkDir(const QString &path) const
{
return QDir().mkpath(path);
}
QStringList FileSystem::list(const QString &path) const
{
return QDir(path).entryList();
}
QString FileSystem::workDir() const
{
return QDir::currentPath();
}
QString FileSystem::separator() const
{
return QDir::separator();
}
QObject *FileSystem::open(const QString &path, const QString &mode) const
{
File *f = NULL;
QFile *_f = new QFile(path);
QFile::OpenMode modeCode = QFile::NotOpen;
QChar modeAsChar = 0;
// Ensure only one "mode character" has been selected
if ( mode.length() != 1) {
qDebug() << "FileSystem::open - " << "Wrong Mode string length:" << mode;
return false;
}
// Read out the mode
modeAsChar = mode[0];
// Determine the OpenMode
switch(modeAsChar.toAscii()) {
case 'r': case 'R': {
modeCode |= QFile::ReadOnly;
// Make sure there is something to read, otherwise return "false"
if ( !_f->exists() ) {
qDebug() << "FileSystem::open - " << "Trying to read a file that doesn't exist:" << path;
return false;
}
break;
}
case 'a': case 'A': {
modeCode |= QFile::Append;
// NOTE: no "break" here! This case will also execute the code for case 'w'.
}
case 'w': case 'W': {
modeCode |= QFile::WriteOnly;
// If the file doesn't exist and the desired path can't be created, return "false"
if ( !_f->exists() && !mkDir(QFileInfo(path).dir().absolutePath()) ) {
qDebug() << "FileSystem::open - " << "Full path coulnd't be created:" << path;
return false;
}
break;
}
default: {
qDebug() << "FileSystem::open - " << "Wrong Mode:" << mode;
return false;
}
}
// Try to Open
if ( _f->open(modeCode) ) {
f = new File(_f);
if ( f ) { return f; }
}
// Return "false" if the file couldn't be opened as requested
qDebug() << "FileSystem::open - " << "Couldn't be opened:" << path;
return false;
}
bool FileSystem::remove(const QString &path) const
{
return QFile::remove(path);
}

84
src/filesystem.h Normal file
View File

@ -0,0 +1,84 @@
/*
This file is part of the PhantomJS project from Ofi Labs.
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@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.
*/
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include <QObject>
#include <QStringList>
#include <QFile>
#include <QTextStream>
class File : public QObject
{
Q_OBJECT
public:
File(QFile *openfile, QObject *parent = 0);
virtual ~File();
public slots:
QString read();
bool write(const QString &data);
QString readLine();
bool writeLine(const QString &data);
bool atEnd() const;
void flush();
void close();
private:
QFile *m_file;
QTextStream m_fileStream;
};
class FileSystem : public QObject
{
Q_OBJECT
Q_PROPERTY(QString workDir READ workDir)
Q_PROPERTY(QString separator READ separator)
public:
FileSystem(QObject *parent = 0);
public slots:
bool exists(const QString &path) const;
bool isDir(const QString &path) const;
bool isFile(const QString &path) const;
bool mkDir(const QString &path) const;
QStringList list(const QString &path) const;
QString workDir() const;
QString separator() const;
QObject *open(const QString &path, const QString &mode) const;
bool remove(const QString &path) const;
};
#endif // FILESYSTEM_H

View File

@ -36,12 +36,14 @@
#include <QtWebKit>
#include <QDir>
#include <QFileInfo>
#include <QFile>
#include <gifwriter.h>
#include "consts.h"
#include "utils.h"
#include "webpage.h"
// public:
Phantom::Phantom(QObject *parent)
: QObject(parent)
, m_terminated(false)
@ -216,45 +218,6 @@ int Phantom::returnValue() const
return m_returnValue;
}
QVariantMap Phantom::version() const
{
QVariantMap result;
result["major"] = PHANTOMJS_VERSION_MAJOR;
result["minor"] = PHANTOMJS_VERSION_MINOR;
result["patch"] = PHANTOMJS_VERSION_PATCH;
return result;
}
QObject *Phantom::createWebPage()
{
WebPage *page = new WebPage(this);
page->applySettings(m_defaultPageSettings);
page->setNetworkAccessManager(m_netAccessMan);
page->setLibraryPath(QFileInfo(m_scriptFile).dir().absolutePath());
return page;
}
void Phantom::exit(int code)
{
m_terminated = true;
m_returnValue = code;
delete m_page;
m_page = 0;
QApplication::instance()->exit(code);
}
bool Phantom::injectJs(const QString &jsFilePath) {
return Utils::injectJsInFrame(jsFilePath, libraryPath(), m_page->mainFrame());
}
void Phantom::printConsoleMessage(const QString &message, int lineNumber, const QString &source)
{
QString msg = message;
if (!source.isEmpty())
msg = source + ":" + QString::number(lineNumber) + " " + msg;
std::cout << qPrintable(msg) << std::endl;
}
QString Phantom::libraryPath() const
{
return m_page->libraryPath();
@ -269,3 +232,49 @@ QString Phantom::scriptName() const
{
return QFileInfo(m_scriptFile).fileName();
}
QVariantMap Phantom::version() const
{
QVariantMap result;
result["major"] = PHANTOMJS_VERSION_MAJOR;
result["minor"] = PHANTOMJS_VERSION_MINOR;
result["patch"] = PHANTOMJS_VERSION_PATCH;
return result;
}
QObject *Phantom::filesystem()
{
return &m_filesystem;
}
// public slots:
QObject *Phantom::createWebPage()
{
WebPage *page = new WebPage(this);
page->applySettings(m_defaultPageSettings);
page->setNetworkAccessManager(m_netAccessMan);
page->setLibraryPath(QFileInfo(m_scriptFile).dir().absolutePath());
return page;
}
bool Phantom::injectJs(const QString &jsFilePath) {
return Utils::injectJsInFrame(jsFilePath, libraryPath(), m_page->mainFrame());
}
void Phantom::exit(int code)
{
m_terminated = true;
m_returnValue = code;
delete m_page;
m_page = 0;
QApplication::instance()->exit(code);
}
// private slots:
void Phantom::printConsoleMessage(const QString &message, int lineNumber, const QString &source)
{
QString msg = message;
if (!source.isEmpty())
msg = source + ":" + QString::number(lineNumber) + " " + msg;
std::cout << qPrintable(msg) << std::endl;
}

View File

@ -36,6 +36,7 @@
class WebPage;
#include "csconverter.h"
#include "networkaccessmanager.h"
#include "filesystem.h"
class Phantom: public QObject
{
@ -45,6 +46,7 @@ class Phantom: public QObject
Q_PROPERTY(QString libraryPath READ libraryPath WRITE setLibraryPath)
Q_PROPERTY(QString scriptName READ scriptName)
Q_PROPERTY(QVariantMap version READ version)
Q_PROPERTY(QObject* fs READ filesystem)
public:
Phantom(QObject *parent = 0);
@ -63,6 +65,8 @@ public:
QVariantMap version() const;
QObject *filesystem();
public slots:
QObject *createWebPage();
bool injectJs(const QString &jsFilePath);
@ -81,6 +85,7 @@ private:
CSConverter *m_converter;
NetworkAccessManager *m_netAccessMan;
QVariantMap m_defaultPageSettings;
FileSystem m_filesystem;
};
#endif // PHANTOM_H

View File

@ -17,13 +17,15 @@ HEADERS += csconverter.h \
webpage.h \
consts.h \
utils.h \
networkaccessmanager.h
networkaccessmanager.h \
filesystem.h
SOURCES += phantom.cpp \
webpage.cpp \
main.cpp \
csconverter.cpp \
utils.cpp \
networkaccessmanager.cpp
networkaccessmanager.cpp \
filesystem.cpp
include(gif/gif.pri)