54 Commits
Author SHA1 Message Date
mlangkabel 2dad29877f expose getVersionString() in API 2019-04-02 17:52:58 +02:00
Malte LangkabelandGitHub 02647c418c Merge pull request #5 from CoatiSoftware/record_qualifier_location
Record qualifier locations
2019-03-26 12:04:01 +01:00
mlangkabel 5dd33e9ecf extend cpp api example to record a qualifier location 2019-03-26 11:33:20 +01:00
mlangkabel 6a55b81e33 add test 2019-03-26 11:33:12 +01:00
mlangkabel 24668448f5 implement functionality to store a qualifier location to the database 2019-03-26 11:33:01 +01:00
Malte LangkabelandGitHub 702330265f Merge pull request #4 from CoatiSoftware/fix_examples
Fix examples for windows
2019-03-26 11:20:19 +01:00
mlangkabel 52635f23f3 fix the same errors in python api example 2019-03-26 11:08:22 +01:00
mlangkabel c4aad954e2 fix some logic and functional errors in the cpp api example 2019-03-26 11:08:14 +01:00
mlangkabel 3b76c403dc rename recordCommentLocation to recordAtomicSourceRange
This is done because the feature can be useful for all kind of multi-line symbols that should not be split being part of a code snippet.
2019-02-26 17:12:18 +01:00
mlangkabel b8664ce131 add Language Extension Guide 2019-02-26 15:36:12 +01:00
mlangkabel 495b40ef16 extend readme with information on relevance of the repo's tags 2019-02-01 16:29:30 +01:00
mlangkabel 4edb7f26ac fix build issue if tags of this repo are not checked out (issue #1) 2019-02-01 15:43:16 +01:00
Eberhard Graether db936766e4 added C++ Poetry Indexer image to README introduction 2018-12-19 15:37:21 +01:00
Eberhard Graether 6a1a5021ee revised SourcetrailDBWriter API documentation and related classes 2018-12-19 15:01:14 +01:00
Eberhard Graether 353e26d47e revised README: cropped images, refactored sample code, added examples and custom source group setup 2018-12-19 13:12:32 +01:00
mlangkabel 807b80a1fd update readme
* add short description
* link python indexer project
2018-12-18 19:29:48 +01:00
Eberhard Graether 9e29169f98 use . in version 2018-12-18 19:10:27 +01:00
mlangkabel effd55a106 remove duplicate of external source code 2018-12-18 17:47:14 +01:00
mlangkabel aa8762b208 link poetry indexer example in readme 2018-12-18 17:33:20 +01:00
mlangkabel e7e1045375 describe versioning in readme and add changelog 2018-12-18 17:30:10 +01:00
mlangkabel 89158d0b1d add documentation for the public SourcetraiDBWriter interface 2018-12-18 16:57:50 +01:00
Eberhard Graether 3ef6b882a4 try to extend python releases on travis to python 3.5, 3.6, 3.7, but has still issues 2018-12-18 16:50:04 +01:00
mlangkabel 834cfc336e store project settings content when opening database
This is required to tell Sourcetrail that the database content is up to date with the current project settings.
2018-12-18 13:26:10 +01:00
mlangkabel 3bb799cc77 fix enum constant collision with define on windows 2018-12-18 11:23:23 +01:00
Eberhard Graether aa85d20e73 added README to examples and improved database version check when used from Sourcetrail 2018-12-18 10:48:43 +01:00
Eberhard Graether f4cf5f171a switched enum syntax in core to enum class 2018-12-18 00:41:19 +01:00
mlangkabel 2e78670c80 add Appveyor builds for python 3.6 and 3.5 2018-12-17 18:28:29 +01:00
Eberhard Graether 1b0e90341c add compiler name and licenses to unix release packages, build with gcc-5 on linux 2018-12-17 17:15:52 +01:00
mlangkabel 4ce48c0aea add msvc14 to appveyor build matrix 2018-12-17 16:30:27 +01:00
mlangkabel 772596a8a6 fix cmake of python bindings example for MSVC builds 2018-12-17 15:30:19 +01:00
mlangkabel 3a642bf396 add appveyor based windows deployment 2018-12-17 14:18:28 +01:00
Eberhard Graether a99017bd48 add global Sourcetrail project to project root 2018-12-17 13:34:15 +01:00
Eberhard Graether 16f130e5a8 fix travis build pipeline 2018-12-15 11:57:31 +01:00
Eberhard Graether ea931ceb9f improved sqlite performance with indices and compiled statements 2018-12-15 02:44:47 +01:00
mlangkabelandEberhard Graether 1c07e5b4dc add api usage examples for cpp and python binding 2018-12-15 02:43:34 +01:00
mlangkabel 4517be935c use file id instead of file path in recorded locations 2018-12-14 18:37:40 +01:00
Eberhard Graether 3b0008585e setup travis for builds, testing and release on osx and linux 2018-12-14 13:34:30 +01:00
mlangkabel 566091a63f add API usage examples to readme 2018-12-14 11:11:14 +01:00
Eberhard Graether af43432e52 fixed build for macOS 2018-12-13 12:39:51 +01:00
mlangkabel cba4e7318f add method to record file language 2018-12-12 15:38:49 +01:00
mlangkabel 20b2db0571 restructure external code and handle 3rd party licenses correctly 2018-12-11 16:50:47 +01:00
mlangkabel 2f5409af5d make building Python bindings configurable via CMake flag 2018-12-11 15:32:04 +01:00
mlangkabel b7f79fc1f5 add CMakeLists in root directory to simplify build configuration 2018-12-11 14:43:48 +01:00
mlangkabel 722772bd9a refine tests for SourcetrailDBWriter interface 2018-12-11 12:36:26 +01:00
mlangkabel 4d5b97b7e6 add catch2 based test setup including some basic test cases 2018-12-10 20:26:32 +01:00
mlangkabel a69232afed add SYMBOL_MODULE to SymbolKind eum 2018-12-10 16:28:55 +01:00
mlangkabel 85aef6164a update open, close and clear API 2018-12-10 13:41:44 +01:00
mlangkabel 403eae366c update the README file 2018-12-03 23:47:32 +01:00
mlangkabel 18a6444d6a make windows builds independent of CMake binary directory 2018-12-03 23:43:29 +01:00
mlangkabel d5672c8b07 add Apache license info to own source files 2018-12-03 23:15:26 +01:00
mlangkabel 0353d0a5f7 clean up SymbolKind enum 2018-12-03 15:33:40 +01:00
mlangkabel 6daaff9dab add support for appveyor 64 bit windows builds 2018-12-03 13:52:50 +01:00
mlangkabel a3da0edf1e add support for appveyor builds (32 bit windows only) 2018-12-03 12:10:46 +01:00
mlangkabel ea3abfc026 indev 2018-11-30 16:16:31 +01:00
443 changed files with 217159 additions and 1 deletions
+6
View File
@@ -0,0 +1,6 @@
/build/
.DS_Store
*.srctrldb
*.srctrlbm
+153
View File
@@ -0,0 +1,153 @@
language: cpp
matrix:
include:
- os: linux
compiler: gcc
dist: trusty
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-5
env:
- CC_COMPILER=gcc-5 CXX_COMPILER=g++-5 PYTHON_BINDING=0
- os: linux
compiler: gcc
dist: trusty
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-5
env:
- CC_COMPILER=gcc-5 CXX_COMPILER=g++-5 PYTHON_BINDING=1 PYTHON=3.5
# - os: linux
# compiler: gcc
# dist: trusty
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - g++-5
# env:
# - CC_COMPILER=gcc-5 CXX_COMPILER=g++-5 PYTHON_BINDING=1 PYTHON=3.6
# - os: linux
# compiler: gcc
# dist: trusty
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - g++-5
# env:
# - CC_COMPILER=gcc-5 CXX_COMPILER=g++-5 PYTHON_BINDING=1 PYTHON=3.7
- os: osx
compiler: clang
env:
- PYTHON_BINDING=0
# - os: osx
# compiler: clang
# env:
# - PYTHON_BINDING=1 PYTHON=3.5
- os: osx
compiler: clang
env:
- PYTHON_BINDING=1 PYTHON=3.6
# - os: osx
# compiler: clang
# env:
# - PYTHON_BINDING=1 PYTHON=3.7
before_install:
- |
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew install swig
brew link --force swig
# TODO: find way to install specific python versions on osx
# if [[ "$PYTHON_BINDING" == "1" ]]; then
# brew install python$PYTHON
# python --version
# fi
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo apt-get update
sudo apt-get install -qq swig
# TODO: this is only working for python3.5, not above
if [[ "$PYTHON_BINDING" == "1" ]]; then
sudo apt-get install python$PYTHON
sudo apt-get install python$PYTHON-dev
alias python="/usr/bin/python$PYTHON"
python --version
fi
fi
install:
- if [[ "${CXX_COMPILER}" != "" ]]; then export CXX=${CXX_COMPILER}; export CXX_FOR_BUILD=${CXX_COMPILER}; fi
- if [[ "${CC_COMPILER}" != "" ]]; then export CC=${CC_COMPILER}; export CC_FOR_BUILD=${CC_COMPILER}; fi
script:
- |
mkdir build
cd build
cmake -DBUILD_BINDINGS_PYTHON=$PYTHON_BINDING -DPYTHON_VERSION=$PYTHON ..
make
./core/test_core
before_deploy:
- |
cd $TRAVIS_BUILD_DIR
VERSION=$(head -1 build/version.txt)
if [[ "$PYTHON_BINDING" == "1" ]]; then
PYTHON_VERSION=${PYTHON//.}
PYTHON_VERSION=${PYTHON_VERSION:0:2}
BUNDLE_NAME=sourcetraildb_python${PYTHON_VERSION}_${VERSION}-${TRAVIS_OS_NAME}-64bit-${TRAVIS_COMPILER}
mkdir -p $BUNDLE_NAME
cp build/bindings_python/sourcetraildb.py $BUNDLE_NAME
cp build/bindings_python/_sourcetraildb* $BUNDLE_NAME/_sourcetraildb.so
else
BUNDLE_NAME=sourcetraildb_core_${VERSION}-${TRAVIS_OS_NAME}-64bit-${TRAVIS_COMPILER}
mkdir -p $BUNDLE_NAME/include
mkdir -p $BUNDLE_NAME/lib
cp build/core/*.a $BUNDLE_NAME/lib
cp core/include/* $BUNDLE_NAME/include
cp build/core/include/* $BUNDLE_NAME/include
fi
mkdir -p $BUNDLE_NAME/license
cp LICENSE.txt $BUNDLE_NAME/license/license_sourcetraildb.txt
cp external/catch/license_catch.txt $BUNDLE_NAME/license/
cp external/cpp_sqlite/license_cpp_sqlite.txt $BUNDLE_NAME/license/
cp external/json/license_json.txt $BUNDLE_NAME/license/
zip -r $BUNDLE_NAME $BUNDLE_NAME
deploy:
provider: releases
api_key:
secure: UwuiE6SrjorpBr1CzTRadX1zq83hwbnur+MvzBueqEHM7Yyu5Y0xMkwchRlX41HzMuSkC0azM0S8GfqJT1E7pIrqgJGvFbXR3t9ZG8HtvrcM4PvTS8b0G0d8aWHfTP2Zv+PAK3MMnYtxmOFPs4IaqO1m+imjQWtpvCRG5tvc4DNIPAMh0S8LCjxUdz35BYAM4pwM7WB9Qt+YhbyP1h3oSQ7qtr1fZYCC0H4G1cjVBLeP9g66/tfg0MIQVf1wxU8KF3H6esilPhFDCnsBYcnYrKyJN9OkMXZvLoxsjqQvTlsSNO2wIQ32dW8fk+1VFebWjN3RnNUV2Zb3wdz2y6e6A08J8T/+QrJ003eUJAGassQEgsuQ85ldcbylbKCVdi+iA+W6pKSJoHIlyr2KQG77OZ+q3obvY09IMNX2qVnUJKG8g9vZHKk8TlvUtIDODUxqJ/XUVwG5aKiUPuE5UMeLnZlO7cWpABb28BjXGehLCDtqg2eu39n+N9hyEjmsJLcOuS03+C55YrjJHW09qZomorMyIa//4jxSAOU9Iah7cRzPGUl/eSwQ2kf0OGWfySd2PreOThWepH0ymvG9htlTUSMM4wRuKnNAmG7NY6TykttJY2KsTLpki+P4MFBlSvL0VvoHQintK69udSVeUrJaGx508w8V59AdZwJjMxhjOXw=
file_glob: true
file: $TRAVIS_BUILD_DIR/*.zip
overwrite: true
skip_cleanup: true
on:
tags: true
repo: CoatiSoftware/SourcetrailDB
+7
View File
@@ -0,0 +1,7 @@
# Changelog
## v1.db23.p0
**2018-12-19**
* First official release of the SourcetrailDB project.
+95
View File
@@ -0,0 +1,95 @@
cmake_minimum_required (VERSION 2.6)
# --- Options ---
set(BUILD_BINDINGS_PYTHON OFF CACHE BOOL "Build the SourcetrailDB Python bindings.")
set(BUILD_EXAMPLES ON CACHE BOOL "Build the examples.")
set(PROJECT_NAME "SourcetrailDB")
project(${PROJECT_NAME})
# --- Default Flags ---
set(CMAKE_BUILD_TYPE_INIT "Release")
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -fPIC")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -fPIC")
endif()
# --- Version ---
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
find_package(Git)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --long
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_VERSION_NUMBER
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
set(GIT_VERSION_NUMBER "")
endif()
if("${GIT_VERSION_NUMBER}" STREQUAL "")
message(WARNING "Unable to derive SourcetrailDB version number from most recent Git tag.")
set(GIT_VERSION_NUMBER "v0.db0.p0-0-a")
endif()
string(REGEX REPLACE "v([0-9]+)\\..*" "\\1" INTERFACE_VERSION "${GIT_VERSION_NUMBER}")
string(REGEX REPLACE "v[0-9]+\\.db([0-9]+)\\..*" "\\1" DATABASE_VERSION "${GIT_VERSION_NUMBER}")
string(REGEX REPLACE "v[0-9]+\\.db[0-9]+\\.p([0-9]+)-.*" "\\1" PATCH_VERSION "${GIT_VERSION_NUMBER}")
set(VERSION_STRING "v${INTERFACE_VERSION}.db${DATABASE_VERSION}.p${PATCH_VERSION}")
set(VERSION_STRING_UNDERSCORE "v${INTERFACE_VERSION}_db${DATABASE_VERSION}_p${PATCH_VERSION}")
message(STATUS "SourcetrailDB Version: ${VERSION_STRING}")
message(STATUS "Interface Version: ${INTERFACE_VERSION}")
message(STATUS "Database Version: ${DATABASE_VERSION}")
message(STATUS "Patch Version: ${PATCH_VERSION}")
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.txt.in
"${CMAKE_CURRENT_BINARY_DIR}/version.txt"
)
# --- Core ---
set(LIB_CORE "lib_core")
set(CORE_SOURCE_DIR "${CMAKE_SOURCE_DIR}/core") # can be accessed in subdirectory CMake files
set(CORE_BINARY_DIR "${CMAKE_BINARY_DIR}/core") # can be accessed in subdirectory CMake files
add_subdirectory(${CORE_SOURCE_DIR} ${CORE_BINARY_DIR})
# --- Python Binding ---
if (BUILD_BINDINGS_PYTHON)
message(STATUS "The SourcetrailDB Python bindings will be built.")
set(PYTHON_BINDING_OUTPUT_DIR "")
add_subdirectory("${CMAKE_SOURCE_DIR}/bindings_python" "${CMAKE_BINARY_DIR}/bindings_python")
else()
message(STATUS "Building the SourcetrailDB Python bindings will be skipped. You can enable building this target by setting 'BUILD_BINDINGS_PYTHON' to 'ON'.")
endif()
# --- Examples ---
if (BUILD_EXAMPLES)
message(STATUS "The examples will be built.")
add_subdirectory("${CMAKE_SOURCE_DIR}/examples/cpp_api_example")
add_subdirectory("${CMAKE_SOURCE_DIR}/examples/cpp_poetry_indexer")
if (BUILD_BINDINGS_PYTHON)
add_subdirectory("${CMAKE_SOURCE_DIR}/examples/python_api_example")
else()
message(STATUS "Skip python binding sample. You can enable building it by setting 'BUILD_BINDINGS_PYTHON' to 'ON'.")
endif()
else()
message(STATUS "Building examples will be skipped. You can enable building examples by setting 'BUILD_EXAMPLES' to 'ON'.")
endif()
+56
View File
@@ -0,0 +1,56 @@
# Sourcetrail Language Extension Guide
## First Things First
Build on the shoulders of giants. There are many language tools and frameworks out there that you can build upon, helping you to get things done much faster:
Look for a parser that generates an Abstract Syntax Tree (AST) for the language you want to index. The parser can be written in any language, but for parsing programming languages these tools are mostly written in the language they are designed to parse. You will probably use the generated AST to visit certain nodes (e.g. all `function definition` nodes) and store all the useful information to the Sourcetrail database (e.g. a `function` with name `foo` is defined at location `<X:Y>`).
Having a parser is fine, but it is not enough. When you parse code that contains a function call, the parser may just create a `call expression` node for you. You may even be able to get the name of the called function from the AST node, but the parser certainly will not know where this function is actually defined. And if the indexed code defines two or more functions with the same name, you are in trouble.
That's why it`s best to have a framework that can resolve this info for you. Just to name a few examples:
* for Java there is the [JavaParser](https://github.com/javaparser/javaparser) for building the AST and the [JavaSymbolSolver](https://github.com/javaparser/javasymbolsolver) (now integrated into JavaParser) for resolving these references.
* for C/C++ this is all done by the [Clang](https://clang.llvm.org/) compiler frontend.
* for Python the AST can be built by [parso](https://github.com/davidhalter/parso) while the references can be solved by [Jedi](https://github.com/davidhalter/jedi).
## Getting Started
Ok, let's assume that you found some awesome frameworks that help you build your Sourcetrail Language Package. So what's next?
1. Start off by writing a small executable piece of code that reads in some input code and generates the AST. For the scope of this guide, let's assume that the following piece of Python code would be your snippet.
<!-- language: python -->
class Foo:
def bar():
return 0
f = Foo()
f.bar()
2. Implement an AST visitor that visits each node of the generated AST and prints that node's type. This functionality will come in handy for debugging your code later on. For our piece of sample code, the AST may look like this:
<!-- language: language-none -->
file_input
|-classdef [Foo]
| `-funcdef [bar()]
| `-return
| `-number [0]
|-assignment
| |-name [f]
| `-call
| `-name [Foo()]
|-call
| `-name [bar()]
| `-qualifier [f]
`-endmarker
3. Make the [SourcetrailDB interface](https://github.com/CoatiSoftware/SourcetrailDB#sourcetraildb-api) accessible from your code base. You can either use [existing bindings](https://github.com/CoatiSoftware/SourcetrailDB#supported-language-bindings) for your desired language or open an issue at the [SourcetrailDB issues page](https://github.com/CoatiSoftware/SourcetrailDB/issues). If your language package has made it to this stage, the SourcetrailDB team will be happy to support your project!
4. Use SourcetrailDB from within your code base by opening a `.srctrldb` file before traversing your AST and closing it again after the AST visitor is done.
5. Your AST should already have information available on where certain symbols are defined (e.g. `classdef [Foo]` and `funcdef [bar()]`). Try to extend your AST visitor to store this information to the Sourcetrail Database (e.g. whenever you visit a class or function declaration, try to create a node with the symbol's name (e.g. `Foo` and `Foo.bar`) in the Sourcetrail database).
6. Setup an automated test suite that runs test cases for indexing code snippets with syntax you already covered in your language package. This way you can make sure that you don`t break things as you move forward.
7. Extend your AST visitor to store additional information for the symbols that you already record (e.g. symbol kind, definition kind, source location).
8. Record references between your symbols. Now, this is the tricky part. Within your AST you may encounter a node that describe references to other nodes (e.g. `call`). Use your language processing framework to resolve those references. For our example this language processing framework would need to find out that
* `bar()` is called on the object in variable `f` and
* `f` contains an instance of the class `Foo` so
* `f.bar()` actually describes a call to `Foo.bar()`.
9. If you have made it this far: Congratulations! You already have a solid Sourcetrail language package up and running! It is time to get your language package linked in the [SourcetrailDB Readme](https://github.com/CoatiSoftware/SourcetrailDB#projects-using-sourcetraildb). Just open an issue or create a pull request.
10. Now it's just about extending the package to record more and more stuff and cover the remaining edge cases. Once the package is mature, it may be integrated and shipped with the official Sourcetrail releases, if you agree and if your licensing terms allow.
View File
+377 -1
View File
@@ -1 +1,377 @@
# SourcetrailDB
# SourcetrailDB
Library to export [Sourcetrail](https://www.sourcetrail.com/) compatible database files for writing custom indexers
## CI Pipelines
Windows: [![Build status](https://ci.appveyor.com/api/projects/status/gbblx1l790vm952c/branch/master?svg=true)](https://ci.appveyor.com/project/mlangkabel/sourcetraildb/branch/master)
Linux and macOS: [![Build Status](https://travis-ci.org/CoatiSoftware/SourcetrailDB.svg?branch=master)](https://travis-ci.org/CoatiSoftware/SourcetrailDB)
## Introduction
The SourcetrailDB project provides write access to [Sourcetrail](https://www.sourcetrail.com/) database files. You can use the SourcetrailDB project to write an indexer for an arbitrary programming language (or other kind of data, e.g. see [poetry indexer example](examples/cpp_poetry_indexer)) and export a Sourcetrail database file that can be viewed and navigated within Sourcetrail.
!["C++ Poetry Indexer"](images/readme/00_cpp_poetry_indexer.png "C++ Poetry Indexer")
## Projects Using SourcetrailDB
The following list of projects already use SourcetrailDB API to extend the language support of Sourcetrail. If you plan on starting a language package on your own, take a look at our [Language Extension Guide](LANGUAGE_EXTENSION_GUIDE.md).
* [SourcetrailPythonIndexer](https://github.com/CoatiSoftware/SourcetrailPythonIndexer)
## Supported Language Bindings
Even though the core implementation is written in C++, this does not require you to write your indexer in C++ as well. Instead you can use a language binding (e.g. see [SWIG](http://www.swig.org/)). These language bindings are already available:
* Python (via [SWIG](http://www.swig.org/))
If the language of your choice is not covered by this list, feel free to [open an issue](https://github.com/CoatiSoftware/SourcetrailDB/issues) or provide a pull request.
## Versioning
The SourcetrailDB version format consists of three numbers in the format `vXX.dbYY.pZZ`.
* `XX`: interface version. This version increases on every change that breaks backwards compatibility.
* `YY`: Sourcetrail database version. This version needs to match the database version of the used Sourcetrail instance. You can find the database version of Sourcetrail in its About dialog.
* `ZZ`: patch number of the build. It will increase with every release that publishes bugfixes and features that don't break any compatibility.
You can find a complete list of available releases on the [GitHub release page](https://github.com/CoatiSoftware/SourcetrailDB/releases). If you are interested in the actual changes of every release, please take a look at the [Changelog](CHANGELOG.md).
## Building
Take a look at [Appveyor (for Windows)](appveyor.yml) or [Travis (for Linux and macOs)](.travis.yml) CI scripts for reference.
### SourcetrailDB Core
Before building the core project, please make sure that you also have checked out the tags of this repository (they are relevant for deriving version number information during the build).
Requirements:
* [CMake](https://cmake.org/) >= 2.6
* C++-Compiler with C++11 support
To build the SourcetrailDB core library `libsourcetraildb.a`:
```
$ cd path/to/SourcetrailDB
$ mkdir build
$ cd build
$ cmake ..
$ make lib_core
```
To run the tests, just build and execute the test executable:
```
$ make test_core
$ ./core/test_core
```
### Python Bindings
Requirements:
* [Python](https://www.python.org/) needs to be included and linked against when building the Python bindings. CMake will auto-detect your Python installation. If you want to build against a specific version of Python, please define the `PYTHON_LIBRARY` variable accordingly when running CMake. Make sure to link to the correct Python version when building for different architectures (32bit/64bit).
* [SWIG 3.0.12](http://www.swig.org/) is used to automatically generate Python binding code. Make sure that SWIG is added to your path environment variable.
If you want to build the Python bindings run:
```
$ cd path/to/SourcetrailDB
$ mkdir build
$ cd build
$ cmake -DBUILD_BINDINGS_PYTHON=ON ..
$ make _sourcetraildb
```
Swig is configured to generate the Python binding code as a pre-build event, so you don't need to bother with updating manually.
### Examples
The examples help you to understand SourcetrailDB usage in practice. Please take a look at each examples README file for build and use instructions. Each example also provides a Sourcetrail project file `.srctrlprj` showing you how to use a custom indexer directly from Sourcetrail (see [Integrating with Sourcetrail](#integrating-with-sourcetrail)).
* [C++ API Example](examples/cpp_api_example)
* [C++ Poetry Indexer](examples/cpp_poetry_indexer)
* [Python API Example](examples/python_api_example)
## SourcetrailDB API
SourcetrailDB tries to keep the API for writing to the Sourcetrail database as simple as possible. For the C++ core take a look at the list of methods of the [SourcetrailDBWriter](core/include/SourcetrailDBWriter.h) class for a complete overview of the provided write API. If you are using bindings for other languages, the code may look different but the set of provided functionality should stay the same.
### Opening or Creating a Database
```c++
// create an instance of SourcetrailDBWriter
sourcetrail::SourcetrailDBWriter writer;
// open a database connection by passing a database file path (.srctrldb or .srctrldb_tmp)
// if the database file does not exist yet, it will be created in this location.
// a project file (.srctrlprj) will also be created, if it does not exist in this location.
writer.open("MyProject.srctrldb");
// record data...
// close the database connection.
writer.close();
```
### Recording a Symbol
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
// records a named non-indexed symbol without type
writer.recordSymbol({ "::", { { "void", "foo", "()" } } });
writer.close();
```
!["Recording a Symbol"](images/readme/01_recording_a_simple_symbol.png "Recording a Symbol")
### Recording Additional Symbol Information
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
sourcetrail::NameHierarchy name = { "::", { { "void", "foo", "()" } } };
// the returned symbolId will be used to record further information for the symbol
int symbolId = writer.recordSymbol(name);
// recording a unique name multiple times will always return the same symbol id
assert(symbolId == writer.recordSymbol(name));
// set symbol "explicit" to remove the "non-indexed" state.
writer.recordSymbolDefinitionKind(symbolId, sourcetrail::DEFINITION_EXPLICIT);
// set type to turn the symbol into "function"
writer.recordSymbolKind(symbolId, sourcetrail::SYMBOL_FUNCTION);
writer.close();
```
!["Recording Additional Symbol Information"](images/readme/02_recording_additional_symbol_information.png "Recording Additional Symbol Information")
### Recording Nested Symbol Names
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject_3.srctrldb");
// create a name hierarchy
sourcetrail::NameHierarchy name;
// specify the delimiter string - in many languages names can be nested
name.nameDelimiter = "::";
// add a name element for the parent
sourcetrail::NameElement parentElement;
parentElement.prefix = ""; // only shown in tooltip of the parent symbol
parentElement.name = "Bar";
parentElement.postfix = ""; // only shown in tooltip of the parent symbol
name.nameElements.push_back(parentElement);
// add a name element for the child
sourcetrail::NameElement childElement;
childElement.prefix = "void"; // only shown in tooltip
childElement.name = "bar";
childElement.postfix = "()"; // only shown in tooltip
name.nameElements.push_back(childElement);
// recording a name hierarchy with multiple elements automatically creates parent symbols, if still unknown
int childId = writer.recordSymbol(name);
writer.recordSymbolDefinitionKind(childId, sourcetrail::DEFINITION_EXPLICIT);
writer.recordSymbolKind(childId, sourcetrail::SYMBOL_METHOD);
writer.close();
```
!["Recording Nested Symbol Names"](images/readme/03_recording_nested_symbol_names.png "Recording Nested Symbol Names")
### Recording Symbol Location
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
int symbolId = writer.recordSymbol({ "::", { { "", "Bar", "" }, { "void", "bar", "()" } } });
// record a file via it's absolute path
int fileId = writer.recordFile("C:/example/Bar.cpp");
// create a location
sourcetrail::SourceRange location;
location.fileId = fileId;
location.startLine = 8; // lines start at 1, not 0
location.startColumn = 7; // columns start at 1, not 0
location.endLine = 8;
location.endColumn = 9;
// adds a clickable location to the file for the specified symbol
writer.recordSymbolLocation(symbolId, location);
// the whole scope location will be visible and highlighted when the symbol is active
writer.recordSymbolScopeLocation(symbolId, { fileId, 8, 1, 11, 1 });
writer.close();
```
!["Recording Symbol Location"](images/readme/04_recording_a_symbols_location.png "Recording Symbol Location")
### Recording References Between Symbols
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
int contextSymbolId = writer.recordSymbol({ "::", { { "", "Bar", "" }, { "void", "bar", "()" } } });
int referencedSymbolId = writer.recordSymbol({ "::", { { "void", "foo", "()" } } });
// edges always go from the context to the referenced symbol
int referenceId = writer.recordReference(contextSymbolId, referencedSymbolId, sourcetrail::REFERENCE_CALL);
// add a location to the reference - highlights the location in the code view when clicking the edge in the graph view
int fileId = writer.recordFile("C:/example/Bar.cpp");
writer.recordReferenceLocation(referenceId, { fileId, 10, 3, 10, 5 });
writer.close();
```
!["Recording References between Symbols"](images/readme/05_recording_references_between_symbols.png "Recording References between Symbols")
### Recording File Information for Syntax Highlighting
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
int fileId = writer.recordFile("C:/example/Bar.cpp");
// enable syntax highlighting using a <language>.rules file loaded from Sourcetrail's data directory
writer.recordFileLanguage(fileId, "cpp");
writer.close();
```
!["Recording File Information for Syntax Highlighting"](images/readme/06_recording_file_information_for_syntax_highlighting.png "Recording File Information for Syntax Highlighting")
### Recording Local Symbols
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
// provide a unique local symbol name - the name is not displayed anywhere
int localId = writer.recordLocalSymbol("some_unique_name");
int fileId = writer.recordFile("C:/example/Foo.cpp");
writer.recordLocalSymbolLocation(localId, { fileId, 3, 6, 3, 6 });
writer.recordLocalSymbolLocation(localId, { fileId, 4, 2, 4, 2 });
writer.close();
```
!["Recording Local Symbols"](images/readme/07_recording_occurrences_of_local_symbols.png "Recording Local Symbols")
### Recording Comments
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
int fileId = writer.recordFile("C:/example/Bar.cpp");
// the recorded source range is atomic - it is always shown completely
int id = writer.recordCommentLocation({ fileId, 3, 2, 7, 4 });
writer.close();
```
!["Recording Comments"](images/readme/08_recording_comments.png "Recording Comments")
### Recording Errors
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
int fileId = writer.recordFile("C:/example/Foo.cpp");
// store and show parsing and indexing errors
std::string message = "Really? You missed that \";\" again?";
bool fatal = false;
sourcetrail::SourceRange location = { fileId, 4, 4, 4, 4 };
int id = writer.recordError(message, fatal, location);
writer.close();
```
!["Recording Errors"](images/readme/09_recording_errors.png "Recording Errors")
### Use Transactions for Speed
```c++
sourcetrail::SourcetrailDBWriter writer;
writer.open("MyProject.srctrldb");
// wrapping your code in transactions really speeds up database operations
writer.beginTransaction();
for (int i = 0; i < 1000; ++i)
{
int id = writer.recordSymbol({ "::", { { "void", "foo" + std::to_string(i), "()" } } });
if (id == 0) // if something goes wrong
{
// discard all the changes made within the transaction
writer.rollbackTransaction();
writer.close();
return;
}
}
// don't forget to commit your transaction to persistently write the changes
writer.commitTransaction();
writer.close();
```
## Integrating with Sourcetrail
Applications using SourcetrailDB can be directly integrated with Sourcetrail by creating a project with a **Custom Command Source Group**. Choose `Custom` in the project selection dialog:
<img src="images/readme/10_custom_command_source_group_selection.png" alt="Custom Command Source Group Selection" width="720"/>
### Project Setup
A Custom Command Source Group defines:
* **Custom Command**: This command will be executed for each source file in the source group. You can pass these variables in the command:
- **%{SOURCE_FILE_PATH}**: The path to each source file in the source group
- **%{DATABASE_FILE_PATH}**: The path to the database of the project
- **%{DATABASE_VERSION}**: The database version of the used Sourcetrail instance
- **%{PROJECT_FILE_PATH}**: The path to the project file
* **Files & Directories to Index**: Paths to search for source files.
* **Excluded Files & Directories**: Files and directories within the above, that should not be indexed.
* **Source File Extensions**: The extension of the source files. Extension is ignored if left empty.
!["Custom Command Source Group Setup"](images/readme/11_custom_command_source_group_setup.png "Custom Command Source Group Setup")
### Indexing
Indexing the project works as usual, the specified **Custom Command** is executed with each source file passed in **%{SOURCE_FILE_PATH}**. The files in the **Custom Command Source Group** will be indexed after all other files.
<img src="images/readme/12_custom_command_source_group_indexing.png" alt="Custom Command Source Group Indexing" width="343"/>
+42
View File
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<config>
<source_groups>
<source_group_3bc49d80-6e3a-42b4-80d8-336fdf0612c4>
<cpp_standard>c++11</cpp_standard>
<cross_compilation>
<target>
<abi>unknown</abi>
<arch>x86_64</arch>
<sys>unknown</sys>
<vendor>unknown</vendor>
</target>
<target_options_enabled>0</target_options_enabled>
</cross_compilation>
<exclude_filters>
<exclude_filter>examples/cpp_api_example/data/example.cpp</exclude_filter>
</exclude_filters>
<header_search_paths>
<header_search_path>build/core/include</header_search_path>
<header_search_path>core/include</header_search_path>
<header_search_path>external/catch/include</header_search_path>
<header_search_path>external/cpp_sqlite/include</header_search_path>
<header_search_path>external/json/include</header_search_path>
<header_search_path>resources_swig/include</header_search_path>
</header_search_paths>
<name>C++ Source Group</name>
<source_extensions>
<source_extension>.cpp</source_extension>
<source_extension>.cxx</source_extension>
<source_extension>.cc</source_extension>
</source_extensions>
<source_paths>
<source_path>core</source_path>
<source_path>examples</source_path>
<source_path>resources_swig</source_path>
</source_paths>
<status>enabled</status>
<type>C++ Source Group</type>
</source_group_3bc49d80-6e3a-42b4-80d8-336fdf0612c4>
</source_groups>
<version>7</version>
</config>
+151
View File
@@ -0,0 +1,151 @@
version: 0.0.0.{build}
image: Visual Studio 2017
environment:
matrix:
- MBITS: 32
PYTHON_VERSION: 37
MSVC_VERSION: 15
DEPLOY_CORE: 1
DEPLOY_PYTHON_BINDINGS: 1
- MBITS: 64
PYTHON_VERSION: 37
MSVC_VERSION: 15
DEPLOY_CORE: 1
DEPLOY_PYTHON_BINDINGS: 1
- MBITS: 32
PYTHON_VERSION: 36
MSVC_VERSION: 15
DEPLOY_CORE: 0
DEPLOY_PYTHON_BINDINGS: 1
- MBITS: 64
PYTHON_VERSION: 36
MSVC_VERSION: 15
DEPLOY_CORE: 0
DEPLOY_PYTHON_BINDINGS: 1
- MBITS: 32
PYTHON_VERSION: 35
MSVC_VERSION: 15
DEPLOY_CORE: 0
DEPLOY_PYTHON_BINDINGS: 1
- MBITS: 64
PYTHON_VERSION: 35
MSVC_VERSION: 15
DEPLOY_CORE: 0
DEPLOY_PYTHON_BINDINGS: 1
- MBITS: 32
PYTHON_VERSION: 37
MSVC_VERSION: 14
DEPLOY_CORE: 1
DEPLOY_PYTHON_BINDINGS: 1
- MBITS: 64
PYTHON_VERSION: 37
MSVC_VERSION: 14
DEPLOY_CORE: 1
DEPLOY_PYTHON_BINDINGS: 1
install:
- ps: |
if ($env:MBITS -eq "32") {
echo "Architecture set to 32 bit."
$env:CMAKE_GENERATOR="Visual Studio $env:MSVC_VERSION"
$env:PYTHON_PATH="C:/Python$env:PYTHON_VERSION"
} elseif ($env:MBITS -eq "64") {
echo "Architecture set to 64 bit."
$env:CMAKE_GENERATOR="Visual Studio $env:MSVC_VERSION Win64"
$env:PYTHON_PATH="C:/Python$env:PYTHON_VERSION-x64"
} else {
echo "No architecture set. Build will be canceled."
}
# Install SWIG by Choco
choco install -y --no-progress swig
before_build:
- mkdir build
- cd build
- cmake -G "%CMAKE_GENERATOR%" ../ -DBUILD_BINDINGS_PYTHON=ON -DPYTHON_LIBRARY="%PYTHON_PATH%/libs/python%PYTHON_VERSION%.lib"
- cd ../
- ps: $env:CORE_VERSION = Get-Content -Path ./build/version.txt
- ps: echo "Core version is $env:CORE_VERSION"
# TODO: convert the core version into dotted format and update appveyor version here
# - ps: $env:BUILD_VERSION = "0.0.1." + $env:APPVEYOR_BUILD_NUMBER
# - ps: echo update build version to $env:BUILD_VERSION
# - ps: Update-AppveyorBuild -Version $env:BUILD_VERSION
build_script:
- cd build
- msbuild /p:configuration=Release /v:m ALL_BUILD.vcxproj
- cd ../
after_build:
- ps: $env:CORE_PACKAGE_NAME = 'sourcetraildb_core_' + $env:CORE_VERSION + '-windows-' + $env:MBITS + 'bit-msvc' + $env:MSVC_VERSION
- ps: $env:PYTHON_PACKAGE_NAME = 'sourcetrailbd_python' + $env:PYTHON_VERSION + '_' + $env:CORE_VERSION + '-windows-' + $env:MBITS + 'bit'
- ps: echo $env:CORE_PACKAGE_NAME
- ps: echo $env:PYTHON_PACKAGE_NAME
- mkdir artifacts_core
- cd artifacts_core
- mkdir %CORE_PACKAGE_NAME%
- cd %CORE_PACKAGE_NAME%
- mkdir lib
- mkdir include
- mkdir license
- cd ../..
- ps: |
copy build/core/release/sourcetraildb.lib artifacts_core/$env:CORE_PACKAGE_NAME/lib/
copy build/core/include/version.h artifacts_core/$env:CORE_PACKAGE_NAME/include/
copy core/include/* artifacts_core/$env:CORE_PACKAGE_NAME/include/
copy LICENSE.txt artifacts_core/$env:CORE_PACKAGE_NAME/license/license_sourcetraildb.txt
copy external/catch/license_catch.txt artifacts_core/$env:CORE_PACKAGE_NAME/license/
copy external/cpp_sqlite/license_cpp_sqlite.txt artifacts_core/$env:CORE_PACKAGE_NAME/license/
copy external/json/license_json.txt artifacts_core/$env:CORE_PACKAGE_NAME/license/
- mkdir artifacts_bindings_python
- cd artifacts_bindings_python
- mkdir %PYTHON_PACKAGE_NAME%
- cd %PYTHON_PACKAGE_NAME%
- mkdir license
- cd ../..
- ps: |
copy build/bindings_python/release/_sourcetraildb.pyd artifacts_bindings_python/$env:PYTHON_PACKAGE_NAME/
copy build/bindings_python/sourcetraildb.py artifacts_bindings_python/$env:PYTHON_PACKAGE_NAME/
copy LICENSE.txt artifacts_bindings_python/$env:PYTHON_PACKAGE_NAME/license/license_sourcetraildb.txt
copy external/catch/license_catch.txt artifacts_bindings_python/$env:PYTHON_PACKAGE_NAME/license/
copy external/cpp_sqlite/license_cpp_sqlite.txt artifacts_bindings_python/$env:PYTHON_PACKAGE_NAME/license/
copy external/json/license_json.txt artifacts_bindings_python/$env:PYTHON_PACKAGE_NAME/license/
- ps: |
$env:ARTIFACTY_TO_DEPLOY = ""
if ($env:DEPLOY_CORE -eq "1") {
$env:ARTIFACTY_TO_DEPLOY = $env:ARTIFACTY_TO_DEPLOY + "," + $env:CORE_PACKAGE_NAME
}
if ($env:DEPLOY_PYTHON_BINDINGS -eq "1") {
$env:ARTIFACTY_TO_DEPLOY = $env:ARTIFACTY_TO_DEPLOY + "," + $env:PYTHON_PACKAGE_NAME
}
$env:ARTIFACTY_TO_DEPLOY = $env:ARTIFACTY_TO_DEPLOY.substring(1)
echo $env:ARTIFACTY_TO_DEPLOY
test_script:
- "build\\core\\release\\test_core.exe"
artifacts:
- path: artifacts_core
name: $(CORE_PACKAGE_NAME)
type: Zip
- path: artifacts_bindings_python
name: $(PYTHON_PACKAGE_NAME)
type: Zip
deploy:
provider: GitHub
artifact: $(ARTIFACTY_TO_DEPLOY)
auth_token:
secure: 8UwbjFrtR19GxLgL3O3efUT0Su2mp3+X23YioThJITupEvexmQJPAf3Whmmb3eeL
on:
appveyor_repo_tag: true
+44
View File
@@ -0,0 +1,44 @@
cmake_minimum_required (VERSION 2.6)
set(PACKAGE_NAME "sourcetraildb")
# --- Setup Paths ---
set(RESOURCES_SWIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../resources_swig")
set(GENERATED_SRC_DIR "${CMAKE_CURRENT_BINARY_DIR}/src")
set(PYTHON_BINDING_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
set(SWIG_INTERFACE_FILE "${RESOURCES_SWIG_DIR}/interface/${PACKAGE_NAME}.i")
# --- Find Python ---
find_package(PythonLibs ${PYTHON_VERSION} REQUIRED)
# --- Find Swig ---
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
# --- Configure Target ---
set_source_files_properties(${SWIG_INTERFACE_FILE} PROPERTIES CPLUSPLUS ON)
include_directories(
"${RESOURCES_SWIG_DIR}/include"
"${CORE_SOURCE_DIR}/include"
${PYTHON_INCLUDE_DIRS}
)
swig_add_library(
${PACKAGE_NAME}
TYPE SHARED
LANGUAGE python
OUTPUT_DIR ${PYTHON_BINDING_OUTPUT_DIR}
OUTFILE_DIR ${GENERATED_SRC_DIR}
SOURCES ${SWIG_INTERFACE_FILE} ${RESOURCES_SWIG_DIR}/src/${PACKAGE_NAME}.cpp
)
swig_link_libraries(${PACKAGE_NAME} ${PYTHON_LIBRARIES} ${LIB_CORE})
+81
View File
@@ -0,0 +1,81 @@
cmake_minimum_required (VERSION 2.6)
set(TEST_CORE "test_core")
set(GENERATED_INCLUDE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")
set(GENERATED_VERSION_FILE "${GENERATED_INCLUDE_DIRECTORY}/version.h")
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
${GENERATED_VERSION_FILE}
)
set(LIB_SRC_FILES
"${CMAKE_SOURCE_DIR}/external/cpp_sqlite/src/CppSQLite3.cpp"
"${CMAKE_SOURCE_DIR}/external/cpp_sqlite/src/sqlite3.c"
src/DatabaseStorage.cpp
src/DefinitionKind.cpp
src/EdgeKind.cpp
src/LocationKind.cpp
src/NameHierarchy.cpp
src/NodeKind.cpp
src/ReferenceKind.cpp
src/SourcetrailDBWriter.cpp
src/SymbolKind.cpp
src/utility.cpp
)
set(LIB_HDR_FILES
"${CMAKE_SOURCE_DIR}/external/json/include/json.hpp"
"${CMAKE_SOURCE_DIR}/external/cpp_sqlite/include/CppSQLite3.h"
"${CMAKE_SOURCE_DIR}/external/cpp_sqlite/include/sqlite3.h"
include/DatabaseStorage.h
include/DefinitionKind.h
include/EdgeKind.h
include/LocationKind.h
include/NameHierarchy.h
include/NodeKind.h
include/ReferenceKind.h
include/SourceRange.h
include/SourcetrailDBWriter.h
include/SourcetrailException.h
include/StorageEdge.h
include/StorageError.h
include/StorageFile.h
include/StorageLocalSymbol.h
include/StorageNode.h
include/StorageOccurrence.h
include/StorageSourceLocation.h
include/StorageSymbol.h
include/SymbolKind.h
include/utility.h
${GENERATED_VERSION_FILE}
)
add_library(${LIB_CORE} STATIC ${LIB_SRC_FILES} ${LIB_HDR_FILES})
set_target_properties(${LIB_CORE} PROPERTIES OUTPUT_NAME "sourcetraildb")
target_include_directories(${LIB_CORE} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_SOURCE_DIR}/external/json/include"
"${CMAKE_SOURCE_DIR}/external/cpp_sqlite/include"
"${GENERATED_INCLUDE_DIRECTORY}"
)
set(TEST_SRC_FILES
test/test.cpp
)
add_executable(${TEST_CORE} ${TEST_SRC_FILES})
target_include_directories(${TEST_CORE} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_SOURCE_DIR}/external/catch/include"
"${CMAKE_SOURCE_DIR}/external/json/include"
"${CMAKE_SOURCE_DIR}/external/cpp_sqlite/include"
"${GENERATED_INCLUDE_DIRECTORY}"
)
target_link_libraries(${TEST_CORE} ${LIB_CORE} "-ldl")
+143
View File
@@ -0,0 +1,143 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_DATABASE_STORAGE_H
#define SOURCETRAIL_DATABASE_STORAGE_H
#include <memory>
#include <string>
#include <vector>
#include "CppSQLite3.h"
#include "StorageEdge.h"
#include "StorageError.h"
#include "StorageFile.h"
#include "StorageLocalSymbol.h"
#include "StorageNode.h"
#include "StorageOccurrence.h"
#include "StorageSourceLocation.h"
#include "StorageSymbol.h"
namespace sourcetrail
{
/**
* Class wrapping the write and update interface of the Sourcetrail database.
*
* The DatabaseStorage provides the interface for writing and updating the Sourcetrail database. This interface only
* knows about basic data types, more elaborate types like enums, structs and classes need to be converted to basic
* types before using this interface.
*/
class DatabaseStorage
{
public:
static int getSupportedDatabaseVersion();
static std::unique_ptr<DatabaseStorage> openDatabase(const std::string& dbFilePath);
~DatabaseStorage();
void setupDatabase();
void clearDatabase();
void setProjectSettingsText(const std::string& text);
bool isEmpty() const;
bool isCompatible() const;
int getLoadedDatabaseVersion() const;
void beginTransaction();
void commitTransaction();
void rollbackTransaction();
void optimizeDatabaseMemory();
int addNode(const StorageNodeData& storageNodeData);
void addSymbol(const StorageSymbol& storageSymbol);
void addFile(const StorageFile& storageFile);
int addEdge(const StorageEdgeData& storageEdgeData);
int addLocalSymbol(const StorageLocalSymbolData& storageLocalSymbolData);
int addSourceLocation(const StorageSourceLocationData& storageSourceLocationData);
void addOccurrence(const StorageOccurrence& storageOccurrence);
int addError(const StorageErrorData& storageErrorData);
void setNodeType(int nodeId, int nodeKind);
void setFileLanguage(int fileId, const std::string& languageIdentifier);
template <typename ResultType>
std::vector<ResultType> getAll() const
{
return doGetAll<ResultType>("");
}
private:
DatabaseStorage() = default;
void setupTables();
void clearTables();
void setupIndices();
void setupPrecompiledStatements();
void clearPrecompiledStatements();
int insertElement();
void insertOrUpdateMetaValue(const std::string& key, const std::string& value);
CppSQLite3Statement compileStatement(const std::string& statement) const;
void executeStatement(const std::string& statement) const;
void executeStatement(CppSQLite3Statement& statement) const;
CppSQLite3Query executeQuery(const std::string& query) const;
CppSQLite3Query executeQuery(CppSQLite3Statement& statement) const;
template <typename ResultType>
std::vector<ResultType> doGetAll(const std::string& query) const;
mutable CppSQLite3DB m_database;
CppSQLite3Statement m_insertElementStatement;
CppSQLite3Statement m_findNodeStatement;
CppSQLite3Statement m_insertNodeStatement;
CppSQLite3Statement m_setNodeTypeStmt;
CppSQLite3Statement m_insertSymbolStatement;
CppSQLite3Statement m_findFileStatement;
CppSQLite3Statement m_insertFileStatement;
CppSQLite3Statement m_setFileLanguageStmt;
CppSQLite3Statement m_insertFileContentStatement;
CppSQLite3Statement m_findEdgeStatement;
CppSQLite3Statement m_insertEdgeStatement;
CppSQLite3Statement m_findLocalSymbolStmt;
CppSQLite3Statement m_insertLocalSymbolStmt;
CppSQLite3Statement m_findSourceLocationStmt;
CppSQLite3Statement m_insertSourceLocationStmt;
CppSQLite3Statement m_insertOccurenceStmt;
CppSQLite3Statement m_findErrorStatement;
CppSQLite3Statement m_insertErrorStatement;
CppSQLite3Statement m_insertOrUpdateMetaValueStmt;
};
template <>
std::vector<StorageEdge> DatabaseStorage::doGetAll<StorageEdge>(const std::string& query) const;
template <>
std::vector<StorageNode> DatabaseStorage::doGetAll<StorageNode>(const std::string& query) const;
template <>
std::vector<StorageSymbol> DatabaseStorage::doGetAll<StorageSymbol>(const std::string& query) const;
template <>
std::vector<StorageFile> DatabaseStorage::doGetAll<StorageFile>(const std::string& query) const;
template <>
std::vector<StorageLocalSymbol> DatabaseStorage::doGetAll<StorageLocalSymbol>(const std::string& query) const;
template <>
std::vector<StorageSourceLocation> DatabaseStorage::doGetAll<StorageSourceLocation>(const std::string& query) const;
template <>
std::vector<StorageOccurrence> DatabaseStorage::doGetAll<StorageOccurrence>(const std::string& query) const;
template <>
std::vector<StorageError> DatabaseStorage::doGetAll<StorageError>(const std::string& query) const;
}
#endif // SOURCETRAIL_DATABASE_STORAGE_H
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_DEFINITION_KIND_H
#define SOURCETRAIL_DEFINITION_KIND_H
namespace sourcetrail
{
/**
* Enum providing all possible values for a symbol's definition kind.
*
* The DefinitionKind specifies "how" a symbol is defined.
* When recording the definition of a symbol, you would usually also record an explicit definition kind.
* However, you may also want to record symbols that are implicitly generated by the compiler. In this case you can
* record an implicit definition kind for those symbols.
* If you do not record any definition kind for a symbol, Sourcetrail will show it as "non-indexed".
*/
enum class DefinitionKind : int
{
IMPLICIT = 1,
EXPLICIT = 2
};
int definitionKindToInt(DefinitionKind kind);
DefinitionKind intToDefinitionKind(int i);
}
#endif // SOURCETRAIL_DEFINITION_KIND_H
+56
View File
@@ -0,0 +1,56 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_EDGE_KIND_H
#define SOURCETRAIL_EDGE_KIND_H
namespace sourcetrail
{
/**
* Enum providing all possible values for kinds of edges that can be stored to the Sourcetrail database.
*
* The DatabaseStorage provides the interface for writing and updating the Sourcetrail database. This interface only
* The EdgeKind enum should only be used internally and contains a complete list of values that may be written to
* the Sourcetrail database file. This enum contains kinds for edges that can be recorded explicitly, but also kinds
* for edges that will be created implicitly. For example edges of type "EDGE_MEMBER" will be created while storing parent
* child node relations when recording symbols with hierarchical names (see NameHierarchy).
*/
enum class EdgeKind : int
{
UNKNOWN = 0,
MEMBER = 1 << 0,
TYPE_USAGE = 1 << 1,
USAGE = 1 << 2,
CALL = 1 << 3,
INHERITANCE = 1 << 4,
OVERRIDE = 1 << 5,
TEMPLATE_ARGUMENT = 1 << 6,
TYPE_ARGUMENT = 1 << 7,
TEMPLATE_DEFAULT_ARGUMENT = 1 << 8,
TEMPLATE_SPECIALIZATION = 1 << 9,
TEMPLATE_MEMBER_SPECIALIZATION = 1 << 10,
INCLUDE = 1 << 11,
IMPORT = 1 << 12,
AGGREGATION = 1 << 13,
MACRO_USAGE = 1 << 14,
ANNOTATION_USAGE = 1 << 15
};
int edgeKindToInt(EdgeKind kind);
EdgeKind intToEdgeKind(int i);
}
#endif // SOURCETRAIL_EDGE_KIND_H
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_LOCATION_KIND_H
#define SOURCETRAIL_LOCATION_KIND_H
namespace sourcetrail
{
/**
* Enum providing all possible values for kinds of locations that can be stored to the Sourcetrail database.
*/
enum class LocationKind : int
{
TOKEN = 0,
SCOPE = 1,
QUALIFIER = 2,
LOCAL_SYMBOL = 3,
SIGNATURE = 4,
ATOMIC_RANGE = 5,
INDEXER_ERROR = 6,
FULLTEXT_SEARCH = 7,
SCREEN_SEARCH = 8
};
int locationKindToInt(LocationKind kind);
LocationKind intToLocationKind(int i);
}
#endif // SOURCETRAIL_LOCATION_KIND_H
+98
View File
@@ -0,0 +1,98 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_NAME_HIERARCHY_H
#define SOURCETRAIL_NAME_HIERARCHY_H
#include <string>
#include <vector>
namespace sourcetrail
{
/**
* Struct that represents a single hierarchical element that is part of a symbol's name.
*
* prefix: optional prefix used for unique identification and shown in tooltips
* name: name represented by this element
* postfix: optional prefix used for unique identification and shown in tooltips
*/
struct NameElement
{
std::string prefix;
std::string name;
std::string postfix;
};
/**
* Struct that represents an entire name of a symbol.
*
* nameDelimiter: delimiter added between name elements
* nameElements: all name elements that make up the hierarchy
*/
struct NameHierarchy
{
std::string nameDelimiter;
std::vector<NameElement> nameElements;
};
/**
* Converts a NameHierarchy to a JSON string
*
* param: nameHierarchy - the name hierarchy to convert to JSON string
*
* return: a JSON object of the form:
* {
* "name_delimiter" : "."
* "name_elements" : [
* {
* "prefix" : "",
* "name" : "",
* "postfix" : ""
* },
* ...
* ]
* }
*/
std::string serializeNameHierarchyToJson(const NameHierarchy& nameHierarchy);
/**
* Converts a JSON string to a NameHierarchy
*
* param: serializedNameHierarchy - JSON object string of the form:
* {
* "name_delimiter" : "."
* "name_elements" : [
* {
* "prefix" : "",
* "name" : "",
* "postfix" : ""
* },
* ...
* ]
* }
* param: error - optional pointer to a string, where an error message will be set
*
* return: NameHierarchy object. Empty on failure.
*/
NameHierarchy deserializeNameHierarchyFromJson(const std::string& serializedNameHierarchy, std::string* error = nullptr);
/**
* INTERNAL: Converts a NameHierarchy to a string in Sourcetrail database format
*/
std::string serializeNameHierarchyToDatabaseString(const NameHierarchy& nameHierarchy);
}
#endif // SOURCETRAIL_NAME_HIERARCHY_H
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_NODE_KIND_H
#define SOURCETRAIL_NODE_KIND_H
namespace sourcetrail
{
/**
* Enum providing all possible values for kinds of nodes that can be stored to the Sourcetrail database.
*/
enum class NodeKind : int
{
UNKNOWN = 1 << 0,
TYPE = 1 << 1,
BUILTIN_TYPE = 1 << 2,
MODULE = 1 << 3,
NAMESPACE = 1 << 4,
PACKAGE = 1 << 5,
STRUCT = 1 << 6,
CLASS = 1 << 7,
INTERFACE = 1 << 8,
ANNOTATION = 1 << 9,
GLOBAL_VARIABLE = 1 << 10,
FIELD = 1 << 11,
FUNCTION = 1 << 12,
METHOD = 1 << 13,
ENUM = 1 << 14,
ENUM_CONSTANT = 1 << 15,
TYPEDEF = 1 << 16,
TEMPLATE_PARAMETER = 1 << 17,
TYPE_PARAMETER = 1 << 18,
FILE = 1 << 19,
MACRO = 1 << 20,
UNION = 1 << 21
};
int nodeKindToInt(NodeKind kind);
NodeKind intToNodeKind(int i);
}
#endif // SOURCETRAIL_NODE_KIND_H
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_REFERENCE_KIND_H
#define SOURCETRAIL_REFERENCE_KIND_H
#include "EdgeKind.h"
namespace sourcetrail
{
/**
* Enum providing all possible values for kinds of references that can be recorded using the SourcetrailDBWriter interface.
*/
enum class ReferenceKind
{
TYPE_USAGE,
USAGE,
CALL,
INHERITANCE,
OVERRIDE,
TEMPLATE_ARGUMENT,
TYPE_ARGUMENT,
TEMPLATE_DEFAULT_ARGUMENT,
TEMPLATE_SPECIALIZATION,
TEMPLATE_MEMBER_SPECIALIZATION,
INCLUDE,
IMPORT,
MACRO_USAGE,
ANNOTATION_USAGE
};
EdgeKind referenceKindToEdgeKind(ReferenceKind kind);
}
#endif // SOURCETRAIL_REFERENCE_KIND_H
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_SOURCE_RANGE_H
#define SOURCETRAIL_SOURCE_RANGE_H
namespace sourcetrail
{
/**
* Struct that represents the location of a range of characters in a source file.
*
* note: Line and column numbers start at 1 instead of 0!
* note: The SourceRange includes both, the start and the end column number.
*/
struct SourceRange
{
int fileId;
int startLine;
int startColumn;
int endLine;
int endColumn;
};
}
#endif // SOURCETRAIL_SOURCE_RANGE_H
+486
View File
@@ -0,0 +1,486 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_SRCTRLDB_WRITER_H
#define SOURCETRAIL_SRCTRLDB_WRITER_H
#include <memory>
#include <string>
#include "DefinitionKind.h"
#include "EdgeKind.h"
#include "LocationKind.h"
#include "NameHierarchy.h"
#include "ReferenceKind.h"
#include "SourceRange.h"
#include "SymbolKind.h"
namespace sourcetrail
{
class DatabaseStorage;
/**
* SourcetrailDBWriter
*
* This class is the main interface for writing data to a Sourcetrail project database.
* It be used to manage a Sourcetrail database file and to write information to it.
*
* The following code snippet illustrates a very basic usage of the SourcetrailDBWriter class:
*
* sourcetrail::SourcetrailDBWriter writer;
* writer.open("MyProject.srctrldb");
* writer.recordSymbol({ "::",{ { "void", "foo", "()" } } });
* writer.close();
*/
class SourcetrailDBWriter
{
public:
SourcetrailDBWriter();
~SourcetrailDBWriter();
/**
* Provides the version of the SourcetrailDB Core as string with format "vXX.dbYY.pZZ"
*
* - XX: interface version. This version increases on every change that breaks backwards
* compatibility.
* - YY: Sourcetrail database version. This version needs to match the database version
* of the used Sourcetrail instance. You can find the database version of Sourcetrail
* in its About dialog.
* - ZZ: patch number of the build. It will increase with every release that publishes
* bugfixes and features that don't break any compatibility.
*
* return: version string
*/
std::string getVersionString() const;
/**
* Provides the supported database version as integer
*
* return: supported database version
*
* see: getVersionString() for details
*/
int getSupportedDatabaseVersion() const;
/**
* Provides the last error that occurred while using the SourcetrailDBWriter
*
* The last error is empty if no error occurred since instantiation of the class or since the
* error has last been cleared.
*
* return: error message of last error that occured
*
* see: clearLastError()
*/
const std::string& getLastError() const;
/**
* Modifies the stored error message
*
* param: error - the new error message
*
* see: getLastError()
*/
void setLastError(const std::string& error) const;
/**
* Clears the stored error message
*
* see: getLastError()
*/
void clearLastError();
/**
* Opens a Sourcetrail database
*
* Call this method to open a Sourcetrail database file. If the database does not have any
* related .srctrlprj project file, a minimal project file will be created that allows for
* opening the database with Sourcetrail.
*
* param: databaseFilePath - absolute file path of the database file, including file extension
*
* return: true if successful. false on failure. getLastError() provides the error message.
*/
bool open(const std::string& databaseFilePath);
/**
* Closes the currently open Sourcetrail database
*
* return: Returns true if the operation was successful. Otherwise false is returned and getLastError()
* can be checked for more detailed information.
*
* see: open(const std::string& databaseFilePath)
*/
bool close();
/**
* Clears the currently open Sourcetrail database
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: open(const std::string& databaseFilePath)
*/
bool clear();
/**
* Checks if the currently open database file contains any data
*
* return: true after opening a non-existing database file or clearing the open database
*/
bool isEmpty() const;
/**
* Checks if the currently open database is compatible with the SourcetrailDBWriter version.
*
* return: true for an empty database or a database that has been created with the same
* database version.
*
* see: getSupportedDatabaseVersion()
* see: getLoadedDatabaseVersion()
*/
bool isCompatible() const;
/**
* Provides the database version of the loaded database file as an integer
*
* return: database version of loaded database
*/
int getLoadedDatabaseVersion() const;
/**
* Starts a database transaction on the currently open database
*
* Apart from allowing to restore the database to the state it was in before this method has
* been called, wrapping multiple calls that record data with one transaction significantly
* increases the performance of these database operations.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: commitTransaction()
* see: rollbackTransaction()
*/
bool beginTransaction();
/**
* Ends the current transaction and writes all of its changes persistently to the database
*
* return: true if successful. false on failure. getLastError() provides the error message.
*/
bool commitTransaction();
/**
* Reverts the database to the state it was in before the current transaction was started
*
* return: true if successful. false on failure. getLastError() provides the error message.
*/
bool rollbackTransaction();
/**
* Reduces the on disk memory consumption of the open database to a minimum
*
* return: true if successful. false on failure. getLastError() provides the error message.
*/
bool optimizeDatabaseMemory();
/**
* Stores a symbol to the database
*
* note: Calling this method multiple times with the same input on the same Sourcetrail
* database will always return the same id.
*
* param: nameHierarchy - the name of the symbol to store.
*
* return: symbolId - integer id of the stored symbol. 0 on failure. getLastError()
* provides the error message.
*
* see: NameHierarchy
*/
int recordSymbol(const NameHierarchy& nameHierarchy);
/**
* Stores a definition kind for a specific symbol to the database
*
* Calling this method allows to store a DefinitionKind (e.g. explicitly defined, implicitly
* defined) for a symbol referenced by id to the database. Calling this method with the same
* symbolId multiple times overwrites the symbol's previously recorded DefinitionKind. If no
* DefinitionKind is recorded for a symbol, Sourcetrail treats this symbol as "non-indexed".
* This may be desired while recording a reference to a symbol with a definition that is located
* outside of the indexed source files.
*
* param: symbolId - the id of the symbol for which a DefinitionKind shall be recorded.
* param: definitionKind - the DefinitionKind that shall be recorded for the respective symbol.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: DefinitionKind
*/
bool recordSymbolDefinitionKind(int symbolId, DefinitionKind definitionKind);
/**
* Stores a symbol kind for a specific symbol to the database
*
* Calling this method allows to store a SymbolKind (e.g. "class", "function", etc.) for a
* symbol referenced by id to the database. Calling this method with the same symbolId multiple
* times overwrites the symbol's previously recorded SymbolKind. If no SymbolKind is recorded
* for a symbol, Sourcetrail displays the type of this symbol as "symbol".
*
* param: symbolId - the id of the symbol for which a SymbolKind shall be recorded.
* param: symbolKind - the SymbolKind that shall be recorded for the respective symbol.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SymbolKind
*/
bool recordSymbolKind(int symbolId, SymbolKind symbolKind);
/**
* Stores a location for a specific symbol to the database
*
* This method allows to store a location for a symbol referenced by id to the database.
* Calling this method with the same symbolId multiple times adds multiple locations for the
* respective symbol. The stored location will be clickable and displayable. When clicked
* Sourcetrail will activate the symbol with the specified id. When the symbol with the specified
* id is activated, this location will be displayed and highlighted by Sourcetrail.
*
* param: symbolId - the id of the symbol for which a location shall be recorded.
* param: location - the SourceRange that shall be recorded as location for the respective symbol.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordSymbolLocation(int symbolId, const SourceRange& location);
/**
* Stores a scope location for a specific symbol to the database
*
* This method allows to store a scope location for a symbol referenced by id to the database.
* Calling this method with the same symbolId multiple times adds multiple scope locations for the
* respective symbol. The stored location will only be displayable and not clickable. When the
* symbol with the specified id is activated, this location will be fully displayed but not
* highlighted by Sourcetrail.
*
* param: symbolId - the id of the symbol for which a scope location shall be recorded.
* param: location - the SourceRange that shall be recorded as scope location for the respective
* symbol.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordSymbolScopeLocation(int symbolId, const SourceRange& location);
/**
* Stores a signature location for a specific symbol to the database
*
* This method allows to store a signature location for a symbol referenced by id to the
* database. If a signature location is recorded for a symbol, Sourcetrail will display the
* respective source code in a tooltip whenever the symbol with the referenced id or any of
* that symbol's locations gets hovered.
* If no signature location is recorded for a symbol, Sourcetrail will show its name hierarchy.
*
* note: Calling this method with the same symbolId multiple times adds multiple signature
* locations for the respective symbol. It is not guaranteed which one will be used, so it is
* advised to call it only once per symbol.
*
* param: symbolId - the id of the symbol for which a signature location shall be recorded.
* param: location - the SourceRange that shall be recorded as signature location for the
* respective symbol.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordSymbolSignatureLocation(int symbolId, const SourceRange& location);
/**
* Stores a reference between two symbols to the database
*
* This method allows to store the information of symbols referencing one another to the database.
* For each recorded reference Sourcetrail's graph view will display an edge that originates at
* the reference's recorded context symbol and points to the recorded referenced symbol. The
* recorded ReferenceKind is used to determine the type of the displayed edge and to generate a
* description in the hover tooltip of the edge.
*
* note: Calling this method multiple times with the same input on the same Sourcetrail database
* will always return the same id.
*
* param: contextSymbolId - the id of the source of the recorded reference edge
* param: referencedSymbolId - the id of the target of the recorded reference edge
* param: referenceKind - kind of the recorded reference edge
*
* return: referenceId - integer id of the stored reference. 0 on failure. getLastError()
* provides the error message.
*
* see: ReferenceKind
*/
int recordReference(int contextSymbolId, int referencedSymbolId, ReferenceKind referenceKind);
/**
* Stores a location for a specific reference to the database
*
* This method allows to store a location for a reference to the database.
* Calling this method with the same referenceId multiple times adds multiple locations for the
* respective reference. The stored location will be clickable and displayable. When the reference
* location is clicked Sourcetrail will activate the symbol referenced by the respective reference.
* When the reference with the specified id is activated, this location will be displayed and
* highlighted by Sourcetrail.
*
* param: referenceId - the id of the reference for which a location shall be recorded.
* param: location - the SourceRange that shall be recorded as location for the respective
* reference.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordReferenceLocation(int referenceId, const SourceRange& location);
/**
* Stores a location for the usage of a symbol's name as qualifier to the database
*
* This method allows to store a location where a specific symbol is used as a qualifier to the
* database. Calling this method with the same referencedSymbolId multiple times adds multiple locations
* for the respective reference. The stored location will be clickable but not displayable: When the
* reference location is clicked Sourcetrail will activate the symbol referenced by the respective
* reference. When the symbol with the specified id is activated, this location will NOT be displayed and
* highlighted by Sourcetrail.
*
* param: referencedSymbolId - the id of the symbol that is used as qualifier at the current location.
* param: location - the SourceRange that shall be recorded as location for the symbol's occurrence as
* qualifier
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordQualifierLocation(int referencedSymbolId, const SourceRange& location);
/**
* Stores a file to the database
*
* note: Calling this method multiple times with the same input on the same Sourcetrail database
* will always return the same id.
*
* param: filePath - the absolute path to the file to store.
*
* return: fileId - integer id of the stored file. 0 on failure. getLastError() provides the
* error message.
*/
int recordFile(const std::string& filePath);
/**
* Stores language information for a specific file to the database
*
* This method allows to store language information for a file to the database. Language information
* is passed and stored as string (e.g. "cpp", "java", etc.) and allows Sourcetrail to pick the
* correct syntax highlighting rules when displaying the respective source file.
*
* param: fileId - the id of the file for which language information shall be recorded.
* param: languageIdentifier - a string that denotes the programming language the respective file
* is written in.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*/
bool recordFileLanguage(int fileId, const std::string& languageIdentifier);
/**
* Stores a local symbol to the database
*
* note: Calling this method multiple times with the same input on the same Sourcetrail database
* will always return the same id.
*
* param: name - a name that is unique for this local symbol (e.g. the string encoded location
* of the local symbol's definition).
*
* return: localSymbolId - integer id of the stored local symbol. 0 on failure. getLastError()
* provides the error message.
*/
int recordLocalSymbol(const std::string& name);
/**
* Stores a location for a specific local symbol to the database
*
* This method allows to store a location for a local symbol symbol referenced by id to the database.
* Calling this method with the same symbolId multiple times adds multiple locations for the
* respective local symbol. The stored location will be clickable and displayable. When clicked
* Sourcetrail will activate this and all other local symbol locations that share the same local
* symbol id.
*
* param: localSymbolId - the id of the local symbol for which a location shall be recorded.
* param: location - the SourceRange that shall be recorded as location for the respective
* local symbol.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordLocalSymbolLocation(int localSymbolId, const SourceRange& location);
/**
* Stores an atomic SourceRange to the database
*
* This method allows to store an atomic SourceRange to the database. These ranges will
* be used by Sourcetrail to prevent the code view from displaying only a part of the range. Thus,
* if any line that lies within one of the project's atomic ranges is dispayed, the remaining
* lines will be displayed as well. This may be useful for dealing with multi-line comments or
* multi-line strings.
*
* param: sourceRange - the SourceRange to record.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordAtomicSourceRange(const SourceRange& sourceRange);
/**
* Stores an indexing error to the database
*
* This method allows to store an indexing error to the database. Errors will be shown by
* Sourcetrail's error view. When clicking the error in Sourcetrail's error list, the code view
* will display this location.
*
* param: message - an error message that will be displayed in Sourcetrail's error list.
* param: fatal - boolean fatal indicates whether parsing/indexing was aborted at this point.
* param: location - the SourceRange of the error encountered.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordError(const std::string& message, bool fatal, const SourceRange& location);
private:
void openDatabase();
void closeDatabase();
void setupDatabaseTables();
void clearDatabaseTables();
void createOrResetProjectFile();
void updateProjectSettingsText();
int addNodeHierarchy(const NameHierarchy& nameHierarchy);
int addFile(const std::string& filePath);
int addEdge(int sourceId, int targetId, EdgeKind edgeKind);
void addSourceLocation(int elementId, const SourceRange& location, LocationKind kind);
std::string m_projectFilePath;
std::string m_databaseFilePath;
std::unique_ptr<DatabaseStorage> m_storage;
mutable std::string m_lastError;
};
}
#endif // SOURCETRAIL_SRCTRLDB_WRITER_H
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_SOURCETRAIL_EXCEPTION_H
#define SOURCETRAIL_SOURCETRAIL_EXCEPTION_H
#include <string>
namespace sourcetrail
{
/**
* Exception type that is thrown by the SourcetrailDBWriter API.
*/
class SourcetrailException
{
public:
SourcetrailException(std::string message) : m_message(message) {}
virtual ~SourcetrailException() = default;
std::string getMessage() const { return m_message; }
private:
std::string m_message;
};
}
#endif // SOURCETRAIL_SOURCETRAIL_EXCEPTION_H
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_EDGE_H
#define SOURCETRAIL_STORAGE_EDGE_H
namespace sourcetrail
{
struct StorageEdgeData
{
StorageEdgeData()
: sourceNodeId(0)
, targetNodeId(0)
, edgeKind(0)
{}
StorageEdgeData(int sourceNodeId, int targetNodeId, int edgeKind)
: sourceNodeId(sourceNodeId)
, targetNodeId(targetNodeId)
, edgeKind(edgeKind)
{}
int sourceNodeId;
int targetNodeId;
int edgeKind;
};
struct StorageEdge : public StorageEdgeData
{
StorageEdge()
: StorageEdgeData()
, id(0)
{}
StorageEdge(int id, const StorageEdgeData& data)
: StorageEdgeData(data)
, id(id)
{}
StorageEdge(int id, int sourceNodeId, int targetNodeId, int edgeKind)
: StorageEdgeData(sourceNodeId, targetNodeId, edgeKind)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_EDGE_H
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_ERROR_H
#define SOURCETRAIL_STORAGE_ERROR_H
#include <string>
namespace sourcetrail
{
struct StorageErrorData
{
StorageErrorData()
: message("")
, translationUnit("")
, fatal(0)
, indexed(0)
{}
StorageErrorData(
std::string message,
std::string translationUnit,
bool fatal,
bool indexed
)
: message(std::move(message))
, translationUnit(std::move(translationUnit))
, fatal(fatal)
, indexed(indexed)
{}
std::string message;
std::string translationUnit;
bool fatal;
bool indexed;
};
struct StorageError : public StorageErrorData
{
StorageError()
: StorageErrorData()
, id(0)
{}
StorageError(int id, const StorageErrorData& data)
: StorageErrorData(data)
, id(id)
{}
StorageError(
int id,
std::string message,
std::string translationUnit,
bool fatal,
bool indexed
)
: StorageErrorData(
std::move(message),
std::move(translationUnit),
fatal,
indexed
)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_ERROR_H
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_FILE_H
#define SOURCETRAIL_STORAGE_FILE_H
#include <string>
namespace sourcetrail
{
struct StorageFile
{
StorageFile()
: id(0)
, filePath("")
, languageIdentifier("")
, modificationTime("")
, indexed(true)
, complete(true)
{}
StorageFile(int id, std::string filePath, std::string languageIdentifier, std::string modificationTime, bool indexed, bool complete)
: id(id)
, filePath(std::move(filePath))
, languageIdentifier(std::move(languageIdentifier))
, modificationTime(std::move(modificationTime))
, indexed(indexed)
, complete(complete)
{}
int id;
std::string filePath;
std::string languageIdentifier;
std::string modificationTime;
bool indexed;
bool complete;
};
}
#endif // SOURCETRAIL_STORAGE_FILE_H
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_LOCAL_SYMBOL_H
#define SOURCETRAIL_STORAGE_LOCAL_SYMBOL_H
#include <string>
namespace sourcetrail
{
struct StorageLocalSymbolData
{
StorageLocalSymbolData()
: name("")
{}
StorageLocalSymbolData(std::string name)
: name(std::move(name))
{}
std::string name;
};
struct StorageLocalSymbol : public StorageLocalSymbolData
{
StorageLocalSymbol()
: StorageLocalSymbolData()
, id(0)
{}
StorageLocalSymbol(int id, const StorageLocalSymbolData& data)
: StorageLocalSymbolData(data)
, id(id)
{}
StorageLocalSymbol(int id, std::string name)
: StorageLocalSymbolData(std::move(name))
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_LOCAL_SYMBOL_H
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_NODE_H
#define SOURCETRAIL_STORAGE_NODE_H
#include <string>
namespace sourcetrail
{
struct StorageNodeData
{
StorageNodeData()
: nodeKind(0)
, serializedName("")
{}
StorageNodeData(int nodeKind, std::string serializedName)
: nodeKind(nodeKind)
, serializedName(std::move(serializedName))
{}
int nodeKind;
std::string serializedName;
};
struct StorageNode : public StorageNodeData
{
StorageNode()
: StorageNodeData()
, id(0)
{}
StorageNode(int id, int nodeKind, std::string serializedName)
: StorageNodeData(nodeKind, std::move(serializedName))
, id(id)
{}
StorageNode(int id, const StorageNodeData& data)
: StorageNodeData(data)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_NODE_H
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_OCCURRENCE_H
#define SOURCETRAIL_STORAGE_OCCURRENCE_H
namespace sourcetrail
{
struct StorageOccurrence
{
StorageOccurrence()
: elementId(0)
, sourceLocationId(0)
{}
StorageOccurrence(int elementId, int sourceLocationId)
: elementId(elementId)
, sourceLocationId(sourceLocationId)
{}
int elementId;
int sourceLocationId;
};
}
#endif // SOURCETRAIL_STORAGE_OCCURRENCE_H
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_SOURCE_LOCATION_H
#define SOURCETRAIL_STORAGE_SOURCE_LOCATION_H
namespace sourcetrail
{
struct StorageSourceLocationData
{
StorageSourceLocationData()
: fileNodeId(0)
, startLineNumber(-1)
, startColumnNumber(-1)
, endLineNumber(-1)
, endColumnNumber(-1)
, locationKind(0)
{}
StorageSourceLocationData(int fileNodeId, int startLineNumber, int startColumnNumber, int endLineNumber, int endColumnNumber, int locationKind)
: fileNodeId(fileNodeId)
, startLineNumber(startLineNumber)
, startColumnNumber(startColumnNumber)
, endLineNumber(endLineNumber)
, endColumnNumber(endColumnNumber)
, locationKind(locationKind)
{}
int fileNodeId;
int startLineNumber;
int startColumnNumber;
int endLineNumber;
int endColumnNumber;
int locationKind;
};
struct StorageSourceLocation : public StorageSourceLocationData
{
StorageSourceLocation()
: StorageSourceLocationData()
, id(0)
{}
StorageSourceLocation(int id, const StorageSourceLocationData& data)
: StorageSourceLocationData(data)
, id(id)
{}
StorageSourceLocation(int id, int fileNodeId, int startLineNumber, int startColumnNumber, int endLineNumber, int endColumnNumber, int locationKind)
: StorageSourceLocationData(fileNodeId, startLineNumber, startColumnNumber, endLineNumber, endColumnNumber, locationKind)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_SOURCE_LOCATION_H
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_SYMBOL_H
#define SOURCETRAIL_STORAGE_SYMBOL_H
#include "DefinitionKind.h"
namespace sourcetrail
{
struct StorageSymbol
{
StorageSymbol()
: id(0)
, definitionKind(definitionKindToInt(DefinitionKind::EXPLICIT))
{}
StorageSymbol(int id, int definitionKind)
: id(id)
, definitionKind(definitionKind)
{}
int id;
int definitionKind;
};
}
#endif // SOURCETRAIL_STORAGE_SYMBOL_H
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_SYMBOL_KIND_H
#define SOURCETRAIL_SYMBOL_KIND_H
#include "NodeKind.h"
namespace sourcetrail
{
/**
* Enum providing all possible values for kinds of symbols that can be recorded using the SourcetrailDBWriter interface.
*/
enum class SymbolKind
{
TYPE,
BUILTIN_TYPE,
MODULE,
NAMESPACE,
PACKAGE,
STRUCT,
CLASS,
INTERFACE,
ANNOTATION,
GLOBAL_VARIABLE,
FIELD,
FUNCTION,
METHOD,
ENUM,
ENUM_CONSTANT,
TYPEDEF,
TEMPLATE_PARAMETER,
TYPE_PARAMETER,
MACRO,
UNION
};
NodeKind symbolKindToNodeKind(SymbolKind kind);
}
#endif // SOURCETRAIL_SYMBOL_KIND_H
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_UTILITY_H
#define SOURCETRAIL_UTILITY_H
#include <string>
#include <time.h>
namespace sourcetrail
{
namespace utility
{
bool getFileExists(const std::string& filePath);
std::string getFileContent(const std::string& filePath);
std::string getDateTimeString(const time_t& time);
int getLineCount(const std::string s);
}
}
#endif // SOURCETRAIL_UTILITY_H
+954
View File
@@ -0,0 +1,954 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "DatabaseStorage.h"
#include <vector>
#include "SourcetrailException.h"
#include "StorageFile.h"
#include "StorageNode.h"
#include "StorageSymbol.h"
#include "NodeKind.h"
#include "utility.h"
#include "version.h"
namespace sourcetrail
{
// --- Public Interface ---
int DatabaseStorage::getSupportedDatabaseVersion()
{
return DATABASE_VERSION;
}
std::unique_ptr<DatabaseStorage> DatabaseStorage::openDatabase(const std::string& dbFilePath)
{
try
{
std::unique_ptr<DatabaseStorage> storage = std::unique_ptr<DatabaseStorage>(new DatabaseStorage());
storage->m_database.open(dbFilePath.c_str());
storage->executeStatement("PRAGMA foreign_keys=ON;");
return std::move(storage);
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException(e.errorMessage());
}
}
DatabaseStorage::~DatabaseStorage()
{
clearPrecompiledStatements();
m_database.close();
}
void DatabaseStorage::setupDatabase()
{
executeStatement("PRAGMA foreign_keys=ON;");
if (!isCompatible())
{
throw SourcetrailException("Unable to setup database tables because database is not compatible.");
}
setupTables();
setupIndices();
setupPrecompiledStatements();
insertOrUpdateMetaValue("storage_version", std::to_string(getSupportedDatabaseVersion()));
}
void DatabaseStorage::clearDatabase()
{
executeStatement("PRAGMA foreign_keys=OFF;");
clearPrecompiledStatements();
clearTables();
setupDatabase();
}
void DatabaseStorage::setProjectSettingsText(const std::string& text)
{
insertOrUpdateMetaValue("project_settings", text);
}
bool DatabaseStorage::isEmpty() const
{
const std::string tableName = "meta";
CppSQLite3Query q = executeQuery(
"SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "';"
);
if (!q.eof())
{
return q.getStringField(0, "") == tableName;
}
return true;
}
bool DatabaseStorage::isCompatible() const
{
if (isEmpty())
{
return true;
}
return getLoadedDatabaseVersion() == getSupportedDatabaseVersion();
}
int DatabaseStorage::getLoadedDatabaseVersion() const
{
if (isEmpty())
{
throw SourcetrailException("Unable to determine version of an empty database.");
}
CppSQLite3Query q = executeQuery("SELECT value FROM meta WHERE key = 'storage_version';");
if (!q.eof())
{
return std::stoi(q.getStringField(0, "0"));
}
return 0;
}
void DatabaseStorage::beginTransaction()
{
executeStatement("BEGIN TRANSACTION;");
}
void DatabaseStorage::commitTransaction()
{
executeStatement("COMMIT TRANSACTION;");
}
void DatabaseStorage::rollbackTransaction()
{
executeStatement("ROLLBACK TRANSACTION;");
}
void DatabaseStorage::optimizeDatabaseMemory()
{
executeStatement("VACUUM;");
}
int DatabaseStorage::addNode(const StorageNodeData& storageNodeData)
{
int id = 0;
{
m_findNodeStatement.bind(1, storageNodeData.serializedName.c_str());
CppSQLite3Query q = executeQuery(m_findNodeStatement);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
m_findNodeStatement.reset();
}
// FIXME: update node nodeKind here
if (id == 0)
{
id = insertElement();
m_insertNodeStatement.bind(1, id);
m_insertNodeStatement.bind(2, storageNodeData.nodeKind);
m_insertNodeStatement.bind(3, storageNodeData.serializedName.c_str());
executeStatement(m_insertNodeStatement);
m_insertNodeStatement.reset();
}
return id;
}
void DatabaseStorage::addSymbol(const StorageSymbol& storageSymbol)
{
m_insertSymbolStatement.bind(1, storageSymbol.id);
m_insertSymbolStatement.bind(2, storageSymbol.definitionKind);
executeStatement(m_insertSymbolStatement);
m_insertSymbolStatement.reset();
}
void DatabaseStorage::addFile(const StorageFile& storageFile)
{
{
m_findFileStatement.bind(1, storageFile.id);
CppSQLite3Query q = executeQuery(m_findFileStatement);
bool exists = !q.eof();
m_findFileStatement.reset();
if (exists)
{
return;
}
}
std::string content = "";
if (utility::getFileExists(storageFile.filePath))
{
content = utility::getFileContent(storageFile.filePath);
}
const int lineCount = utility::getLineCount(content);
{
m_insertFileStatement.bind(1, storageFile.id);
m_insertFileStatement.bind(2, storageFile.filePath.c_str());
m_insertFileStatement.bind(3, storageFile.languageIdentifier.c_str());
m_insertFileStatement.bind(4, storageFile.modificationTime.c_str());
m_insertFileStatement.bind(5, storageFile.indexed);
m_insertFileStatement.bind(6, storageFile.complete);
m_insertFileStatement.bind(7, lineCount);
executeStatement(m_insertFileStatement);
m_insertFileStatement.reset();
}
if (!content.empty())
{
m_insertFileContentStatement.bind(1, storageFile.id);
m_insertFileContentStatement.bind(2, content.c_str());
executeStatement(m_insertFileContentStatement);
m_insertFileContentStatement.reset();
}
}
int DatabaseStorage::addEdge(const StorageEdgeData& storageEdgeData)
{
int id = 0;
{
m_findEdgeStatement.bind(1, storageEdgeData.sourceNodeId);
m_findEdgeStatement.bind(2, storageEdgeData.targetNodeId);
m_findEdgeStatement.bind(3, storageEdgeData.edgeKind);
CppSQLite3Query q = executeQuery(m_findEdgeStatement);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
m_findEdgeStatement.reset();
}
if (id == 0)
{
id = insertElement();
m_insertEdgeStatement.bind(1, id);
m_insertEdgeStatement.bind(2, storageEdgeData.edgeKind);
m_insertEdgeStatement.bind(3, storageEdgeData.sourceNodeId);
m_insertEdgeStatement.bind(4, storageEdgeData.targetNodeId);
executeStatement(m_insertEdgeStatement);
m_insertEdgeStatement.reset();
}
return id;
}
int DatabaseStorage::addLocalSymbol(const StorageLocalSymbolData& storageLocalSymbolData)
{
int id = 0;
{
m_findLocalSymbolStmt.bind(1, storageLocalSymbolData.name.c_str());
CppSQLite3Query q = executeQuery(m_findLocalSymbolStmt);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
m_findLocalSymbolStmt.reset();
}
if (id == 0)
{
id = insertElement();
m_insertLocalSymbolStmt.bind(1, id);
m_insertLocalSymbolStmt.bind(2, storageLocalSymbolData.name.c_str());
executeStatement(m_insertLocalSymbolStmt);
m_insertLocalSymbolStmt.reset();
}
return id;
}
int DatabaseStorage::addSourceLocation(const StorageSourceLocationData& storageSourceLocationData)
{
int id = 0;
{
m_findSourceLocationStmt.bind(1, storageSourceLocationData.fileNodeId);
m_findSourceLocationStmt.bind(2, storageSourceLocationData.startLineNumber);
m_findSourceLocationStmt.bind(3, storageSourceLocationData.startColumnNumber);
m_findSourceLocationStmt.bind(4, storageSourceLocationData.endLineNumber);
m_findSourceLocationStmt.bind(5, storageSourceLocationData.endColumnNumber);
m_findSourceLocationStmt.bind(6, storageSourceLocationData.locationKind);
CppSQLite3Query q = executeQuery(m_findSourceLocationStmt);
if (!q.eof())
{
id = q.getIntField(0, 0);
}
m_findSourceLocationStmt.reset();
}
if (id == 0)
{
m_insertSourceLocationStmt.bind(1, storageSourceLocationData.fileNodeId);
m_insertSourceLocationStmt.bind(2, storageSourceLocationData.startLineNumber);
m_insertSourceLocationStmt.bind(3, storageSourceLocationData.startColumnNumber);
m_insertSourceLocationStmt.bind(4, storageSourceLocationData.endLineNumber);
m_insertSourceLocationStmt.bind(5, storageSourceLocationData.endColumnNumber);
m_insertSourceLocationStmt.bind(6, storageSourceLocationData.locationKind);
executeStatement(m_insertSourceLocationStmt);
id = m_database.lastRowId();
m_insertSourceLocationStmt.reset();
}
return id;
}
void DatabaseStorage::addOccurrence(const StorageOccurrence& storageOccurrence)
{
m_insertOccurenceStmt.bind(1, storageOccurrence.elementId);
m_insertOccurenceStmt.bind(2, storageOccurrence.sourceLocationId);
executeStatement(m_insertOccurenceStmt);
m_insertOccurenceStmt.reset();
}
int DatabaseStorage::addError(const StorageErrorData& storageErrorData)
{
int id = 0;
{
m_findErrorStatement.bind(1, storageErrorData.message.c_str());
m_findErrorStatement.bind(2, storageErrorData.fatal);
CppSQLite3Query q = executeQuery(m_findErrorStatement);
if (!q.eof() && q.numFields() > 0)
{
id = q.getIntField(0, -1);
}
m_findErrorStatement.reset();
}
if (id == 0)
{
id = insertElement();
m_insertErrorStatement.bind(1, id);
m_insertErrorStatement.bind(2, storageErrorData.message.c_str());
m_insertErrorStatement.bind(3, storageErrorData.fatal);
m_insertErrorStatement.bind(4, storageErrorData.indexed);
m_insertErrorStatement.bind(5, storageErrorData.translationUnit.c_str());
executeStatement(m_insertErrorStatement);
id = m_database.lastRowId();
m_insertErrorStatement.reset();
}
return id;
}
void DatabaseStorage::setNodeType(int nodeId, int nodeType)
{
m_setNodeTypeStmt.bind(1, nodeType);
m_setNodeTypeStmt.bind(2, nodeId);
executeStatement(m_setNodeTypeStmt);
m_setNodeTypeStmt.reset();
}
void DatabaseStorage::setFileLanguage(int fileId, const std::string& languageIdentifier)
{
m_setFileLanguageStmt.bind(1, languageIdentifier.c_str());
m_setFileLanguageStmt.bind(2, fileId);
executeStatement(m_setFileLanguageStmt);
m_setFileLanguageStmt.reset();
}
// --- Private Interface ---
void DatabaseStorage::setupTables()
{
executeStatement(
"CREATE TABLE IF NOT EXISTS meta("
" id INTEGER, "
" key TEXT, "
" value TEXT, "
" PRIMARY KEY(id)"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS element("
" id INTEGER, "
" PRIMARY KEY(id)"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS edge("
" id INTEGER NOT NULL, "
" type INTEGER NOT NULL, "
" source_node_id INTEGER NOT NULL, "
" target_node_id INTEGER NOT NULL, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE, "
" FOREIGN KEY(source_node_id) REFERENCES node(id) ON DELETE CASCADE, "
" FOREIGN KEY(target_node_id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS node("
" id INTEGER NOT NULL, "
" type INTEGER NOT NULL, "
" serialized_name TEXT, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS symbol("
" id INTEGER NOT NULL, "
" definition_kind INTEGER NOT NULL, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS file("
" id INTEGER NOT NULL, "
" path TEXT, "
" language TEXT, "
" modification_time TEXT, "
" indexed INTEGER, "
" complete INTEGER, "
" line_count INTEGER, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS filecontent("
" id INTERGER, "
" content TEXT, "
" FOREIGN KEY(id) REFERENCES file(id)"
" ON DELETE CASCADE "
" ON UPDATE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS local_symbol("
" id INTEGER NOT NULL, "
" name TEXT, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS source_location("
" id INTEGER NOT NULL, "
" file_node_id INTEGER, "
" start_line INTEGER, "
" start_column INTEGER, "
" end_line INTEGER, "
" end_column INTEGER, "
" type INTEGER, "
" PRIMARY KEY(id), "
" FOREIGN KEY(file_node_id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS occurrence("
" element_id INTEGER NOT NULL, "
" source_location_id INTEGER NOT NULL, "
" PRIMARY KEY(element_id, source_location_id), "
" FOREIGN KEY(element_id) REFERENCES element(id) ON DELETE CASCADE, "
" FOREIGN KEY(source_location_id) REFERENCES source_location(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS component_access("
" node_id INTEGER NOT NULL, "
" type INTEGER NOT NULL, "
" PRIMARY KEY(node_id), "
" FOREIGN KEY(node_id) REFERENCES node(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS error("
" id INTEGER NOT NULL, "
" message TEXT, "
" fatal INTEGER NOT NULL, "
" indexed INTEGER NOT NULL, "
" translation_unit TEXT, "
" PRIMARY KEY(id), "
" FOREIGN KEY(id) REFERENCES element(id) ON DELETE CASCADE"
");"
);
}
void DatabaseStorage::clearTables()
{
const std::vector<std::string> tableNames = {
"meta",
"error",
"component_access",
"occurrence",
"source_location",
"local_symbol",
"filecontent",
"file",
"symbol",
"node",
"edge",
"element"
};
for (const std::string& tableName : tableNames)
{
executeStatement("DROP TABLE IF EXISTS main." + tableName + ";");
}
}
void DatabaseStorage::setupIndices()
{
executeStatement(
"CREATE INDEX IF NOT EXISTS node_serialized_name_index ON node(serialized_name);"
);
executeStatement(
"CREATE INDEX IF NOT EXISTS edge_source_target_type_index ON edge(source_node_id, target_node_id, type);"
);
executeStatement(
"CREATE INDEX IF NOT EXISTS local_symbol_name_index ON local_symbol(name);"
);
executeStatement(
"CREATE INDEX IF NOT EXISTS source_location_all_data_index "
"ON source_location(file_node_id, start_line, start_column, end_line, end_column, type);"
);
executeStatement(
"CREATE INDEX IF NOT EXISTS error_all_data_index ON error(message, fatal);"
);
}
void DatabaseStorage::setupPrecompiledStatements()
{
m_insertElementStatement = compileStatement(
"INSERT INTO element(id) VALUES(NULL);"
);
m_findNodeStatement = compileStatement(
"SELECT id FROM node WHERE serialized_name == ? LIMIT 1;"
);
m_insertNodeStatement = compileStatement(
"INSERT INTO node(id, type, serialized_name) VALUES(?, ?, ?);"
);
m_setNodeTypeStmt = compileStatement(
"UPDATE node SET type = ? WHERE id == ?;"
);
m_insertSymbolStatement = compileStatement(
"INSERT OR IGNORE INTO symbol(id, definition_kind) VALUES(?, ?);"
);
m_findFileStatement = compileStatement(
"SELECT id FROM file WHERE id == ?;"
);
m_insertFileStatement = compileStatement(
"INSERT OR IGNORE INTO file(id, path, language, modification_time, indexed, complete, line_count) VALUES(?, ?, ?, ?, ?, ?, ?);"
);
m_setFileLanguageStmt = compileStatement(
"UPDATE file SET language = ? WHERE id == ?;"
);
m_insertFileContentStatement = compileStatement(
"INSERT INTO filecontent(id, content) VALUES(?, ?);"
);
m_findEdgeStatement = compileStatement(
"SELECT id FROM edge WHERE source_node_id == ? AND target_node_id == ? AND type == ? LIMIT 1;"
);
m_insertEdgeStatement = compileStatement(
"INSERT INTO edge(id, type, source_node_id, target_node_id) VALUES(?, ?, ?, ?);"
);
m_findLocalSymbolStmt = compileStatement(
"SELECT id FROM local_symbol WHERE name == ? LIMIT 1;"
);
m_insertLocalSymbolStmt = compileStatement(
"INSERT INTO local_symbol(id, name) VALUES(?, ?);"
);
m_findSourceLocationStmt = compileStatement(
"SELECT id FROM source_location WHERE "
"file_node_id = ? AND "
"start_line = ? AND "
"start_column = ? AND "
"end_line = ? AND "
"end_column = ? AND "
"type = ? "
"LIMIT 1;"
);
m_insertSourceLocationStmt = compileStatement(
"INSERT INTO source_location("
"id, file_node_id, start_line, start_column, end_line, end_column, type) "
"VALUES(NULL, ?, ?, ?, ?, ?, ?);"
);
m_insertOccurenceStmt = compileStatement(
"INSERT OR IGNORE INTO occurrence(element_id, source_location_id) VALUES(?, ?);"
);
m_findErrorStatement = compileStatement(
"SELECT id FROM error WHERE "
"message = ? AND "
"fatal == ? "
"LIMIT 1;"
);
m_insertErrorStatement = compileStatement(
"INSERT INTO error(id, message, fatal, indexed, translation_unit) "
"VALUES(?, ?, ?, ?, ?);"
);
m_insertOrUpdateMetaValueStmt = compileStatement(
"INSERT OR REPLACE INTO meta(id, key, value) VALUES("
"(SELECT id FROM meta WHERE key = ?), ?, ?"
");"
);
}
void DatabaseStorage::clearPrecompiledStatements()
{
m_insertElementStatement.finalize();
m_findNodeStatement.finalize();
m_insertNodeStatement.finalize();
m_setNodeTypeStmt.finalize();
m_insertSymbolStatement.finalize();
m_findFileStatement.finalize();
m_insertFileStatement.finalize();
m_setFileLanguageStmt.finalize();
m_insertFileContentStatement.finalize();
m_findEdgeStatement.finalize();
m_insertEdgeStatement.finalize();
m_findLocalSymbolStmt.finalize();
m_insertLocalSymbolStmt.finalize();
m_findSourceLocationStmt.finalize();
m_insertSourceLocationStmt.finalize();
m_insertOccurenceStmt.finalize();
m_findErrorStatement.finalize();
m_insertErrorStatement.finalize();
m_insertOrUpdateMetaValueStmt.finalize();
}
int DatabaseStorage::insertElement()
{
executeStatement(m_insertElementStatement);
int id = m_database.lastRowId();
m_insertElementStatement.reset();
return id;
}
void DatabaseStorage::insertOrUpdateMetaValue(const std::string& key, const std::string& value)
{
m_insertOrUpdateMetaValueStmt.bind(1, key.c_str());
m_insertOrUpdateMetaValueStmt.bind(2, key.c_str());
m_insertOrUpdateMetaValueStmt.bind(3, value.c_str());
executeStatement(m_insertOrUpdateMetaValueStmt);
m_insertOrUpdateMetaValueStmt.reset();
}
CppSQLite3Statement DatabaseStorage::compileStatement(const std::string& statement) const
{
try
{
return m_database.compileStatement(statement.c_str());
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to compile statement \"" + statement + "\" with message \"" + e.errorMessage() + "\".");
}
return CppSQLite3Statement();
}
void DatabaseStorage::executeStatement(const std::string& statement) const
{
try
{
m_database.execDML(statement.c_str());
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute statement \"" + statement + "\" with message \"" + e.errorMessage() + "\".");
}
}
void DatabaseStorage::executeStatement(CppSQLite3Statement& statement) const
{
try
{
statement.execDML();
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute statement with message \"" + std::string(e.errorMessage()) + "\".");
}
}
CppSQLite3Query DatabaseStorage::executeQuery(const std::string& query) const
{
try
{
return m_database.execQuery(query.c_str());
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute query \"" + query + "\" with message \"" + e.errorMessage() + "\".");
}
}
CppSQLite3Query DatabaseStorage::executeQuery(CppSQLite3Statement& statement) const
{
try
{
return statement.execQuery();
}
catch (CppSQLite3Exception e)
{
throw SourcetrailException("Failed to execute query with message \"" + std::string(e.errorMessage()) + "\".");
}
}
template <>
std::vector<StorageEdge> DatabaseStorage::doGetAll<StorageEdge>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, type, source_node_id, target_node_id FROM edge " + query + ";"
);
std::vector<StorageEdge> edges;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int edgeKind = q.getIntField(1, -1);
const int sourceId = q.getIntField(2, 0);
const int targetId = q.getIntField(3, 0);
if (id != 0 && edgeKind != -1)
{
edges.emplace_back(StorageEdge(id, sourceId, targetId, edgeKind));
}
q.nextRow();
}
return edges;
}
template <>
std::vector<StorageNode> DatabaseStorage::doGetAll<StorageNode>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, type, serialized_name FROM node " + query + ";"
);
std::vector<StorageNode> nodes;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int type = q.getIntField(1, -1);
const std::string serializedName = q.getStringField(2, "");
if (id != 0 && type != -1)
{
nodes.emplace_back(StorageNode(id, type, serializedName));
}
q.nextRow();
}
return nodes;
}
template <>
std::vector<StorageSymbol> DatabaseStorage::doGetAll<StorageSymbol>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, definition_kind FROM symbol " + query + ";"
);
std::vector<StorageSymbol> symbols;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int definitionKind = q.getIntField(1, 0);
if (id != 0)
{
symbols.emplace_back(StorageSymbol(id, definitionKind));
}
q.nextRow();
}
return symbols;
}
template <>
std::vector<StorageFile> DatabaseStorage::doGetAll<StorageFile>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, path, language, modification_time, indexed, complete FROM file " + query + ";"
);
std::vector<StorageFile> files;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const std::string filePath = q.getStringField(1, "");
const std::string languageIdentifier = q.getStringField(2, "");
const std::string modificationTime = q.getStringField(3, "");
const bool indexed = q.getIntField(4, 0);
const bool complete = q.getIntField(5, 0);
if (id != 0)
{
files.emplace_back(StorageFile(id, filePath, languageIdentifier, modificationTime, indexed, complete));
}
q.nextRow();
}
return files;
}
template <>
std::vector<StorageLocalSymbol> DatabaseStorage::doGetAll<StorageLocalSymbol>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, name FROM local_symbol " + query + ";"
);
std::vector<StorageLocalSymbol> localSymbols;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const std::string name = q.getStringField(1, "");
if (id != 0)
{
localSymbols.emplace_back(StorageLocalSymbol(id, name));
}
q.nextRow();
}
return localSymbols;
}
template <>
std::vector<StorageSourceLocation> DatabaseStorage::doGetAll<StorageSourceLocation>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, file_node_id, start_line, start_column, end_line, end_column, type FROM source_location " + query + ";"
);
std::vector<StorageSourceLocation> sourceLocations;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const int fileNodeId = q.getIntField(1, 0);
const int startLineNumber = q.getIntField(2, -1);
const int startColNumber = q.getIntField(3, -1);
const int endLineNumber = q.getIntField(4, -1);
const int endColNumber = q.getIntField(5, -1);
const int locationKind = q.getIntField(6, -1);
if (id != 0 && fileNodeId != 0 && startLineNumber != -1 && startColNumber != -1 && endLineNumber != -1 &&
endColNumber != -1 && locationKind != -1)
{
sourceLocations.emplace_back(StorageSourceLocation(id, fileNodeId, startLineNumber, startColNumber, endLineNumber, endColNumber, locationKind));
}
q.nextRow();
}
return sourceLocations;
}
template <>
std::vector<StorageOccurrence> DatabaseStorage::doGetAll<StorageOccurrence>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT element_id, source_location_id FROM occurrence " + query + ";"
);
std::vector<StorageOccurrence> occurrences;
while (!q.eof())
{
const int elementId = q.getIntField(0, 0);
const int sourceLocationId = q.getIntField(1, 0);
if (elementId != 0 && sourceLocationId != 0)
{
occurrences.emplace_back(StorageOccurrence(elementId, sourceLocationId));
}
q.nextRow();
}
return occurrences;
}
template <>
std::vector<StorageError> DatabaseStorage::doGetAll<StorageError>(const std::string& query) const
{
CppSQLite3Query q = executeQuery(
"SELECT id, message, fatal, indexed, translation_unit FROM error " + query + ";"
);
std::vector<StorageError> errors;
while (!q.eof())
{
const int id = q.getIntField(0, 0);
const std::string message = q.getStringField(1, "");
const bool fatal = q.getIntField(2, 0);
const bool indexed = q.getIntField(3, 0);
const std::string translationUnit = q.getStringField(4, "");
if (id != 0)
{
errors.emplace_back(StorageError(id, message, translationUnit, fatal, indexed));
}
q.nextRow();
}
return errors;
}
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "DefinitionKind.h"
namespace sourcetrail
{
int definitionKindToInt(DefinitionKind kind)
{
return static_cast<int>(kind);
}
DefinitionKind intToDefinitionKind(int i)
{
const DefinitionKind kinds[] = { DefinitionKind::IMPLICIT, DefinitionKind::EXPLICIT };
for (DefinitionKind kind : kinds)
{
if (i == definitionKindToInt(kind))
{
return kind;
}
}
return DefinitionKind::EXPLICIT;
}
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "EdgeKind.h"
#include "ReferenceKind.h"
namespace sourcetrail
{
int edgeKindToInt(EdgeKind kind)
{
return static_cast<int>(kind);
}
EdgeKind intToEdgeKind(int i)
{
const EdgeKind kinds[] = {
EdgeKind::MEMBER,
EdgeKind::TYPE_USAGE,
EdgeKind::USAGE,
EdgeKind::CALL,
EdgeKind::INHERITANCE,
EdgeKind::OVERRIDE,
EdgeKind::TEMPLATE_ARGUMENT,
EdgeKind::TYPE_ARGUMENT,
EdgeKind::TEMPLATE_DEFAULT_ARGUMENT,
EdgeKind::TEMPLATE_SPECIALIZATION,
EdgeKind::TEMPLATE_MEMBER_SPECIALIZATION,
EdgeKind::INCLUDE,
EdgeKind::IMPORT,
EdgeKind::AGGREGATION,
EdgeKind::MACRO_USAGE
};
for (EdgeKind kind : kinds)
{
if (i == edgeKindToInt(kind))
{
return kind;
}
}
return EdgeKind::UNKNOWN;
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LocationKind.h"
#include "SourcetrailException.h"
namespace sourcetrail
{
int locationKindToInt(LocationKind kind)
{
return static_cast<int>(kind);
}
LocationKind intToLocationKind(int i)
{
const LocationKind kinds[] = {
LocationKind::TOKEN,
LocationKind::SCOPE,
LocationKind::QUALIFIER,
LocationKind::LOCAL_SYMBOL,
LocationKind::SIGNATURE,
LocationKind::ATOMIC_RANGE,
LocationKind::INDEXER_ERROR,
LocationKind::FULLTEXT_SEARCH,
LocationKind::SCREEN_SEARCH
};
for (LocationKind kind : kinds)
{
if (i == locationKindToInt(kind))
{
return kind;
}
}
throw SourcetrailException("Unable to convert integer \"" + std::to_string(i) + "\" to location kind.");
}
}
+130
View File
@@ -0,0 +1,130 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NameHierarchy.h"
#include "json.hpp"
namespace sourcetrail
{
std::string serializeNameHierarchyToJson(const NameHierarchy& nameHierarchy)
{
typedef nlohmann::json json;
nlohmann::json j;
j["name_delimiter"] = nameHierarchy.nameDelimiter;
for (const NameElement& nameElement : nameHierarchy.nameElements)
{
j["name_elements"].push_back(
{
{ "prefix", nameElement.prefix } ,
{ "name", nameElement.name } ,
{ "postfix", nameElement.postfix }
});
}
return j.dump(4);
}
NameHierarchy deserializeNameHierarchyFromJson(const std::string& serializedNameHierarchy, std::string* error)
{
typedef nlohmann::json json;
NameHierarchy nameHierarchy;
try
{
json j = nlohmann::json::parse(serializedNameHierarchy);
{
json jDelimiter = j["name_delimiter"];
if (jDelimiter.is_string())
{
nameHierarchy.nameDelimiter = jDelimiter.get<std::string>();
}
}
{
json jNameElements = j["name_elements"];
if (jNameElements.is_array())
{
for (json::iterator it = jNameElements.begin(); it != jNameElements.end(); ++it)
{
NameElement nameElement;
{
json jPrefix = it.value()["prefix"];
if (jPrefix.is_string())
{
nameElement.prefix = jPrefix.get<std::string>();
}
}
{
json jName = it.value()["name"];
if (jName.is_string())
{
nameElement.name = jName.get<std::string>();
}
}
{
json jPostfix = it.value()["postfix"];
if (jPostfix.is_string())
{
nameElement.postfix = jPostfix.get<std::string>();
}
}
nameHierarchy.nameElements.push_back(nameElement);
}
}
}
}
catch (json::exception& e)
{
if (error)
{
*error = e.what();
}
}
catch (...)
{
if (error)
{
*error = "Exception thrown during NameHierarchy deserialization";
}
}
return nameHierarchy;
}
std::string serializeNameHierarchyToDatabaseString(const NameHierarchy& nameHierarchy)
{
static std::string META_DELIMITER = "\tm";
static std::string NAME_DELIMITER = "\tn";
static std::string PARTS_DELIMITER = "\ts";
static std::string SIGNATURE_DELIMITER = "\tp";
std::string serialized = nameHierarchy.nameDelimiter + META_DELIMITER;
for (size_t i = 0; i < nameHierarchy.nameElements.size(); i++)
{
if (i != 0)
{
serialized += NAME_DELIMITER;
}
const NameElement& nameElement = nameHierarchy.nameElements[i];
serialized += nameElement.name + PARTS_DELIMITER + nameElement.prefix + SIGNATURE_DELIMITER + nameElement.postfix;
}
return serialized;
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NodeKind.h"
namespace sourcetrail
{
int nodeKindToInt(NodeKind kind)
{
return static_cast<int>(kind);
}
NodeKind intToNodeKind(int i)
{
const NodeKind kinds[] = {
NodeKind::UNKNOWN,
NodeKind::TYPE,
NodeKind::BUILTIN_TYPE,
NodeKind::MODULE,
NodeKind::NAMESPACE,
NodeKind::PACKAGE,
NodeKind::STRUCT,
NodeKind::CLASS,
NodeKind::INTERFACE,
NodeKind::ANNOTATION,
NodeKind::GLOBAL_VARIABLE,
NodeKind::FIELD,
NodeKind::FUNCTION,
NodeKind::METHOD,
NodeKind::ENUM,
NodeKind::ENUM_CONSTANT,
NodeKind::TYPEDEF,
NodeKind::TEMPLATE_PARAMETER,
NodeKind::TYPE_PARAMETER,
NodeKind::FILE,
NodeKind::MACRO,
NodeKind::UNION
};
for (NodeKind kind : kinds)
{
if (i == nodeKindToInt(kind))
{
return kind;
}
}
return NodeKind::UNKNOWN;
}
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ReferenceKind.h"
#include "EdgeKind.h"
namespace sourcetrail
{
EdgeKind referenceKindToEdgeKind(ReferenceKind kind)
{
switch (kind)
{
case ReferenceKind::TYPE_USAGE:
return EdgeKind::TYPE_USAGE;
case ReferenceKind::USAGE:
return EdgeKind::USAGE;
case ReferenceKind::CALL:
return EdgeKind::CALL;
case ReferenceKind::INHERITANCE:
return EdgeKind::INHERITANCE;
case ReferenceKind::OVERRIDE:
return EdgeKind::OVERRIDE;
case ReferenceKind::TEMPLATE_ARGUMENT:
return EdgeKind::TEMPLATE_ARGUMENT;
case ReferenceKind::TYPE_ARGUMENT:
return EdgeKind::TYPE_ARGUMENT;
case ReferenceKind::TEMPLATE_DEFAULT_ARGUMENT:
return EdgeKind::TEMPLATE_DEFAULT_ARGUMENT;
case ReferenceKind::TEMPLATE_SPECIALIZATION:
return EdgeKind::TEMPLATE_SPECIALIZATION;
case ReferenceKind::TEMPLATE_MEMBER_SPECIALIZATION:
return EdgeKind::TEMPLATE_MEMBER_SPECIALIZATION;
case ReferenceKind::INCLUDE:
return EdgeKind::INCLUDE;
case ReferenceKind::IMPORT:
return EdgeKind::IMPORT;
case ReferenceKind::MACRO_USAGE:
return EdgeKind::MACRO_USAGE;
case ReferenceKind::ANNOTATION_USAGE:
return EdgeKind::ANNOTATION_USAGE;
}
return EdgeKind::UNKNOWN;
}
}
+788
View File
@@ -0,0 +1,788 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SourcetrailDBWriter.h"
#include <algorithm>
#include <fstream>
#include <vector>
#include "CppSQLite3.h"
#include "DatabaseStorage.h"
#include "DefinitionKind.h"
#include "EdgeKind.h"
#include "LocationKind.h"
#include "NameHierarchy.h"
#include "NodeKind.h"
#include "ReferenceKind.h"
#include "SourceRange.h"
#include "SourcetrailException.h"
#include "SymbolKind.h"
#include "utility.h"
#include "version.h"
namespace sourcetrail
{
// --- Public Interface ---
SourcetrailDBWriter::SourcetrailDBWriter()
: m_lastError("")
{
}
SourcetrailDBWriter::~SourcetrailDBWriter()
{
}
std::string SourcetrailDBWriter::getVersionString() const
{
return VERSION_STRING;
}
int SourcetrailDBWriter::getSupportedDatabaseVersion() const
{
return DatabaseStorage::getSupportedDatabaseVersion();
}
const std::string& SourcetrailDBWriter::getLastError() const
{
return m_lastError;
}
void SourcetrailDBWriter::setLastError(const std::string& error) const
{
m_lastError = error;
}
void SourcetrailDBWriter::clearLastError()
{
m_lastError.clear();
}
bool SourcetrailDBWriter::open(const std::string& databaseFilePath)
{
m_databaseFilePath = databaseFilePath;
m_projectFilePath = databaseFilePath; //FIXME: only find dot after last slash/backslash! otherwise it may be part of the file path
const size_t pos = m_projectFilePath.rfind('.');
if (pos != std::string::npos)
{
m_projectFilePath = m_projectFilePath.substr(0, pos);
}
m_projectFilePath += ".srctrlprj";
{
bool projectFileExists = false;
{
std::ifstream f(m_projectFilePath.c_str());
projectFileExists = f.good();
f.close();
}
if (!projectFileExists)
{
try
{
createOrResetProjectFile();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
}
try
{
openDatabase();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
try
{
setupDatabaseTables();
updateProjectSettingsText();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::close()
{
try
{
closeDatabase();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::clear()
{
try
{
clearDatabaseTables();
updateProjectSettingsText();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::isEmpty() const
{
if (!m_storage)
{
m_lastError = "Unable to check if database is empty, because no database is currently open.";
return true;
}
try
{
return m_storage->isEmpty();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return true;
}
}
bool SourcetrailDBWriter::isCompatible() const
{
if (!m_storage)
{
m_lastError = "Unable to check if database is compatible, because no database is currently open.";
return false;
}
try
{
return m_storage->isCompatible();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::getLoadedDatabaseVersion() const
{
if (!m_storage)
{
m_lastError = "Unable to fetch database version, because no database is currently open.";
return false;
}
try
{
return m_storage->getLoadedDatabaseVersion();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::beginTransaction()
{
if (!m_storage)
{
m_lastError = "Unable to begin transaction, because no database is currently open.";
return false;
}
try
{
m_storage->beginTransaction();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::commitTransaction()
{
if (!m_storage)
{
m_lastError = "Unable to commit transaction, because no database is currently open.";
return false;
}
try
{
m_storage->commitTransaction();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::rollbackTransaction()
{
if (!m_storage)
{
m_lastError = "Unable to rollback transaction, because no database is currently open.";
return false;
}
try
{
m_storage->rollbackTransaction();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::optimizeDatabaseMemory()
{
if (!m_storage)
{
m_lastError = "Unable to optimize database memory, because no database is currently open.";
return false;
}
try
{
m_storage->optimizeDatabaseMemory();
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
int SourcetrailDBWriter::recordSymbol(const NameHierarchy& nameHierarchy)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol, because no database is currently open.";
return false;
}
try
{
return addNodeHierarchy(nameHierarchy);
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordSymbolDefinitionKind(int symbolId, DefinitionKind definitionKind)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol kind, because no database is currently open.";
return false;
}
try
{
m_storage->addSymbol(StorageSymbol(symbolId, definitionKindToInt(definitionKind)));
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::recordSymbolKind(int symbolId, SymbolKind symbolKind)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol kind, because no database is currently open.";
return false;
}
try
{
m_storage->setNodeType(symbolId, nodeKindToInt(symbolKindToNodeKind(symbolKind)));
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
bool SourcetrailDBWriter::recordSymbolLocation(int symbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(symbolId, location, LocationKind::TOKEN);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordSymbolScopeLocation(int symbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol scope location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(symbolId, location, LocationKind::SCOPE);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordSymbolSignatureLocation(int symbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol signature location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(symbolId, location, LocationKind::SIGNATURE);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::recordReference(int contextSymbolId, int referencedSymbolId, ReferenceKind referenceKind)
{
if (!m_storage)
{
m_lastError = "Unable to record reference, because no database is currently open.";
return false;
}
try
{
return addEdge(contextSymbolId, referencedSymbolId, referenceKindToEdgeKind(referenceKind));
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordReferenceLocation(int referenceId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol reference location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(referenceId, location, LocationKind::TOKEN);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordQualifierLocation(int referencedSymbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol qualifier location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(referencedSymbolId, location, LocationKind::QUALIFIER);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::recordFile(const std::string& filePath)
{
if (!m_storage)
{
m_lastError = "Unable to record file, because no database is currently open.";
return false;
}
try
{
return addFile(filePath);
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordFileLanguage(int fileId, const std::string& languageIdentifier)
{
if (!m_storage)
{
m_lastError = "Unable to record file language, because no database is currently open.";
return false;
}
try
{
m_storage->setFileLanguage(fileId, languageIdentifier);
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
return true;
}
int SourcetrailDBWriter::recordLocalSymbol(const std::string& name)
{
if (!m_storage)
{
m_lastError = "Unable to record local symbol, because no database is currently open.";
return false;
}
try
{
return m_storage->addLocalSymbol(StorageLocalSymbolData(name));
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordLocalSymbolLocation(int localSymbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record local symbol location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(localSymbolId, location, LocationKind::LOCAL_SYMBOL);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordAtomicSourceRange(const SourceRange& sourceRange)
{
if (!m_storage)
{
m_lastError = "Unable to record atomic source range, because no database is currently open.";
return false;
}
try
{
const int sourceLocationId = m_storage->addSourceLocation(StorageSourceLocationData(
sourceRange.fileId,
sourceRange.startLine,
sourceRange.startColumn,
sourceRange.endLine,
sourceRange.endColumn,
locationKindToInt(LocationKind::ATOMIC_RANGE)
));
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
bool SourcetrailDBWriter::recordError(const std::string& message, bool fatal, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record error, because no database is currently open.";
return false;
}
try
{
const int errorId = m_storage->addError(StorageErrorData(message, "", fatal, true));
addSourceLocation(errorId, location, LocationKind::INDEXER_ERROR);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
// --- Private Interface ---
void SourcetrailDBWriter::openDatabase()
{
if (m_storage)
{
closeDatabase();
}
try
{
m_storage = DatabaseStorage::openDatabase(m_databaseFilePath);
}
catch (CppSQLite3Exception e)
{
m_storage.reset();
throw e;
}
}
void SourcetrailDBWriter::closeDatabase()
{
if (!m_storage)
{
throw SourcetrailException("Unable to close database, because no database is currently open.");
}
m_storage.reset();
}
void SourcetrailDBWriter::setupDatabaseTables()
{
if (!m_storage)
{
throw SourcetrailException("Unable to setup database tables, because no database is currently open.");
}
m_storage->setupDatabase();
}
void SourcetrailDBWriter::clearDatabaseTables()
{
if (!m_storage)
{
throw SourcetrailException("Unable to setup database tables, because no database is currently open.");
}
m_storage->clearDatabase();
}
void SourcetrailDBWriter::createOrResetProjectFile()
{
try
{
std::ofstream fileStream;
fileStream.open(m_projectFilePath, std::ios::out);
fileStream << std::string(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <version>0</version>\n"
"</config>\n"
);
fileStream.close();
}
catch (...)
{
throw SourcetrailException("Exception occurred while creating project file.");
}
}
void SourcetrailDBWriter::updateProjectSettingsText()
{
try
{
std::ifstream f(m_projectFilePath.c_str());
if (f.is_open())
{
std::string line;
std::string text;
while (getline(f, line))
{
text += line + '\n';
}
f.close();
m_storage->setProjectSettingsText(text);
}
else
{
throw SourcetrailException("Unable to open project file.");
}
}
catch (...)
{
throw SourcetrailException("Exception occurred while creating project file.");
}
}
int SourcetrailDBWriter::addNodeHierarchy(const NameHierarchy& nameHierarchy)
{
if (nameHierarchy.nameElements.size() == 0)
{
throw SourcetrailException("Unable to add nodes for an empty name hierarchy.");
}
int parentNodeId = 0;
NameHierarchy currentNameHierarchy;
currentNameHierarchy.nameDelimiter = nameHierarchy.nameDelimiter;
for (size_t i = 0; i < nameHierarchy.nameElements.size(); i++)
{
currentNameHierarchy.nameElements.push_back(nameHierarchy.nameElements[i]);
int nodeId = m_storage->addNode(StorageNodeData(
nodeKindToInt(NodeKind::UNKNOWN),
serializeNameHierarchyToDatabaseString(currentNameHierarchy)
));
if (parentNodeId != 0)
{
addEdge(parentNodeId, nodeId, EdgeKind::MEMBER);
}
parentNodeId = nodeId;
}
return parentNodeId;
}
int SourcetrailDBWriter::addFile(const std::string& filePath)
{
NameElement nameElement;
nameElement.name = filePath;
NameHierarchy nameHierarchy;
nameHierarchy.nameDelimiter = "/";
nameHierarchy.nameElements.push_back(nameElement);
const int nodeId = addNodeHierarchy(nameHierarchy);
m_storage->setNodeType(nodeId, nodeKindToInt(NodeKind::FILE));
m_storage->addFile(StorageFile(nodeId, filePath, "", utility::getDateTimeString(time(0)), true, true));
return nodeId;
}
int SourcetrailDBWriter::addEdge(int sourceId, int targetId, EdgeKind edgeKind)
{
if (!m_storage)
{
throw SourcetrailException("Unable to add edge, because no database is currently open.");
}
if (!sourceId)
{
throw SourcetrailException("Unable to add edge, because source id is invalid.");
}
if (!targetId)
{
throw SourcetrailException("Unable to add edge, because target id is invalid.");
}
return m_storage->addEdge(StorageEdgeData(sourceId, targetId, edgeKindToInt(edgeKind)));
}
void SourcetrailDBWriter::addSourceLocation(int elementId, const SourceRange& location, LocationKind kind)
{
const int sourceLocationId = m_storage->addSourceLocation(StorageSourceLocationData(
location.fileId,
location.startLine,
location.startColumn,
location.endLine,
location.endColumn,
locationKindToInt(kind)
));
m_storage->addOccurrence(StorageOccurrence(
elementId,
sourceLocationId
));
}
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SymbolKind.h"
#include "NodeKind.h"
namespace sourcetrail
{
NodeKind symbolKindToNodeKind(SymbolKind kind)
{
switch (kind)
{
case SymbolKind::TYPE:
return NodeKind::TYPE;
case SymbolKind::BUILTIN_TYPE:
return NodeKind::BUILTIN_TYPE;
case SymbolKind::MODULE:
return NodeKind::MODULE;
case SymbolKind::NAMESPACE:
return NodeKind::NAMESPACE;
case SymbolKind::PACKAGE:
return NodeKind::PACKAGE;
case SymbolKind::STRUCT:
return NodeKind::STRUCT;
case SymbolKind::CLASS:
return NodeKind::CLASS;
case SymbolKind::INTERFACE:
return NodeKind::INTERFACE;
case SymbolKind::ANNOTATION:
return NodeKind::ANNOTATION;
case SymbolKind::GLOBAL_VARIABLE:
return NodeKind::GLOBAL_VARIABLE;
case SymbolKind::FIELD:
return NodeKind::FIELD;
case SymbolKind::FUNCTION:
return NodeKind::FUNCTION;
case SymbolKind::METHOD:
return NodeKind::METHOD;
case SymbolKind::ENUM:
return NodeKind::ENUM;
case SymbolKind::ENUM_CONSTANT:
return NodeKind::ENUM_CONSTANT;
case SymbolKind::TYPEDEF:
return NodeKind::TYPEDEF;
case SymbolKind::TEMPLATE_PARAMETER:
return NodeKind::TEMPLATE_PARAMETER;
case SymbolKind::TYPE_PARAMETER:
return NodeKind::TYPE_PARAMETER;
case SymbolKind::MACRO:
return NodeKind::MACRO;
case SymbolKind::UNION:
return NodeKind::UNION;
}
return NodeKind::UNKNOWN;
}
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utility.h"
#include <algorithm>
#include <ctime>
#include <fstream>
#include "SourcetrailException.h"
namespace sourcetrail
{
namespace utility
{
bool getFileExists(const std::string& filePath)
{
std::ifstream file(filePath);
return file.good();
}
std::string getFileContent(const std::string& filePath)
{
std::string content;
std::ifstream file;
file.open(filePath);
if (file.fail())
{
throw SourcetrailException("Could not open file " + filePath);
}
for (std::string line; std::getline(file, line); )
{
content += line + "\n";
}
file.close();
return content;
}
std::string getDateTimeString(const time_t& time)
{
std::tm* ptm = std::localtime(&time);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", ptm);
return buffer;
}
int getLineCount(const std::string s)
{
return std::count(s.begin(), s.end(), '\n');
}
}
}
+602
View File
@@ -0,0 +1,602 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() function
#include "catch.hpp"
#include "DatabaseStorage.h"
#include "NodeKind.h"
#include "SourcetrailDBWriter.h"
namespace sourcetrail
{
TEST_CASE("Testing SourcetrailDBWriter performs general operations")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
SECTION("writer is compatible after clearing")
{
REQUIRE(writer.isCompatible());
}
SECTION("writer is empty after clearing")
{
REQUIRE(writer.isEmpty());
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records nodes")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const NameHierarchy nameSymbol1({ "." ,{ { "void", "foo", "()" } } });
const int idSymbol1 = writer.recordSymbol(nameSymbol1);
REQUIRE(idSymbol1 != 0);
REQUIRE(writer.getLastError() == "");
SECTION("database contains node after recording simple symbol")
{
const std::vector<StorageNode> nodes = storage->getAll<StorageNode>();
REQUIRE(nodes.size() == 1);
REQUIRE(nodes.front().id == idSymbol1);
REQUIRE(nodes.front().serializedName == serializeNameHierarchyToDatabaseString(nameSymbol1));
REQUIRE(nodes.front().nodeKind == nodeKindToInt(NodeKind::UNKNOWN));
}
SECTION("writer does not record node for symbol twice")
{
const int secondIdSymbol1 = writer.recordSymbol(nameSymbol1);
REQUIRE(secondIdSymbol1 == idSymbol1);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageNode> nodes = storage->getAll<StorageNode>();
REQUIRE(nodes.size() == 1);
}
SECTION("writer records \"explicit\" symbol definition kind")
{
const bool success = writer.recordSymbolDefinitionKind(idSymbol1, DefinitionKind::EXPLICIT);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageSymbol> symbols = storage->getAll<StorageSymbol>();
REQUIRE(symbols.size() == 1);
REQUIRE(symbols.front().definitionKind == definitionKindToInt(DefinitionKind::EXPLICIT));
}
SECTION("writer records \"class\" symbol kind")
{
const bool success = writer.recordSymbolKind(idSymbol1, SymbolKind::CLASS);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageNode> nodes = storage->getAll<StorageNode>();
REQUIRE(nodes.size() == 1);
REQUIRE(nodes.front().nodeKind == nodeKindToInt(NodeKind::CLASS));
}
SECTION("writer records symbol locations")
{
const std::string filePath = "path/to/non_existing_file.cpp";
const int fileId = writer.recordFile(filePath);
const int startLine = 1;
const int startCol = 2;
const int endLine = 3;
const int endCol = 4;
std::vector<StorageSourceLocation> sourceLocations;
SECTION("writer records symbol token location")
{
const bool success = writer.recordSymbolLocation(
idSymbol1,
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::TOKEN));
}
SECTION("writer records symbol scope location")
{
const bool success = writer.recordSymbolScopeLocation(
idSymbol1,
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::SCOPE));
}
SECTION("writer records symbol signature location")
{
const bool success = writer.recordSymbolSignatureLocation(
idSymbol1,
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::SIGNATURE));
}
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
REQUIRE(sourceLocations.front().endColumnNumber == endCol);
const std::vector<StorageOccurrence> occurrences = storage->getAll<StorageOccurrence>();
REQUIRE(occurrences.size() == 1);
REQUIRE(occurrences.front().elementId == idSymbol1);
REQUIRE(occurrences.front().sourceLocationId == sourceLocations.front().id);
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records edges")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const NameHierarchy nameSymbol1({ "." ,{ { "void", "foo", "()" } } });
const int idSymbol1 = writer.recordSymbol(nameSymbol1);
REQUIRE(idSymbol1 != 0);
REQUIRE(writer.getLastError() == "");
const NameHierarchy nameSymbol2({ "." ,{ { "void", "bar", "()" } } });
const int idSymbol2 = writer.recordSymbol(nameSymbol2);
REQUIRE(idSymbol2 != 0);
REQUIRE(writer.getLastError() == "");
const ReferenceKind kindReference1 = ReferenceKind::CALL;
const int idReference1 = writer.recordReference(idSymbol1, idSymbol2, kindReference1);
REQUIRE(idReference1 != 0);
REQUIRE(writer.getLastError() == "");
SECTION("database contains edge after recording simple reference")
{
const std::vector<StorageEdge> edges = storage->getAll<StorageEdge>();
REQUIRE(edges.size() == 1);
REQUIRE(edges.front().id == idReference1);
REQUIRE(edges.front().sourceNodeId == idSymbol1);
REQUIRE(edges.front().targetNodeId == idSymbol2);
REQUIRE(edges.front().edgeKind == edgeKindToInt(referenceKindToEdgeKind(kindReference1)));
}
SECTION("writer does not record edge for reference twice")
{
const int secondIdReference1 = writer.recordReference(idSymbol1, idSymbol2, ReferenceKind::CALL);
REQUIRE(secondIdReference1 == idReference1);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageEdge> edges = storage->getAll<StorageEdge>();
REQUIRE(edges.size() == 1);
}
SECTION("writer records reference location")
{
const std::string filePath = "path/to/non_existing_file.cpp";
const int fileId = writer.recordFile(filePath);
const int startLine = 1;
const int startCol = 2;
const int endLine = 3;
const int endCol = 4;
const bool success = writer.recordReferenceLocation(
idReference1,
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::TOKEN));
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
REQUIRE(sourceLocations.front().endColumnNumber == endCol);
const std::vector<StorageOccurrence> occurrences = storage->getAll<StorageOccurrence>();
REQUIRE(occurrences.size() == 1);
REQUIRE(occurrences.front().elementId == idReference1);
REQUIRE(occurrences.front().sourceLocationId == sourceLocations.front().id);
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records qualifier locations")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const NameHierarchy nameSymbol1({ "." ,{ { "", "Foo", "" } } });
const int idSymbol1 = writer.recordSymbol(nameSymbol1);
REQUIRE(idSymbol1 != 0);
REQUIRE(writer.getLastError() == "");
const std::string filePath = "path/to/non_existing_file.cpp";
const int fileId = writer.recordFile(filePath);
const int startLine = 1;
const int startCol = 2;
const int endLine = 3;
const int endCol = 4;
const bool success = writer.recordQualifierLocation(idSymbol1, { fileId, startLine, startCol, endLine, endCol });
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
SECTION("database contains qualifier location after recording qualifier location")
{
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::QUALIFIER));
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
REQUIRE(sourceLocations.front().endColumnNumber == endCol);
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records file")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const std::string filePath = "path/to/non_existing_file.cpp";
const int idFile1 = writer.recordFile(filePath);
REQUIRE(idFile1 != 0);
REQUIRE(writer.getLastError() == "");
SECTION("database contains file after recording file")
{
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().id == idFile1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(files.front().languageIdentifier == "");
}
SECTION("writer does not record file twice")
{
const int secondIdFile1 = writer.recordFile(filePath);
REQUIRE(secondIdFile1 == idFile1);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
}
SECTION("writer records file language")
{
const std::string languageIdentifier = "testlanguage";
const bool success = writer.recordFileLanguage(
idFile1,
languageIdentifier
);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().id == idFile1);
REQUIRE(files.front().languageIdentifier == languageIdentifier);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records local symbols")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const std::string localSymbolName1 = "foo";
const int idLocalSymbol1 = writer.recordLocalSymbol(localSymbolName1);
REQUIRE(idLocalSymbol1 != 0);
REQUIRE(writer.getLastError() == "");
SECTION("database contains local symbol after recording local symbol")
{
const std::vector<StorageLocalSymbol> localSymbols = storage->getAll<StorageLocalSymbol>();
REQUIRE(localSymbols.size() == 1);
REQUIRE(localSymbols.front().id == idLocalSymbol1);
REQUIRE(localSymbols.front().name == localSymbolName1);
}
SECTION("writer does not record local symbol twice")
{
const int secondIdLocalSymbol1 = writer.recordLocalSymbol(localSymbolName1);
REQUIRE(secondIdLocalSymbol1 == idLocalSymbol1);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageLocalSymbol> localSymbols = storage->getAll<StorageLocalSymbol>();
REQUIRE(localSymbols.size() == 1);
}
SECTION("writer records local symbol location")
{
const std::string filePath = "path/to/non_existing_file.cpp";
const int fileId = writer.recordFile(filePath);
const int startLine = 1;
const int startCol = 2;
const int endLine = 3;
const int endCol = 4;
const bool success = writer.recordLocalSymbolLocation(
idLocalSymbol1,
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::LOCAL_SYMBOL));
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
REQUIRE(sourceLocations.front().endColumnNumber == endCol);
const std::vector<StorageOccurrence> occurrences = storage->getAll<StorageOccurrence>();
REQUIRE(occurrences.size() == 1);
REQUIRE(occurrences.front().elementId == idLocalSymbol1);
REQUIRE(occurrences.front().sourceLocationId == sourceLocations.front().id);
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records comment locations")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const std::string filePath = "path/to/non_existing_file.cpp";
const int fileId = writer.recordFile(filePath);
const int startLine = 1;
const int startCol = 2;
const int endLine = 3;
const int endCol = 4;
const bool success1 = writer.recordAtomicSourceRange(
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success1);
REQUIRE(writer.getLastError() == "");
SECTION("database contains comment location after recording local symbol")
{
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::ATOMIC_RANGE));
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
REQUIRE(sourceLocations.front().endColumnNumber == endCol);
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
SECTION("writer does not record atomic source range twice")
{
const bool success2 = writer.recordAtomicSourceRange(
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success2);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records errors")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const std::string message = "This is a very serious test error message.";
const bool fatal = false;
const std::string filePath = "path/to/non_existing_file.cpp";
const int fileId = writer.recordFile(filePath);
const int startLine = 1;
const int startCol = 2;
const int endLine = 3;
const int endCol = 4;
const bool success1 = writer.recordError(
message,
fatal,
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success1);
REQUIRE(writer.getLastError() == "");
SECTION("database contains error after recording error")
{
const std::vector<StorageError> errors = storage->getAll<StorageError>();
REQUIRE(errors.size() == 1);
REQUIRE(errors.front().message == message);
REQUIRE(errors.front().fatal == fatal);
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::INDEXER_ERROR));
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
REQUIRE(sourceLocations.front().endColumnNumber == endCol);
const std::vector<StorageOccurrence> occurrences = storage->getAll<StorageOccurrence>();
REQUIRE(occurrences.size() == 1);
REQUIRE(occurrences.front().elementId == errors.front().id);
REQUIRE(occurrences.front().sourceLocationId == sourceLocations.front().id);
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
SECTION("writer does not record error twice")
{
const bool success2 = writer.recordError(
message,
fatal,
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success2);
REQUIRE(writer.getLastError() == "");
const std::vector<StorageError> errors = storage->getAll<StorageError>();
REQUIRE(errors.size() == 1);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef SOURCETRAIL_VERSION_H
#define SOURCETRAIL_VERSION_H
// This file is (re-)generated when running CMake on this project.
#define INTERFACE_VERSION @INTERFACE_VERSION@
#define DATABASE_VERSION @DATABASE_VERSION@
#define PATCH_VERSION @PATCH_VERSION@
#define VERSION_STRING "@VERSION_STRING@"
#endif // SOURCETRAIL_VERSION_H
+35
View File
@@ -0,0 +1,35 @@
cmake_minimum_required (VERSION 2.6)
set(EXAMPLE_NAME "cpp_api_example")
# --- Configure Build ---
set(EXAMPLE_SRC_FILES
src/main.cpp
)
set(EXAMPLE_HDR_FILES
)
add_executable(${EXAMPLE_NAME} ${EXAMPLE_SRC_FILES} ${EXAMPLE_HDR_FILES})
target_include_directories(${EXAMPLE_NAME} PUBLIC
"${CORE_SOURCE_DIR}/include"
)
target_link_libraries(${EXAMPLE_NAME} ${LIB_CORE} "-ldl")
# --- Configure Sourcetrail Project File ---
add_custom_command(
TARGET ${EXAMPLE_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${EXAMPLE_NAME}> ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE_NAME}
)
set(API_EXAMPLE_DATA_PATH "${CMAKE_CURRENT_SOURCE_DIR}/data")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/${EXAMPLE_NAME}.srctrlprj.in"
"${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE_NAME}.srctrlprj"
)
+24
View File
@@ -0,0 +1,24 @@
## C++ API Example
### Requirements
* CMake
* C++ Compiler
### Building
* Run cmake with `BUILD_EXAMPLES=ON`
* Build target `cpp_api_example`
### Running from Command Line
Invoke binary located in the build directory:
```
$ cpp_api_example path/to/database_file.srctrldb path/to/examples/cpp_api_example/data/example.cpp
```
### Running with Sourcetrail
Open `cpp_api_example.srctrlprj` located in the build directory with Sourcetrail and index the project.
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<config>
<source_groups>
<source_group_78efd997-84bf-4db6-9736-f5ddd702053c>
<custom_command>./cpp_api_example %{DATABASE_FILE_PATH} %{SOURCE_FILE_PATH} %{DATABASE_VERSION}</custom_command>
<name>Custom Command Source Group</name>
<source_extensions>
<source_extension>.cpp</source_extension>
</source_extensions>
<source_paths>
<source_path>@API_EXAMPLE_DATA_PATH@/example.cpp</source_path>
</source_paths>
<status>enabled</status>
<type>Custom Command Source Group</type>
</source_group_78efd997-84bf-4db6-9736-f5ddd702053c>
</source_groups>
<version>7</version>
</config>
+24
View File
@@ -0,0 +1,24 @@
/*
* MyType
*
* This is a multiline comment
*/
namespace api
{
class MyType
: public BaseType
{
public:
void my_method(bool do_send_signal) const
{
if (do_send_signal)
{
Client::send_signal();
}
}
}
}
+165
View File
@@ -0,0 +1,165 @@
#include <cstdlib>
#include <fstream>
#include <iostream>
#include "SourcetrailDBWriter.h"
void findAndReplaceAll(std::string &data, const std::string &toSearch, const std::string &replaceStr)
{
size_t pos = data.find(toSearch);
while (pos != std::string::npos)
{
data.replace(pos, toSearch.size(), replaceStr);
pos = data.find(toSearch, pos + replaceStr.size());
}
}
int main(int argc, const char *argv[])
{
sourcetrail::SourcetrailDBWriter dbWriter;
std::cout << "\nSourcetrailDB C++ API Example" << std::endl;
std::cout << std::endl;
std::cout << "SourcetrailDB version: " << dbWriter.getVersionString() << std::endl;
std::cout << "Supported database version: " << dbWriter.getSupportedDatabaseVersion() << std::endl;
std::cout << std::endl;
if (argc < 3 || argc > 4)
{
std::cout << "usage: cpp_api_example <database_path> <source_path> <optional:database_version>";
}
std::string dbPath = argv[1];
std::string sourcePath = argv[2];
findAndReplaceAll(sourcePath, "\\", "/");
int dbVersion = 0;
if (argc == 4)
{
char* end;
dbVersion = strtol(argv[3], &end, 10);
}
if (dbVersion && dbVersion != dbWriter.getSupportedDatabaseVersion())
{
std::cerr << "error: binary only supports database version: " << dbWriter.getSupportedDatabaseVersion()
<< ". Requested version: " << dbVersion << std::endl;
return 1;
}
// open database by passing .srctrldb or .srctrldb_tmp path
std::cout << "Opening Database: " << dbPath << std::endl;
if (!dbWriter.open(dbPath))
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
std::cout << "Clearing Database... " << std::endl;
if (!dbWriter.clear())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
std::cout << "Starting Indexing..." << std::endl;
// start recording with faster speed
if (!dbWriter.beginTransaction())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
// record source file by passing it's absolute path
int fileId = dbWriter.recordFile(sourcePath);
dbWriter.recordFileLanguage(fileId, "cpp"); // record file language for syntax highlighting
// record atomic source range for multi line comment
dbWriter.recordAtomicSourceRange({ fileId, 2, 1, 6, 3 });
// record namespace "api"
sourcetrail::NameHierarchy namespaceName { "::", { { "", "api", "" } } };
int namespaceId = dbWriter.recordSymbol(namespaceName);
dbWriter.recordSymbolDefinitionKind(namespaceId, sourcetrail::DefinitionKind::EXPLICIT);
dbWriter.recordSymbolKind(namespaceId, sourcetrail::SymbolKind::NAMESPACE);
dbWriter.recordSymbolLocation(namespaceId, { fileId, 8, 11, 8, 13 });
dbWriter.recordSymbolScopeLocation(namespaceId, { fileId, 8, 1, 24, 1 });
// record class "MyType"
sourcetrail::NameHierarchy className = namespaceName;
className.nameElements.push_back( { "", "MyType", "" } );
int classId = dbWriter.recordSymbol(className);
dbWriter.recordSymbolDefinitionKind(classId, sourcetrail::DefinitionKind::EXPLICIT);
dbWriter.recordSymbolKind(classId, sourcetrail::SymbolKind::CLASS);
dbWriter.recordSymbolLocation(classId, { fileId, 11, 7, 11, 12 });
dbWriter.recordSymbolScopeLocation(classId, { fileId, 11, 1, 22, 1 }); // gets highlight when active
// record inheritance reference to "BaseType"
int baseId = dbWriter.recordSymbol( { "::", { { "", "BaseType", "" } } } );
int inheritanceId = dbWriter.recordReference(classId, baseId, sourcetrail::ReferenceKind::INHERITANCE);
dbWriter.recordReferenceLocation(inheritanceId, { fileId, 12, 14, 12, 21 });
// add child method "void my_method() const"
sourcetrail::NameHierarchy methodName = className;
methodName.nameElements.push_back( { "void", "my_method", "() const" } );
int methodId = dbWriter.recordSymbol(methodName);
dbWriter.recordSymbolDefinitionKind(methodId, sourcetrail::DefinitionKind::EXPLICIT);
dbWriter.recordSymbolKind(methodId, sourcetrail::SymbolKind::METHOD);
dbWriter.recordSymbolLocation(methodId, { fileId, 15, 10, 15, 18 });
dbWriter.recordSymbolScopeLocation(methodId, { fileId, 15, 5, 21, 5 }); // gets highlight when active
dbWriter.recordSymbolSignatureLocation(methodId, { fileId, 15, 5, 15, 45 }); // used in tooltip
// record usage of parameter type "bool"
int typeId = dbWriter.recordSymbol({ "::", { { "", "bool", "" } } });
int typeuseId = dbWriter.recordReference(methodId, typeId, sourcetrail::ReferenceKind::TYPE_USAGE);
dbWriter.recordReferenceLocation(typeuseId, { fileId, 15, 20, 15, 23 });
// record parameter "do_send_signal"
int localId = dbWriter.recordLocalSymbol("do_send_signal");
dbWriter.recordLocalSymbolLocation(localId, { fileId, 15, 25, 15, 38 });
dbWriter.recordLocalSymbolLocation(localId, { fileId, 17, 13, 17, 26 });
// record source range of "Client" as qualifier location
int qualifierId = dbWriter.recordSymbol({ "::",{ { "", "Client", "" } } });
dbWriter.recordQualifierLocation(qualifierId, { fileId, 19, 13, 19, 18 });
// record function call reference to "send_signal()"
int funcId = dbWriter.recordSymbol({ "::", { { "", "Client", "" }, { "", "send_signal", "()" } } });
dbWriter.recordSymbolKind(funcId, sourcetrail::SymbolKind::FUNCTION);
int callId = dbWriter.recordReference(methodId, funcId, sourcetrail::ReferenceKind::CALL);
dbWriter.recordReferenceLocation(callId, { fileId, 19, 21, 19, 31 });
// record error
dbWriter.recordError("Really? You missed that \";\" again? (intentional error)", false, { fileId, 22, 1, 22, 1 });
// end recording
if (!dbWriter.commitTransaction())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
// check for errors before finishing
if (dbWriter.getLastError().size())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
std::cout << "done!" << std::endl;
return 0;
}
@@ -0,0 +1,35 @@
cmake_minimum_required (VERSION 2.6)
set(EXAMPLE_NAME "poetry_indexer")
# --- Configure Build ---
set(EXAMPLE_SRC_FILES
src/main.cpp
)
set(EXAMPLE_HDR_FILES
)
add_executable(${EXAMPLE_NAME} ${EXAMPLE_SRC_FILES} ${EXAMPLE_HDR_FILES})
target_include_directories(${EXAMPLE_NAME} PUBLIC
"${CORE_SOURCE_DIR}/include"
)
target_link_libraries(${EXAMPLE_NAME} ${LIB_CORE} "-ldl")
# --- Configure Sourcetrail Project File ---
add_custom_command(
TARGET ${EXAMPLE_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${EXAMPLE_NAME}> ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE_NAME}
)
set(POETRY_INDEXER_DATA_PATH "${CMAKE_CURRENT_SOURCE_DIR}/data")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/${EXAMPLE_NAME}.srctrlprj.in"
"${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE_NAME}.srctrlprj"
)
+24
View File
@@ -0,0 +1,24 @@
## Poetry Indexer Example
### Requirements
* CMake
* C++ Compiler
### Building
* Run cmake with `BUILD_EXAMPLES=ON`
* Build target `poetry_indexer`
### Running from Command Line
Invoke binary located in the build directory:
```
$ poetry_indexer path/to/database_file.srctrldb path/to/examples/cpp_poetry_indexer/data/e_e_cummings_-_in_just-.txt
```
### Running with Sourcetrail
Open `poetry_indexer.srctrlprj` located in the build directory with Sourcetrail and index the project.
@@ -0,0 +1 @@
Licensed under "CCO: Public Domain" (https://creativecommons.org/publicdomain/zero/1.0/)
@@ -0,0 +1,30 @@
CHRISTOPHER MARLOWE
Elegies, Book One, 5
In summers heat and mid-time of the day
To rest my limbs upon a bed I lay,
One window shut, the other open stood,
Which gave such light as twinkles in a wood,
Like twilight glimpse at setting of the sun
Or night being past, and yet not day begun.
Such light to shamefaced maidens must be shown,
Where they may sport, and seem to be unknown.
Then came Corinna in a long loose gown,
Her white neck hid with tresses hanging down:
Resembling fair Semiramis going to bed
Or Lais of a thousand wooers sped.
I snatched her gown, being thin, the harm was small,
Yet strived she to be covered therewithal.
And striving thus as one that would be cast,
Betrayed herself, and yielded at the last.
Stark naked as she stood before mine eye,
Not one wen in her body could I spy.
What arms and shoulders did I touch and see,
How apt her breasts were to be pressed by me?
How smooth a belly under her waist saw I?
How large a leg, and what a lusty thigh?
To leave the rest, all liked me passing well,
I clinged her naked body, down she fell,
Judge you the rest: being tired she bad me kiss,
Jove send me more such afternoons as this.
@@ -0,0 +1,13 @@
CHRISTOPHER MARLOWE
from Hero and Leander: "It lies not in our power to love or hate"
It lies not in our power to love or hate,
For will in us is overruled by fate.
When two are stripped, long ere the course begin,
We wish that one should lose, the other win;
And one especially do we affect
Of two gold ingots, like in each respect:
The reason no man knows; let it suffice
What we behold is censured by our eyes.
Where both deliberate, the love is slight:
Who ever loved, that loved not at first sight?
@@ -0,0 +1,182 @@
CHRISTOPHER MARLOWE
Hero and Leander
On Hellespont, guilty of true love's blood,
In view and opposite two cities stood,
Sea-borderers, disjoin'd by Neptune's might;
The one Abydos, the other Sestos hight.
At Sestos Hero dwelt; Hero the fair,
Whom young Apollo courted for her hair,
And offer'd as a dower his burning throne,
Where she could sit for men to gaze upon.
The outside of her garments were of lawn,
The lining purple silk, with gilt stars drawn;
Her wide sleeves green, and border'd with a grove,
Where Venus in her naked glory strove
To please the careless and disdainful eyes
Of proud Adonis, that before her lies;
Her kirtle blue, whereon was many a stain,
Made with the blood of wretched lovers slain.
Upon her head she ware a myrtle wreath,
From whence her veil reach'd to the ground beneath;
Her veil was artificial flowers and leaves,
Whose workmanship both man and beast deceives;
Many would praise the sweet smell as she past,
When 'twas the odour which her breath forth cast;
And there for honey bees have sought in vain,
And beat from thence, have lighted there again.
About her neck hung chains of pebble-stone,
Which lighten'd by her neck, like diamonds shone.
She ware no gloves; for neither sun nor wind
Would burn or parch her hands, but, to her mind,
Or warm or cool them, for they took delight
To play upon those hands, they were so white.
Buskins of shells, all silver'd, used she,
And branch'd with blushing coral to the knee;
Where sparrows perch'd, of hollow pearl and gold,
Such as the world would wonder to behold:
Those with sweet water oft her handmaid fills,
Which as she went, would chirrup through the bills.
Some say, for her the fairest Cupid pin'd,
And looking in her face, was strooken blind.
But this is true; so like was one the other,
As he imagin'd Hero was his mother;
And oftentimes into her bosom flew,
About her naked neck his bare arms threw,
And laid his childish head upon her breast,
And with still panting rock'd there took his rest.
So lovely-fair was Hero, Venus' nun,
As Nature wept, thinking she was undone,
Because she took more from her than she left,
And of such wondrous beauty her bereft:
Therefore, in sign her treasure suffer'd wrack,
Since Hero's time hath half the world been black.
Amorous Leander, beautiful and young
(Whose tragedy divine Musus sung),
Dwelt at Abydos; since him dwelt there none
For whom succeeding times make greater moan.
His dangling tresses, that were never shorn,
Had they been cut, and unto Colchos borne,
Would have allur'd the vent'rous youth of Greece
To hazard more than for the golden fleece.
Fair Cynthia wish'd his arms might be her sphere;
Grief makes her pale, because she moves not there.
His body was as straight as Circe's wand;
Jove might have sipt out nectar from his hand.
Even as delicious meat is to the taste,
So was his neck in touching, and surpast
The white of Pelops' shoulder: I could tell ye,
How smooth his breast was, and how white his belly;
And whose immortal fingers did imprint
That heavenly path with many a curious dint
That runs along his back; but my rude pen
Can hardly blazon forth the loves of men,
Much less of powerful gods: let it suffice
That my slack Muse sings of Leander's eyes;
Those orient cheeks and lips, exceeding his
That leapt into the water for a kiss
Of his own shadow, and, despising many,
Died ere he could enjoy the love of any.
Had wild Hippolytus Leander seen,
Enamour'd of his beauty had he been.
His presence made the rudest peasant melt,
That in the vast uplandish country dwelt;
The barbarous Thracian soldier, mov'd with nought,
Was mov'd with him, and for his favour sought.
Some swore he was a maid in man's attire,
For in his looks were all that men desire,
A pleasant smiling cheek, a speaking eye,
A brow for love to banquet royally;
And such as knew he was a man, would say,
"Leander, thou art made for amorous play;
Why art thou not in love, and lov'd of all?
Though thou be fair, yet be not thine own thrall."
The men of wealthy Sestos every year,
For his sake whom their goddess held so dear,
Rose-cheek'd Adonis, kept a solemn feast.
Thither resorted many a wandering guest
To meet their loves; such as had none at all
Came lovers home from this great festival;
For every street, like to a firmament,
Glister'd with breathing stars, who, where they went,
Frighted the melancholy earth, which deem'd
Eternal heaven to burn, for so it seem'd
As if another Pha{"e}ton had got
The guidance of the sun's rich chariot.
But far above the loveliest, Hero shin'd,
And stole away th' enchanted gazer's mind;
For like sea-nymphs' inveigling harmony,
So was her beauty to the standers-by;
Nor that night-wandering, pale, and watery star
(When yawning dragons draw her thirling car
From Latmus' mount up to the gloomy sky,
Where, crown'd with blazing light and majesty,
She proudly sits) more over-rules the flood
Than she the hearts of those that near her stood.
Even as when gaudy nymphs pursue the chase,
Wretched Ixion's shaggy-footed race,
Incens'd with savage heat, gallop amain
From steep pine-bearing mountains to the plain,
So ran the people forth to gaze upon her,
And all that view'd her were enamour'd on her.
And as in fury of a dreadful fight,
Their fellows being slain or put to flight,
Poor soldiers stand with fear of death dead-strooken,
So at her presence all surpris'd and tooken,
Await the sentence of her scornful eyes;
He whom she favours lives; the other dies.
There might you see one sigh, another rage,
And some, their violent passions to assuage,
Compile sharp satires; but, alas, too late,
For faithful love will never turn to hate.
And many, seeing great princes were denied,
Pin'd as they went, and thinking on her, died.
On this feast-dayO cursed day and hour!
Went Hero thorough Sestos, from her tower
To Venus' temple, where unhappily,
As after chanc'd, they did each other spy.
So fair a church as this had Venus none:
The walls were of discolour'd jasper-stone,
Wherein was Proteus carved; and over-head
A lively vine of green sea-agate spread,
Where by one hand light-headed Bacchus hung,
And with the other wine from grapes out-wrung.
Of crystal shining fair the pavement was;
The town of Sestos call'd it Venus' glass:
There might you see the gods in sundry shapes,
Committing heady riots, incest, rapes:
For know, that underneath this radiant flower
Was Danae's statue in a brazen tower,
Jove slyly stealing from his sister's bed,
To dally with Idalian Ganimed,
And for his love Europa bellowing loud,
And tumbling with the rainbow in a cloud;
Blood-quaffing Mars heaving the iron net,
Which limping Vulcan and his Cyclops set;
Love kindling fire, to burn such towns as Troy,
Sylvanus weeping for the lovely boy
That now is turn'd into a cypress tree,
Under whose shade the wood-gods love to be.
And in the midst a silver altar stood:
There Hero, sacrificing turtles' blood,
Vail'd to the ground, veiling her eyelids close;
And modestly they opened as she rose.
Thence flew Love's arrow with the golden head;
And thus Leander was enamoured.
Stone-still he stood, and evermore he gazed,
Till with the fire that from his count'nance blazed
Relenting Hero's gentle heart was strook:
Such force and virtue hath an amorous look.
It lies not in our power to love or hate,
For will in us is over-rul'd by fate.
When two are stript, long ere the course begin,
We wish that one should lose, the other win;
And one especially do we affect
Of two gold ingots, like in each respect:
The reason no man knows, let it suffice,
What we behold is censur'd by our eyes.
Where both deliberate, the love is slight:
Who ever lov'd, that lov'd not at first sight?
@@ -0,0 +1,32 @@
CHRISTOPHER MARLOWE
The Passionate Shepherd to His Love
Come live with me and be my love,
And we will all the pleasures prove,
That Valleys, groves, hills, and fields,
Woods, or steepy mountain yields.
And we will sit upon the Rocks,
Seeing the Shepherds feed their flocks,
By shallow Rivers to whose falls
Melodious birds sing Madrigals.
And I will make thee beds of Roses
And a thousand fragrant posies,
A cap of flowers, and a kirtle
Embroidered all with leaves of Myrtle;
A gown made of the finest wool
Which from our pretty Lambs we pull;
Fair lined slippers for the cold,
With buckles of the purest gold;
A belt of straw and Ivy buds,
With Coral clasps and Amber studs:
And if these pleasures may thee move,
Come live with me, and be my love.
The Shepherds Swains shall dance and sing
For thy delight each May-morning:
If these delights thy mind may move,
Then live with me, and be my love.
@@ -0,0 +1,17 @@
DUCHESS OF NEWCASTLE MARGARET CAVENDISH
An Epilogue to the Above
Sir Charles into my chamber coming in,
When I was writing of my Fairy Queen;
I praysaid hewhen Queen Mab you do see
Present my service to her Majesty:
And tell her I have heard Fame's loud report
Both of her beauty and her stately court.
When I Queen Mab within my fancy viewed,
My thoughts bowed low, fearing I should be rude;
Kissing her garment thin which fancy made,
I knelt upon a thought, like one that prayed;
And then, in whispers soft, I did present
His humble service which in mirth was sent;
Thus by imagination I have been
In Fairy court and seen the Fairy Queen.
@@ -0,0 +1,13 @@
DUCHESS OF NEWCASTLE MARGARET CAVENDISH
The Duchess to Her Readers
A Poet am I neither born nor bred,
But to a witty poet married:
Whose brain is fresh and pleasant as the Spring,
Where Fancies grow and where the Muses sing.
There oft I lean my head, and listening, hark,
To catch his words and all his fancies mark:
And from that garden show of beauties take
Whereof a posy I in verse may make.
Thus I, that have no gardens of my own,
There gather flowers that are newly blown.
@@ -0,0 +1,36 @@
E. E. CUMMINGS
[in Just-]
in Just-
spring when the world is mud-
luscious the little
lame balloonman
whistles far and wee
and eddieandbill come
running from marbles and
piracies and it's
spring
when the world is puddle-wonderful
the queer
old balloonman whistles
far and wee
and bettyandisbel come dancing
from hop-scotch and jump-rope and
it's
spring
and
the
goat-footed
balloonMan whistles
far
and
wee
@@ -0,0 +1,37 @@
E. E. CUMMINGS
[little tree]
little tree
little silent Christmas tree
you are so little
you are more like a flower
who found you in the green forest
and were you very sorry to come away?
see i will comfort you
because you smell so sweetly
i will kiss your cool bark
and hug you safe and tight
just as your mother would,
only don't be afraid
look the spangles
that sleep all the year in a dark box
dreaming of being taken out and allowed to shine,
the balls the chains red and gold the fluffy threads,
put up your little arms
and i'll give them all to you to hold
every finger shall have its ring
and there won't be a single place dark or unhappy
then when you're quite dressed
you'll stand in the window for everyone to see
and how they'll stare!
oh but you'll be very proud
and my little sister and i will take hands
and looking up at our beautiful tree
we'll dance and sing
"Noel Noel"
@@ -0,0 +1,20 @@
EDMUND SPENSER
Amoretti I: Happy ye leaves when as those lilly hands
Happy ye leaves when as those lilly hands,
Which hold my life in their dead doing might
Shall handle you and hold in loves soft bands,
Lyke captives trembling at the victors sight.
And happy lines, on which with starry light,
Those lamping eyes will deigne sometimes to look
And reade the sorrowes of my dying spright,
Written with teares in harts close bleeding book.
And happy rymes bathd in the sacred brooke,
Of Helicon whence she derived is,
When ye behold that Angels blessed looke,
My soules long lacked foode, my heavens blis.
Leaves, lines, and rymes, seeke her to please alone,
Whom if ye please, I care for other none.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti III: The Sovereign Beauty
The sovereign beauty which I do admire,
Witness the world how worthy to be praised:
The light whereof hath kindled heavenly fire
In my frail spirit, by her from baseness raised;
That being now with her huge brightness dazed,
Base thing I can no more endure to view;
But looking still on her, I stand amazed
At wondrous sight of so celestial hue.
So when my tongue would speak her praises due,
It stopped is with thought's astonishment:
And when my pen would write her titles true,
It ravish'd is with fancy's wonderment:
Yet in my heart I then both speak and write
The wonder that my wit cannot endite.
@@ -0,0 +1,6 @@
EDMUND SPENSER
Amoretti IV: "New yeare forth looking out of Janus gate"
New yeare forth looking out of Janus gate,
Doth seeme to promise hope of new delight:
And bidding thold Adieu, his pass
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LIV: Of this worlds Theatre in which we stay
Of this worlds Theatre in which we stay,
My love lyke the Spectator ydly sits
Beholding me that all the pageants play,
Disguysing diversly my troubled wits.
Sometimes I joy when glad occasion fits,
And mask in myrth lyke to a Comedy:
Soone after when my joy to sorrow flits,
I waile and make my woes a Tragedy.
Yet she beholding me with constant eye,
Delights not in my merth nor rues my smart:
But when I laugh she mocks, and when I cry
She laughes, and hardens evermore her hart.
What then can move her? if not merth nor mone,
She is no woman, but a sencelesse stone.
@@ -0,0 +1,18 @@
EDMUND SPENSER
Amoretti LV: So oft as I her beauty do behold
So oft as I her beauty do behold,
And therewith do her cruelty compare,
I marvel of what substance was the mould
The which her made at once so cruel-fair.
Not earth; for her high thoughts more heavenly are:
Not water; for her love doth burn like fire:
Not air; for she is not so light or rare:
Not fire; for she doth freeze with faint desire.
Then needs another element inquire
Whereof she might be made; that is, the sky.
For to the heaven her haughty looks aspire,
And eke her love is pure immortal high.
Then since to heaven ye likened are the best,
Be like in mercy as in all the rest.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXII: "The weary yeare his race now having run"
The weary yeare his race now having run,
The new begins his compast course anew:
With shew of morning mylde he hath begun,
Betokening peace and plenty to ensew.
So let us, which this chaunge of weather vew,
Chaunge eeke our mynds and former lives amend,
The old yeares sinnes forepast let us eschew,
And fly the faults with which we did offend.
Then shall the new yeares joy forth freshly send,
Into the glooming world his gladsome ray:
And all these stormes which now his beauty blend,
Shall turne to caulmes and tymely cleare away.
So likewise love cheare you your heavy spright,
And chaunge old yeares annoy to new delight.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXVI: "To all those happy blessings which ye have"
To all those happy blessings which ye have,
With plenteous hand by heaven upon you thrown:
This one disparagement they to you gave,
That ye your love lent to so meane a one.
Yee whose high worths surpassing paragon,
Could not on earth have found one fit for mate,
Ne but in heaven matchable to none,
Why did ye stoup unto so lowly state.
But ye thereby much greater glory gate,
Then had ye sorted with a princes pere:
For now your light doth more it selfe dilate,
And in my darknesse greater doth appeare.
Yet since your light hath once enlumind me,
With my reflex yours shall encreased be.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXVII: Like as a Huntsman
Like as a huntsman after weary chase,
Seeing the game from him escap'd away,
Sits down to rest him in some shady place,
With panting hounds beguiled of their prey:
So after long pursuit and vain assay,
When I all weary had the chase forsook,
The gentle deer return'd the self-same way,
Thinking to quench her thirst at the next brook.
There she beholding me with milder look,
Sought not to fly, but fearless still did bide:
Till I in hand her yet half trembling took,
And with her own goodwill her firmly tied.
Strange thing, me seem'd, to see a beast so wild,
So goodly won, with her own will beguil'd.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXX: Fresh spring the herald of loves mighty king
Fresh spring the herald of loves mighty king,
In whose cote armour richly are displayed
All sorts of flowers the which on earth do spring
In goodly colours gloriously arrayd:
Goe to my love, where she is carelesse layd,
Yet in her winters bowre not well awake:
Tell her the joyous time wil not be staid
Unless she doe him by the forelock take.
Bid her therefore her selfe soone ready make,
To wayt on love amongst his lovely crew:
Where every one that misseth then her make,
Shall be by him amearst with penance dew.
Make hast therefore sweet love, whilest it is prime,
For none can call againe the passed time.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXXI: I joy to see how in your drawen work
I joy to see how in your drawen work,
Your selfe unto the Bee ye doe compare;
And me unto the Spyder that doth lurke,
In close awayt to catch her unaware.
Right so your selfe were caught in cunning snare
Of a deare for, and thralled to his love:
In whose streight bands ye now captived are
So firmely, that ye never may remove.
But as your whole worke is woven all about,
With woodbynd flowers and fragrant Enlantine:
So sweet your prison you in time shall prove,
With many deare delights bedecked fyne,
And all thensforth eternall peace shall see
Betweene the Spyder and the gentle Bee.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXXIV: Most Happy Letters
Most happy letters, fram'd by skilful trade,
With which that happy name was first design'd:
The which three times thrice happy hath me made,
With gifts of body, fortune, and of mind.
The first my being to me gave by kind,
From mother's womb deriv'd by due descent,
The second is my sovereign Queen most kind,
That honour and large richesse to me lent.
The third my love, my life's last ornament,
By whom my spirit out of dust was raised:
To speak her praise and glory excellent,
Of all alive most worthy to be praised.
Ye three Elizabeths for ever live,
That three such graces did unto me give.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXXIX: Men Call you Fair
Men call you fair, and you do credit it,
For that your self ye daily such do see:
But the true fair, that is the gentle wit,
And vertuous mind, is much more prais'd of me.
For all the rest, how ever fair it be,
Shall turn to naught and lose that glorious hue:
But only that is permanent and free
From frail corruption, that doth flesh ensue.
That is true beauty: that doth argue you
To be divine, and born of heavenly seed:
Deriv'd from that fair Spirit, from whom all true
And perfect beauty did at first proceed.
He only fair, and what he fair hath made,
All other fair, like flowers untimely fade.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXXV: One Day I Wrote her Name
One day I wrote her name upon the strand,
But came the waves and washed it away:
Again I wrote it with a second hand,
But came the tide, and made my pains his prey.
"Vain man," said she, "that dost in vain assay,
A mortal thing so to immortalize;
For I myself shall like to this decay,
And eke my name be wiped out likewise."
"Not so," (quod I) "let baser things devise
To die in dust, but you shall live by fame:
My verse your vertues rare shall eternize,
And in the heavens write your glorious name:
Where whenas death shall all the world subdue,
Our love shall live, and later life renew."
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXXXI: Fayre is my love, when her fayre golden heares
Fayre is my love, when her fayre golden heares,
With the loose wynd ye waving chance to marke:
Fayre when the rose in her red cheekes appears,
Or in her eyes the fyre of love does sparke.
Fayre when her brest lyke a rich laden barke,
With pretious merchandize she forth doth lay:
Fayre when that cloud of pryde which oft doth dark
Her goodly light with smiles she drives away,
But fayrest she, when so she doth display
The gate with pearles and rubyes richly dight:
Throgh which her words so wise do make their way
To beare the message of her gentle spright.
The rest be works of natures wonderment,
But this the worke of harts astonishment.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti LXXXIX: Lyke as the Culver on the bared bough
Lyke as the Culver on the bared bough,
Sits mourning for the absence of her mate:
And in her songs sends many a wishfull vow,
For his returne that seemes to linger late,
So I alone now left disconsolate,
Mourne to my selfe the absence of my love:
And wandring here and there all desolate,
Seek with my playnts to match that mournful dove:
Ne joy of ought that under heaven doth hove,
Can comfort me, but her owne joyous sight:
Whose sweet aspect both God and man can move,
In her unspotted pleasauns to delight.
Dark is my day, whyles her fayre light I mis,
And dead my life that wants such lively blis.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti VIII: More then most faire, full of the living fire
More then most faire, full of the living fire,
Kindled above unto the maker neere:
No eies but joyes, in which al powers conspire,
That to the world naught else be counted deare.
Thrugh your bright beams doth not the blinded guest
Shoot out his darts to base affections wound?
But Angels come to lead fraile mindes to rest
In chast desires on heavenly beauty bound.
You frame my thoughts and fashion me within,
You stop my toung, and teach my hart to speake,
You calme the storme that passion did begin,
Strong thrugh your cause, but by your vertue weak.
Dark is the world, where your light shined never;
Well is he borne, that may behold you ever.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti XIII: "In that proud port, which her so goodly graceth"
In that proud port, which her so goodly graceth,
Whiles her faire face she reares up to the skie:
And to the ground her eie lids low embaseth
Most goodly temperature ye may descry,
Myld humblesse mixt with awfull majesty,
For looking on the earth whence she was borne:
Her minde remembreth her mortalitie,
What so is fayrest shall to earth returne.
But that same lofty countenance seemes to scorne
Base thing, and thinke how she to heaven may clime:
Treading downe earth as lothsome and forlorne,
That hinders heavenly thoughts with drossy slime.
Yet lowly still vouchsafe to looke on me,
Such lowlinesse shall make you lofty be.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti XV: Ye tradefull Merchants that with weary toyle
Ye tradefull Merchants that with weary toyle,
Do seeke most pretious things to make your gain:
And both the Indias of their treasures spoile,
What needeth you to seeke so farre in vaine?
For loe my love doth in her selfe containe
All this worlds riches that may farre be found,
If Saphyres, loe hir eies be Saphyres plaine,
If Rubies, loe hir lips be Rubies sound:
If Pearles, hir teeth be pearles both pure and round;
If Yvorie, her forhead yvory weene;
If Gold, her locks are finest gold on ground;
If silver, her faire hands are silver sheene;
But that which fairest is, but few behold,
Her mind adornd with vertues manifold.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti XXII: This Holy Season
This holy season, fit to fast and pray,
Men to devotion ought to be inclin'd:
Therefore I likewise on so holy day,
For my sweet saint some service fit will find.
Her temple fair is built within my mind,
In which her glorious image placed is,
On which my thoughts do day and night attend,
Like sacred priests that never think amiss.
There I to her as th' author of my bliss,
Will build an altar to appease her ire:
And on the same my heart will sacrifice,
Burning in flames of pure and chaste desire:
The which vouchsafe, O goddess, to accept,
Amongst thy dearest relics to be kept.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti XXIII: Penelope for her Ulisses sake
Penelope for her Ulisses sake,
Devizd a Web her wooers to deceave:
In which the worke that she all day did make
The same at night she did again unreave:
Such subtile craft my Damzell doth conceave,
Th importune suit of my desire to shnone:
For all that I in many dayes doo weave,
In one short houre I find by her undonne.
So when I thinke to end that I begonne,
I must begin and never bring to end:
For with one looke she spils that long I sponne,
And with one word my whole years work doth rend.
Such labour like the Spyders web I fynd,
Whose fruitless worke is broken with least wynd.
@@ -0,0 +1,17 @@
EDMUND SPENSER
Amoretti XXX: My Love is like to ice, and I to fire
My Love is like to ice, and I to fire:
How comes it then that this her cold so great
Is not dissolved through my so hot desire,
But harder grows the more I her entreat?
Or how comes it that my exceeding heat
Is not allayed by her heart-frozen cold,
But that I burn much more in boiling sweat,
And feel my flames augmented manifold?
What more miraculous thing may be told,
That fire, which all things melts, should harden ice,
And ice, which is congeald with senseless cold,
Should kindle fire by wonderful device?
Such is the power of love in gentle mind,
That it can alter all the course of kind.
@@ -0,0 +1,330 @@
EDMUND SPENSER
An Hymn In Honour Of Beauty
AH whither, Love, wilt thou now carry me?
What wontless fury dost thou now inspire
Into my feeble breast, too full of thee?
Whilst seeking to aslake thy raging fire,
Thou in me kindlest much more great desire,
And up aloft above my strength dost raise
The wondrous matter of my fire to praise.
That as I erst in praise of thine own name,
So now in honour of thy mother dear,
An honourable hymn I eke should frame,
And with the brightness of her beauty clear,
The ravish'd hearts of gazeful men might rear
To admiration of that heavenly light,
From whence proceeds such soul-enchanting might.
Thereto do thou, great goddess, queen of beauty,
Mother of love, and of all world's delight,
Without whose sovereign grace and kindly duty
Nothing on earth seems fair to fleshly sight,
Do thou vouchsafe with thy love-kindling light
T' illuminate my dim and dulled eyne,
And beautify this sacred hymn of thine:
That both to thee, to whom I mean it most,
And eke to her, whose fair immortal beam
Hath darted fire into my feeble ghost,
That now it wasted is with woes extreme,
It may so please, that she at length will stream
Some dew of grace into my withered heart,
After long sorrow and consuming smart.
WHAT time this world's great Workmaster did cast
To make all things such as we now behold,
It seems that he before his eyes had plac'd
A goodly pattern, to whose perfect mould
He fashion'd them as comely as he could;
That now so fair and seemly they appear,
As nought may be amended anywhere.
That wondrous pattern, wheresoe'er it be,
Whether in earth laid up in secret store,
Or else in heaven, that no man may it see
With sinful eyes, for fear it to deflore,
Is perfect Beauty, which all men adore;
Whose face and feature doth so much excel
All mortal sense, that none the same may tell.
Thereof as every earthly thing partakes
Or more or less, by influence divine,
So it more fair accordingly it makes,
And the gross matter of this earthly mine,
Which clotheth it, thereafter doth refine,
Doing away the dross which dims the light
Of that fair beam which therein is empight.
For, through infusion of celestial power,
The duller earth it quick'neth with delight,
And lifeful spirits privily doth pour
Through all the parts, that to the looker's sight
They seem to please. That is thy sovereign might,
O Cyprian queen, which flowing from the beam
Of thy bright star, thou into them dost stream.
That is the thing which giveth pleasant grace
To all things fair, that kindleth lively fire,
Light of thy lamp, which, shining in the face,
Thence to the soul darts amorous desire,
And robs the hearts of those which it admire;
Therewith thou pointest thy son's poison'd arrow,
That wounds the life, and wastes the inmost marrow.
How vainly then do idle wits invent,
That beauty is nought else but mixture made
Of colours fair, and goodly temp'rament
Of pure complexions, that shall quickly fade
And pass away, like to a summer's shade;
Or that it is but comely composition
Of parts well measur'd, with meet disposition.
Hath white and red in it such wondrous power,
That it can pierce through th' eyes unto the heart,
And therein stir such rage and restless stour,
As nought but death can stint his dolour's smart?
Or can proportion of the outward part
Move such affection in the inward mind,
That it can rob both sense and reason blind?
Why do not then the blossoms of the field,
Which are array'd with much more orient hue,
And to the sense most dainty odours yield,
Work like impression in the looker's view?
Or why do not fair pictures like power shew,
In which oft-times we nature see of art
Excell'd, in perfect limning every part?
But ah, believe me, there is more than so,
That works such wonders in the minds of men;
I, that have often prov'd, too well it know,
And whoso list the like assays to ken,
Shall find by trial, and confess it then,
That beauty is not, as fond men misdeem,
An outward shew of things, that only seem.
For that same goodly hue of white and red,
With which the cheeks are sprinkled, shall decay,
And those sweet rosy leaves, so fairly spread
Upon the lips, shall fade and fall away
To that they were, even to corrupted clay;
That golden wire, those sparkling stars so bright,
Shall turn to dust; and lose their goodly light.
But that fair lamp, from whose celestial ray
That light proceeds, which kindleth lovers' fire,
Shall never be extinguish'd nor decay;
But when the vital spirits do expire,
Unto her native planet shall retire;
For it is heavenly born and cannot die,
Being a parcel of the purest sky.
For when the soul, the which derived was,
At first, out of that great immortal Spright,
By whom all live to love, whilom did pass
Down from the top of purest heaven's height
To be embodied here, it then took light
And lively spirits from that fairest star,
Which lights the world forth from his fiery car.
Which power retaining still or more or less,
When she in fleshly seed is eft enraced,
Through every part she doth the same impress,
According as the heavens have her graced,
And frames her house, in which she will be placed,
Fit for herself, adorning it with spoil
Of th' heavenly riches which she robb'd erewhile.
Thereof it comes that these fair souls, which have
The most resemblance of that heavenly light,
Frame to themselves most beautiful and brave
Their fleshly bower, most fit for their delight,
And the gross matter by a sovereign might
Tempers so trim, that it may well be seen
A palace fit for such a virgin queen.
So every spirit, as it is most pure,
And hath in it the more of heavenly light,
So it the fairer body doth procure
To habit in, and it more fairly dight
With cheerful grace and amiable sight.
For of the soul the body form doth take:
For soul is form, and doth the body make.
Therefore wherever that thou dost behold
A comely corpse, with beauty fair endued,
Know this for certain, that the same doth hold
A beauteous soul, with fair conditions thewed,
Fit to receive the seed of virtue strewed.
For all that fair is, is by nature good;
That is a sign to know the gentle blood.
Yet oft it falls that many a gentle mind
Dwells in deformed tabernacle drown'd,
Either by chance, against the course of kind,
Or through unaptness in the substance found,
Which it assumed of some stubborn ground,
That will not yield unto her form's direction,
But is deform'd with some foul imperfection.
And oft it falls, (ay me, the more to rue)
That goodly beauty, albe heavenly born,
Is foul abus'd, and that celestial hue,
Which doth the world with her delight adorn,
Made but the bait of sin, and sinners' scorn,
Whilst every one doth seek and sue to have it,
But every one doth seek but to deprave it.
Yet nathemore is that fair beauty's blame,
But theirs that do abuse it unto ill:
Nothing so good, but that through guilty shame
May be corrupt, and wrested unto will:
Natheless the soul is fair and beauteous still,
However flesh{"e}s fault it filthy make;
For things immortal no corruption take.
But ye fair dames, the world's dear ornaments
And lively images of heaven's light,
Let not your beams with such disparagements
Be dimm'd, and your bright glory dark'ned quite;
But mindful still of your first country's sight,
Do still preserve your first informed grace,
Whose shadow yet shines in your beauteous face.
Loathe that foul blot, that hellish firebrand,
Disloyal lust, fair beauty's foulest blame,
That base affections, which your ears would bland,
Commend to you by love's abused name,
But is indeed the bondslave of defame;
Which will the garland of your glory mar,
And quench the light of your bright shining star.
But gentle Love, that loyal is and true,
Will more illumine your resplendent ray,
And add more brightness to your goodly hue,
From light of his pure fire; which, by like way
Kindled of yours, your likeness doth display;
Like as two mirrors, by oppos'd reflection,
Do both express the face's first impression.
Therefore, to make your beauty more appear,
It you behoves to love, and forth to lay
That heavenly riches which in you ye bear,
That men the more admire their fountain may;
For else what booteth that celestial ray,
If it in darkness be enshrined ever,
That it of loving eyes be viewed never?
But, in your choice of loves, this well advise,
That likest to yourselves ye them select,
The which your forms' first source may sympathize,
And with like beauty's parts be inly deckt;
For, if you loosely love without respect,
It is no love, but a discordant war,
Whose unlike parts amongst themselves do jar.
For love is a celestial harmony
Of likely hearts compos'd of stars' concent,
Which join together in sweet sympathy,
To work each other's joy and true content,
Which they have harbour'd since their first descent
Out of their heavenly bowers, where they did see
And know each other here belov'd to be.
Then wrong it were that any other twain
Should in love's gentle band combined be
But those whom Heaven did at first ordain,
And made out of one mould the more t' agree;
For all that like the beauty which they see,
Straight do not love; for love is not so light
As straight to burn at first beholder's sight.
But they, which love indeed, look otherwise,
With pure regard and spotless true intent,
Drawing out of the object of their eyes
A more refined form, which they present
Unto their mind, void of all blemishment;
Which it reducing to her first perfection,
Beholdeth free from flesh's frail infection.
And then conforming it unto the light,
Which in itself it hath remaining still,
Of that first Sun, yet sparkling in his sight,
Thereof he fashions in his higher skill
An heavenly beauty to his fancy's will;
And it embracing in his mind entire,
The mirror of his own thought doth admire.
Which seeing now so inly fair to be,
As outward it appeareth to the eye,
And with his spirit's proportion to agree,
He thereon fixeth all his fantasy,
And fully setteth his felicity;
Counting it fairer than it is indeed,
And yet indeed her fairness doth exceed.
For lovers' eyes more sharply sighted be
Than other men's, and in dear love's delight
See more than any other eyes can see,
Through mutual receipt of beam{"e}s bright,
Which carry privy message to the spright,
And to their eyes that inmost fair display,
As plain as light discovers dawning day.
Therein they see, through amorous eye-glances,
Armies of loves still flying to and fro,
Which dart at them their little fiery lances;
Whom having wounded, back again they go,
Carrying compassion to their lovely foe;
Who, seeing her fair eyes' so sharp effect,
Cures all their sorrows with one sweet aspect.
In which how many wonders do they rede
To their conceit, that others never see,
Now of her smiles, with which their souls they feed,
Like gods with nectar in their banquets free;
Now of her looks, which like to cordials be;
But when her words' embassade forth she sends,
Lord, how sweet music that unto them lends.
Sometimes upon her forehead they behold
A thousand graces masking in delight;
Sometimes within her eyelids they unfold
Ten thousand sweet belgards, which to their sight
Do seem like twinkling stars in frosty night;
But on her lips, like rosy buds in May,
So many millions of chaste pleasures play.
All those, O Cytherea, and thousands more
Thy handmaids be, which do on thee attend,
To deck thy beauty with their dainties' store,
That may it more to mortal eyes commend,
And make it more admir'd of foe and friend:
That in men's hearts thou may'st thy throne install,
And spread thy lovely kingdom over all.
Then Io, triumph! O great Beauty's Queen,
Advance the banner of thy conquest high,
That all this world, the which thy vassals bene,
May draw to thee, and with due fealty
Adore the power of thy great majesty,
Singing this hymn in honour of thy name,
Compil'd by me, which thy poor liegeman am.
In lieu whereof grant, O great sovereign,
That she whose conquering beauty doth captive
My trembling heart in her eternal chain,
One drop of grace at length will to me give,
That I her bounden thrall by her may live,
And this same life, which first fro me she reaved,
May owe to her, of whom I it received.
And you, fair Venus' darling, my dear dread,
Fresh flower of grace, great goddess of my life,
When your fair eyes these fearful lines shall read,
Deign to let fall one drop of due relief,
That may recure my heart's long pining grief,
And shew what wondrous power your beauty hath,
That can restore a damned wight from death.
@@ -0,0 +1,459 @@
EDMUND SPENSER
Epithalamion
Ye learned sisters which have oftentimes
Beene to me ayding, others to adorne:
Whom ye thought worthy of your gracefull rymes,
That even the greatest did not greatly scorne
To heare theyr names sung in your simple layes,
But joyed in theyr prayse.
And when ye list your owne mishaps to mourne,
Which death, or love, or fortunes wreck did rayse,
Your string could soone to sadder tenor turne,
And teach the woods and waters to lament
Your dolefull dreriment.
Now lay those sorrowfull complaints aside,
And having all your heads with girland crownd,
Helpe me mine owne loves prayses to resound,
Ne let the same of any be envide:
So Orpheus did for his owne bride,
So I unto my selfe alone will sing,
The woods shall to me answer and my Eccho ring.
Early before the worlds light giving lampe,
His golden beame upon the hils doth spred,
Having disperst the nights unchearefull dampe,
Doe ye awake, and with fresh lusty hed,
Go to the bowre of my beloved love,
My truest turtle dove,
Bid her awake; for Hymen is awake,
And long since ready forth his maske to move,
With his bright Tead that flames with many a flake,
And many a bachelor to waite on him,
In theyr fresh garments trim.
Bid her awake therefore and soone her dight,
For lo the wished day is come at last,
That shall for al the paynes and sorrowes past,
Pay to her usury of long delight:
And whylest she doth her dight,
Doe ye to her of joy and solace sing,
That all the woods may answer and your eccho ring.
Bring with you all the Nymphes that you can heare
Both of the rivers and the forrests greene:
And of the sea that neighbours to her neare,
Al with gay girlands goodly wel beseene.
And let them also with them bring in hand
Another gay girland
For my fayre love of lillyes and of roses,
Bound truelove wize with a blew silke riband.
And let them make great store of bridale poses,
And let them eeke bring store of other flowers
To deck the bridale bowers.
And let the ground whereas her foot shall tread,
For feare the stones her tender foot should wrong
Be strewed with fragrant flowers all along,
And diapred lyke the discolored mead.
Which done, doe at her chamber dore awayt,
For she will waken strayt,
The whiles doe ye this song unto her sing,
The woods shall to you answer and your Eccho ring.
Ye Nymphes of Mulla which with carefull heed,
The silver scaly trouts doe tend full well,
And greedy pikes which use therein to feed,
(Those trouts and pikes all others doo excell)
And ye likewise which keepe the rushy lake,
Where none doo fishes take,
Bynd up the locks the which hang scatterd light,
And in his waters which your mirror make,
Behold your faces as the christall bright,
That when you come whereas my love doth lie,
No blemish she may spie.
And eke ye lightfoot mayds which keepe the deere,
That on the hoary mountayne use to towre,
And the wylde wolves which seeke them to devoure,
With your steele darts doo chace from comming neer,
Be also present heere,
To helpe to decke her and to help to sing,
That all the woods may answer and your eccho ring.
Wake, now my love, awake; for it is time,
The Rosy Morne long since left Tithones bed,
All ready to her silver coche to clyme,
And Phoebus gins to shew his glorious hed.
Hark how the cheerefull birds do chaunt theyr laies
And carroll of loves praise.
The merry Larke hir mattins sings aloft,
The thrush replyes, the Mavis descant playes,
The Ouzell shrills, the Ruddock warbles soft,
So goodly all agree with sweet consent,
To this dayes merriment.
Ah my deere love why doe ye sleepe thus long,
When meeter were that ye should now awake,
T'awayt the comming of your joyous make,
And hearken to the birds lovelearned song,
The deawy leaves among.
For they of joy and pleasance to you sing,
That all the woods them answer and theyr eccho ring.
My love is now awake out of her dreames,
And her fayre eyes like stars that dimmed were
With darksome cloud, now shew theyr goodly beames
More bright then Hesperus his head doth rere.
Come now ye damzels, daughters of delight,
Helpe quickly her to dight,
But first come ye fayre houres which were begot
In Joves sweet paradice, of Day and Night,
Which doe the seasons of the yeare allot,
And al that ever in this world is fayre
Doe make and still repayre.
And ye three handmayds of the Cyprian Queene,
The which doe still adorne her beauties pride,
Helpe to addorne my beautifullest bride:
And as ye her array, still throw betweene
Some graces to be seene,
And as ye use to Venus, to her sing,
The whiles the woods shal answer and your eccho ring.
Now is my love all ready forth to come,
Let all the virgins therefore well awayt,
And ye fresh boyes that tend upon her groome
Prepare your selves; for he is comming strayt.
Set all your things in seemely good aray
Fit for so joyfull day,
The joyfulst day that ever sunne did see.
Faire Sun, shew forth thy favourable ray,
And let thy lifull heat not fervent be
For feare of burning her sunshyny face,
Her beauty to disgrace.
O fayrest Phoebus, father of the Muse,
If ever I did honour thee aright,
Or sing the thing, that mote thy mind delight,
Doe not thy servants simple boone refuse,
But let this day let this one day be myne,
Let all the rest be thine.
Then I thy soverayne prayses loud will sing,
That all the woods shal answer and theyr eccho ring.
Harke how the Minstrels gin to shrill aloud
Their merry Musick that resounds from far,
The pipe, the tabor, and the trembling Croud,
That well agree withouten breach or jar.
But most of all the Damzels doe delite,
When they their tymbrels smyte,
And thereunto doe daunce and carrol sweet,
That all the sences they doe ravish quite,
The whyles the boyes run up and downe the street,
Crying aloud with strong confused noyce,
As if it were one voyce.
Hymen io Hymen, Hymen they do shout,
That even to the heavens theyr shouting shrill
Doth reach, and all the firmament doth fill,
To which the people standing all about,
As in approvance doe thereto applaud
And loud advaunce her laud,
And evermore they Hymen Hymen sing,
That al the woods them answer and theyr eccho ring.
Loe where she comes along with portly pace
Lyke Phoebe from her chamber of the East,
Arysing forth to run her mighty race,
Clad all in white, that seemes a virgin best.
So well it her beseemes that ye would weene
Some angell she had beene.
Her long loose yellow locks lyke golden wyre,
Sprinckled with perle, and perling flowres a tweene,
Doe lyke a golden mantle her attyre,
And being crowned with a girland greene,
Seeme lyke some mayden Queene.
Her modest eyes abashed to behold
So many gazers, as on her do stare,
Upon the lowly ground affixed are.
Ne dare lift up her countenance too bold,
But blush to heare her prayses sung so loud,
So farre from being proud.
Nathlesse doe ye still loud her prayses sing,
That all the woods may answer and your eccho ring.
Tell me ye merchants daughters did ye see
So fayre a creature in your towne before?
So sweet, so lovely, and so mild as she,
Adornd with beautyes grace and vertues store,
Her goodly eyes lyke Saphyres shining bright,
Her forehead yvory white,
Her cheekes lyke apples which the sun hath rudded,
Her lips lyke cherryes charming men to byte,
Her brest like to a bowle of creame uncrudded,
Her paps lyke lyllies budded,
Her snowie necke lyke to a marble towre,
And all her body like a pallace fayre,
Ascending uppe with many a stately stayre,
To honors seat and chastities sweet bowre.
Why stand ye still ye virgins in amaze,
Upon her so to gaze,
Whiles ye forget your former lay to sing,
To which the woods did answer and your eccho ring.
But if ye saw that which no eyes can see,
The inward beauty of her lively spright,
Garnisht with heavenly guifts of high degree,
Much more then would ye wonder at that sight,
And stand astonisht lyke to those which red
Medusaes mazeful hed.
There dwels sweet love and constant chastity,
Unspotted fayth and comely womenhed,
Regard of honour and mild modesty,
There vertue raynes as Queene in royal throne,
And giveth lawes alone.
The which the base affections doe obay,
And yeeld theyr services unto her will,
Ne thought of thing uncomely ever may
Thereto approch to tempt her mind to ill.
Had ye once seene these her celestial threasures,
And unrevealed pleasures,
Then would ye wonder and her prayses sing,
That al the woods should answer and your eccho ring.
Open the temple gates unto my love,
Open them wide that she may enter in,
And all the postes adorne as doth behove,
And all the pillours deck with girlands trim,
For to recyve this Saynt with honour dew,
That commeth in to you.
With trembling steps and humble reverence,
She commeth in, before th'almighties vew:
Of her ye virgins learne obedience,
When so ye come into those holy places,
To humble your proud faces;
Bring her up to th'high altar that she may,
The sacred ceremonies there partake,
The which do endlesse matrimony make,
And let the roring Organs loudly play
The praises of the Lord in lively notes,
The whiles with hollow throates
The Choristers the joyous Antheme sing,
That al the woods may answere and their eccho ring.
Behold whiles she before the altar stands
Hearing the holy priest that to her speakes
And blesseth her with his two happy hands,
How the red roses flush up in her cheekes,
And the pure snow with goodly vermill stayne,
Like crimsin dyde in grayne,
That even th'Angels which continually,
About the sacred Altare doe remaine,
Forget their service and about her fly,
Ofte peeping in her face that seemes more fayre,
The more they on it stare.
But her sad eyes still fastened on the ground,
Are governed with goodly modesty,
That suffers not one looke to glaunce awry,
Which may let in a little thought unsownd.
Why blush ye love to give to me your hand,
The pledge of all our band?
Sing ye sweet Angels, Alleluya sing,
That all the woods may answere and your eccho ring.
Now al is done; bring home the bride againe,
Bring home the triumph of our victory,
Bring home with you the glory of her gaine,
With joyance bring her and with jollity.
Never had man more joyfull day then this,
Whom heaven would heape with blis.
Make feast therefore now all this live long day,
This day for ever to me holy is,
Poure out the wine without restraint or stay,
Poure not by cups, but by the belly full,
Poure out to all that wull,
And sprinkle all the postes and wals with wine,
That they may sweat, and drunken be withall.
Crowne ye God Bacchus with a coronall,
And Hymen also crowne with wreathes of vine,
And let the Graces daunce unto the rest;
For they can doo it best:
The whiles the maydens doe theyr carroll sing,
To which the woods shal answer and theyr eccho ring.
Ring ye the bels, ye yong men of the towne,
And leave your wonted labors for this day:
This day is holy; doe ye write it downe,
That ye for ever it remember may.
This day the sunne is in his chiefest hight,
With Barnaby the bright,
From whence declining daily by degrees,
He somewhat loseth of his heat and light,
When once the Crab behind his back he sees.
But for this time it ill ordained was,
To chose the longest day in all the yeare,
And shortest night, when longest fitter weare:
Yet never day so long, but late would passe.
Ring ye the bels, to make it weare away,
And bonefiers make all day,
And daunce about them, and about them sing:
That all the woods may answer, and your eccho ring.
Ah when will this long weary day have end,
And lende me leave to come unto my love?
How slowly do the houres theyr numbers spend?
How slowly does sad Time his feathers move?
Hast thee O fayrest Planet to thy home
Within the Westerne fome:
Thy tyred steedes long since have need of rest.
Long though it be, at last I see it gloome,
And the bright evening star with golden creast
Appeare out of the East.
Fayre childe of beauty, glorious lampe of love
That all the host of heaven in rankes doost lead,
And guydest lovers through the nightes dread,
How chearefully thou lookest from above,
And seemst to laugh atweene thy twinkling light
As joying in the sight
Of these glad many which for joy doe sing,
That all the woods them answer and their echo ring.
Now ceasse ye damsels your delights forepast;
Enough is it, that all the day was youres:
Now day is doen, and night is nighing fast:
Now bring the Bryde into the brydall boures.
Now night is come, now soone her disaray,
And in her bed her lay;
Lay her in lillies and in violets,
And silken courteins over her display,
And odourd sheetes, and Arras coverlets.
Behold how goodly my faire love does ly
In proud humility;
Like unto Maia, when as Jove her tooke,
In Tempe, lying on the flowry gras,
Twixt sleepe and wake, after she weary was,
With bathing in the Acidalian brooke.
Now it is night, ye damsels may be gon,
And leave my love alone,
And leave likewise your former lay to sing:
The woods no more shal answere, nor your echo ring.
Now welcome night, thou night so long expected,
That long daies labour doest at last defray,
And all my cares, which cruell love collected,
Hast sumd in one, and cancelled for aye:
Spread thy broad wing over my love and me,
That no man may us see,
And in thy sable mantle us enwrap,
From feare of perrill and foule horror free.
Let no false treason seeke us to entrap,
Nor any dread disquiet once annoy
The safety of our joy:
But let the night be calme and quietsome,
Without tempestuous storms or sad afray:
Lyke as when Jove with fayre Alcmena lay,
When he begot the great Tirynthian groome:
Or lyke as when he with thy selfe did lie,
And begot Majesty.
And let the mayds and yongmen cease to sing:
Ne let the woods them answer, nor theyr eccho ring.
Let no lamenting cryes, nor dolefull teares,
Be heard all night within nor yet without:
Ne let false whispers, breeding hidden feares,
Breake gentle sleepe with misconceived dout.
Let no deluding dreames, nor dreadful sights
Make sudden sad affrights;
Ne let housefyres, nor lightnings helpelesse harmes,
Ne let the Pouke, nor other evill sprights,
Ne let mischivous witches with theyr charmes,
Ne let hob Goblins, names whose sence we see not,
Fray us with things that be not.
Let not the shriech Oule, nor the Storke be heard:
Nor the night Raven that still deadly yels,
Nor damned ghosts cald up with mighty spels,
Nor griesly vultures make us once affeard:
Ne let th'unpleasant Quyre of Frogs still croking
Make us to wish theyr choking.
Let none of these theyr drery accents sing;
Ne let the woods them answer, nor theyr eccho ring.
But let stil Silence trew night watches keepe,
That sacred peace may in assurance rayne,
And tymely sleep, when it is tyme to sleepe,
May poure his limbs forth on your pleasant playne,
The whiles an hundred little winged loves,
Like divers fethered doves,
Shall fly and flutter round about your bed,
And in the secret darke, that none reproves,
Their prety stelthes shal worke, and snares shal spread
To filch away sweet snatches of delight,
Conceald through covert night.
Ye sonnes of Venus, play your sports at will,
For greedy pleasure, carelesse of your toyes,
Thinks more upon her paradise of joyes,
Then what ye do, albe it good or ill.
All night therefore attend your merry play,
For it will soone be day:
Now none doth hinder you, that say or sing,
Ne will the woods now answer, nor your Eccho ring.
Who is the same, which at my window peepes?
Or whose is that faire face, that shines so bright,
Is it not Cinthia, she that never sleepes,
But walkes about high heaven al the night?
O fayrest goddesse, do thou not envy
My love with me to spy:
For thou likewise didst love, though now unthought,
And for a fleece of woll, which privily,
The Latmian shephard once unto thee brought,
His pleasures with thee wrought.
Therefore to us be favorable now;
And sith of wemens labours thou hast charge,
And generation goodly dost enlarge,
Encline thy will t'effect our wishfull vow,
And the chast wombe informe with timely seed,
That may our comfort breed:
Till which we cease our hopefull hap to sing,
Ne let the woods us answere, nor our Eccho ring.
And thou great Juno, which with awful might
The lawes of wedlock still dost patronize,
And the religion of the faith first plight
With sacred rites hast taught to solemnize:
And eeke for comfort often called art
Of women in their smart,
Eternally bind thou this lovely band,
And all thy blessings unto us impart.
And thou glad Genius, in whose gentle hand,
The bridale bowre and geniall bed remaine,
Without blemish or staine,
And the sweet pleasures of theyr loves delight
With secret ayde doest succour and supply,
Till they bring forth the fruitfull progeny,
Send us the timely fruit of this same night.
And thou fayre Hebe, and thou Hymen free,
Grant that it may so be.
Til which we cease your further prayse to sing,
Ne any woods shal answer, nor your Eccho ring.
And ye high heavens, the temple of the gods,
In which a thousand torches flaming bright
Doe burne, that to us wretched earthly clods,
In dreadful darknesse lend desired light;
And all ye powers which in the same remayne,
More then we men can fayne,
Poure out your blessing on us plentiously,
And happy influence upon us raine,
That we may raise a large posterity,
Which from the earth, which they may long possesse,
With lasting happinesse,
Up to your haughty pallaces may mount,
And for the guerdon of theyr glorious merit
May heavenly tabernacles there inherit,
Of blessed Saints for to increase the count.
So let us rest, sweet love, in hope of this,
And cease till then our tymely joyes to sing,
The woods no more us answer, nor our eccho ring.
Song made in lieu of many ornaments,
With which my love should duly have bene dect,
Which cutting off through hasty accidents,
Ye would not stay your dew time to expect,
But promist both to recompens,
Be unto her a goodly ornament,
And for short time an endlesse moniment.
@@ -0,0 +1,644 @@
EDMUND SPENSER
from The Faerie Queene: Book I, Canto I
Lo I the man, whose Muse whilome did maske,
As time her taught in lowly Shepheards weeds,
Am now enforst a far unfitter taske,
For trumpets sterne to chaunge mine Oaten reeds,
And sing of Knights and Ladies gentle deeds;
Whose prayses having slept in silence long,
Me, all too meane, the sacred Muse areeds
To blazon broad emongst her learned throng:
Fierce warres and faithful loves shall moralize my song.
Helpe then, O holy Virgin chiefe of nine,
Thy weaker Novice to performe thy will,
Lay forth out of thine everlasting scryne
The antique rolles, which there lye hidden still,
Of Faerie knights and fairest Tanaquill,
Whom that most noble Briton Prince so long
Sought through the world, and suffered so much ill,
That I must rue his undeserved wrong:
O helpe thou my weake wit, and sharpen my dull tong.
And thou most dreaded impe of highest Jove,
Faire Venus sonne, that with thy cruell dart
At that good knight so cunningly didst rove,
That glorious fire it kindled in his hart,
Lay now thy deadly Heben bow apart,
And with thy mother milde come to mine ayde:
Come both, and with you bring triumphant Mart,
In loves and gentle jollities arrayd,
After his murdrous spoiles and bloudy rage allayd.
And with them eke, O Goddesse heavenly bright,
Mirrour of grace and Majestie divine,
Great Lady of the greatest Isle, whose light
Like Phoebus lampe throughout the world doth shine,
Shed thy faire beames into my feeble eyne,
And raise my thoughts too humble and too vile,
To thinke of that true glorious type of thine,
The argument of mine afflicted stile:
The which to heare, vouchsafe, O dearest dred a-while.
i
A Gentle Knight was pricking on the plaine,
Y cladd in mightie armes and silver shielde,
Wherein old dints of deepe wounds did remaine,
The cruell markes of many a bloudy fielde;
Yet armes till that time did he never wield:
His angry steede did chide his foming bitt,
As much disdayning to the curbe to yield:
Full jolly knight he seemd, and faire did sitt,
As one for knightly giusts and fierce encounters fitt.
ii
But on his brest a bloudie Crosse he bore,
The deare remembrance of his dying Lord,
For whose sweete sake that glorious badge he wore,
And dead as living ever him ador'd:
Upon his shield the like was also scor'd,
For soveraine hope, which in his helpe he had:
Right faithfull true he was in deede and word,
But of his cheere did seeme too solemne sad;
Yet nothing did he dread, but ever was ydrad.
iii
Upon a great adventure he was bond,
That greatest Gloriana to him gave,
That greatest Glorious Queene of Faerie lond,
To winne him worship, and her grace to have,
Which of all earthly things he most did crave;
And ever as he rode, his hart did earne
To prove his puissance in battell brave
Upon his foe, and his new force to learne;
Upon his foe, a Dragon horrible and stearne.
iv
A lovely Ladie rode him faire beside,
Upon a lowly Asse more white then snow,
Yet she much whiter, but the same did hide
Under a vele, that wimpled was full low,
And over all a blacke stole she did throw,
As one that inly mournd: so was she sad,
And heavie sat upon her palfrey slow;
Seemed in heart some hidden care she had,
And by her in a line a milke white lambe she lad.
v
So pure an innocent, as that same lambe,
She was in life and every vertuous lore,
And by descent from Royall lynage came
Of ancient Kings and Queenes, that had of yore
Their scepters stretcht from East to Westerne shore,
And all the world in their subjection held;
Till that infernall feend with foule uprore
Forwasted all their land, and them expeld:
Whom to avenge, she had this Knight from far compeld.
vi
Behind her farre away a Dwarfe did lag,
That lasie seemd in being ever last,
Or wearied with bearing of her bag
Of needments at his backe. Thus as they past,
The day with cloudes was suddeine overcast,
And angry Jove an hideous storme of raine
Did poure into his Lemans lap so fast,
That every wight to shrowd it did constrain,
And this faire couple eke to shroud themselves were fain.
vii
Enforst to seeke some covert nigh at hand,
A shadie grove not far away they spide,
That promist ayde the tempest to withstand:
Whose loftie trees yclad with sommers pride,
Did spred so broad, that heavens light did hide,
Not perceable with power of any starre:
And all within were pathes and alleies wide,
With footing worne, and leading inward farre:
Faire harbour that them seemes; so in they entred arre.
viii
And foorth they passe, with pleasure forward led,
Joying to heare the birdes sweete harmony,
Which therein shrouded from the tempest dred,
Seemd in their song to scorne the cruell sky.
Much can they prayse the trees so straight and hy,
The sayling Pine, the Cedar proud and tall,
The vine-prop Elme, the Poplar never dry,
The builder Oake, sole king of forrests all,
The Aspine good for staves, the Cypresse funerall.
ix
The Laurell, meed of mightie Conquerours
And Poets sage, the Firre that weepeth still,
The Willow worne of forlorne Paramours,
The Eugh obedient to the benders will,
The Birch for shaftes, the Sallow for the mill,
The Mirrhe sweete bleeding in the bitter wound,
The warlike Beech, the Ash for nothing ill,
The fruitfull Olive, and the Platane round,
The carver Holme, the Maple seeldom inward sound.
x
Led with delight, they thus beguile the way,
Untill the blustring storme is overblowne;
When weening to returne, whence they did stray,
They cannot find that path, which first was showne,
But wander too and fro in wayes unknowne,
Furthest from end then, when they neerest weene,
That makes them doubt, their wits be not their owne:
So many pathes, so many turnings seene,
That which of them to take, in diverse doubt they been.
xi
At last resolving forward still to fare,
Till that some end they finde or in or out,
That path they take, that beaten seemd most bare,
And like to lead the labyrinth about;
Which when by tract they hunted had throughout,
At length it brought them to a hollow cave,
Amid the thickest woods. The Champion stout
Eftsoones dismounted from his courser brave,
And to the Dwarfe a while his needlesse spere he gave.
xii
Be well aware, quoth then that Ladie milde,
Least suddaine mischiefe ye too rash provoke:
The danger hid, the place unknowne and wilde,
Breeds dreadfull doubts: Oft fire is without smoke,
And perill without show: therefore your stroke
Sir knight with-hold, till further triall made.
Ah Ladie (said he) shame were to revoke
The forward footing for an hidden shade:
Vertue gives her selfe light, through darkenesse for to wade.
xiii
Yea but (quoth she) the perill of this place
I better wot then you, though now too late
To wish you backe returne with foule disgrace,
Yet wisedome warnes, whilest foot is in the gate,
To stay the steppe, ere forced to retrate.
This is the wandring wood, this Errours den,
A monster vile, whom God and man does hate:
Therefore I read beware. Fly fly (quoth then
The fearefull Dwarfe:) this is no place for living men.
xiv
But full of fire and greedy hardiment,
The youthfull knight could not for ought be staide,
But forth unto the darksome hole he went,
And looked in: his glistring armor made
A litle glooming light, much like a shade,
By which he saw the ugly monster plaine,
Halfe like a serpent horribly displaide,
But th'other halfe did womans shape retaine,
Most lothsom, filthie, foule, and full of vile disdaine.
xv
And as she lay upon the durtie ground,
Her huge long taile her den all overspred,
Yet was in knots and many boughtes upwound,
Pointed with mortall sting. Of her there bred
A thousand yong ones, which she dayly fed,
Sucking upon her poisonous dugs, eachone
Of sundry shapes, yet all ill favored:
Soone as that uncouth light upon them shone,
Into her mouth they crept, and suddain all were gone.
xvi
Their dam upstart, out of her den effraide,
And rushed forth, hurling her hideous taile
About her cursed head, whose folds displaid
Were stretcht now forth at length without entraile.
She lookt about, and seeing one in mayle
Armed to point, sought backe to turne againe;
For light she hated as the deadly bale,
Ay wont in desert darknesse to remaine,
Where plaine none might her see, nor she see any plaine.
xvii
Which when the valiant Elfe perceiv'd, he lept
As Lyon fierce upon the flying pray,
And with his trenchand blade her boldly kept
From turning backe, and forced her to stay:
Therewith enrag'd she loudly gan to bray,
And turning fierce, her speckled taile advaunst,
Threatning her angry sting, him to dismay:
Who nought aghast, his mightie hand enhaunst:
The stroke down from her head unto her shoulder glaunst.
xviii
Much daunted with that dint, her sence was dazd,
Yet kindling rage, her selfe she gathered round,
And all attonce her beastly body raizd
With doubled forces high above the ground:
Tho wrapping up her wrethed sterne arownd,
Lept fierce upon his shield, and her huge traine
All suddenly about his body wound,
That hand or foot to stirre he strove in vaine:
God helpe the man so wrapt in Errours endlesse traine.
xix
His Lady sad to see his sore constraint,
Cride out, Now now Sir knight, shew what ye bee,
Add faith unto your force, and be not faint:
Strangle her, else she sure will strangle thee.
That when he heard, in great perplexitie,
His gall did grate for griefe and high disdaine,
And knitting all his force got one hand free,
Wherewith he grypt her gorge with so great paine,
That soone to loose her wicked bands did her constraine.
xx
Therewith she spewd out of her filthy maw
A floud of poyson horrible and blacke,
Full of great lumpes of flesh and gobbets raw,
Which stunck so vildly, that it forst him slacke
His grasping hold, and from her turne him backe:
Her vomit full of bookes and papers was,
With loathly frogs and toades, which eyes did lacke,
And creeping sought way in the weedy gras:
Her filthy parbreake all the place defiled has.
xxi
As when old father Nilus gins to swell
With timely pride above the Aegyptian vale,
His fattie waves do fertile slime outwell,
And overflow each plaine and lowly dale:
But when his later spring gins to avale,
Huge heapes of mudd he leaves, wherein there breed
Ten thousand kindes of creatures, partly male
And partly female of his fruitfull seed;
Such ugly monstrous shapes elsewhere may no man reed.
xxii
The same so sore annoyed has the knight,
That welnigh choked with the deadly stinke,
His forces faile, ne can no longer fight.
Whose corage when the feend perceiv'd to shrinke,
She poured forth out of her hellish sinke
Her fruitfull cursed spawne of serpents small,
Deformed monsters, fowle, and blacke as inke,
Which swarming all about his legs did crall,
And him encombred sore, but could not hurt at all.
xxiii
As gentle Shepheard in sweete even-tide,
When ruddy Phoebus gins to welke in west,
High on an hill, his flocke to vewen wide,
Markes which do byte their hasty supper best;
A cloud of combrous gnattes do him molest,
All striving to infixe their feeble stings,
That from their noyance he no where can rest,
But with his clownish hands their tender wings
He brusheth oft, and oft doth mar their murmurings.
xxiv
Thus ill bestedd, and fearefull more of shame,
Then of the certaine perill he stood in,
Halfe furious unto his foe he came,
Resolv'd in minde all suddenly to win,
Or soone to lose, before he once would lin;
And strooke at her with more then manly force,
That from her body full of filthie sin
He raft her hatefull head without remorse;
A streame of cole black bloud forth gushed from her corse.
xxv
Her scattred brood, soone as their Parent deare
They saw so rudely falling to the ground,
Groning full deadly, all with troublous feare,
Gathred themselves about her body round,
Weening their wonted entrance to have found
At her wide mouth: but being there withstood
They flocked all about her bleeding wound,
And sucked up their dying mothers blood,
Making her death their life, and eke her hurt their good.
xxvi
That detestable sight him much amazde,
To see th'unkindly Impes of heaven accurst,
Devoure their dam; on whom while so he gazd,
Having all satisfide their bloudy thurst,
Their bellies swolne he saw with fulnesse burst,
And bowels gushing forth: well worthy end
Of such as drunke her life, the which them nurst;
Now needeth him no lenger labour spend,
His foes have slaine themselves, with whom he should contend.
xxvii
His Ladie seeing all, that chaunst, from farre
Approcht in hast to greet his victorie,
And said, Faire knight, borne under happy starre,
Who see your vanquisht foes before you lye:
Well worthy be you of that Armorie,
Wherein ye have great glory wonne this day,
And proov'd your strength on a strong enimie,
Your first adventure: many such I pray,
And henceforth ever wish, that like succeed it may.
xxviii
Then mounted he upon his Steede againe,
And with the Lady backward sought to wend;
That path he kept, which beaten was most plame,
Ne ever would to any by-way bend,
But still did follow one unto the end,
The which at last out of the wood them brought.
So forward on his way (with God to frend)
He passed forth, and new adventure sought;
Long way he travelled, before he heard of ought.
xxix
At length they chaunst to meet upon the way
An aged Sire, in long blacke weedes yclad,
His feete all bare, his beard all hoarie gray,
And by his belt his booke he hanging had;
Sober he seemde, and very sagely sad,
And to the ground his eyes were lowly bent,
Simple in shew, and voyde of malice bad,
And all the way he prayed, as he went,
And often knockt his brest, as one that did repent.
xxx
He faire the knight saluted, louting low,
Who faire him quited, as that courteous was:
And after asked him, if he did know
Of straunge adventures, which abroad did pas.
Ah my deare Sonne (quoth he) how should, alas,
Silly old man, that lives in hidden cell,
Bidding his beades all day for his trespas,
Tydings of warre and worldly trouble tell?
With holy father sits not with such things to mell.
xxxi
But if of daunger which hereby doth dwell,
And homebred evill ye desire to heare,
Of a straunge man I can you tidings tell,
That wasteth all this countrey farre and neare.
Of such (said he) I chiefly do inquere,
And shall you well reward to shew the place,
In which that wicked wight his dayes doth weare:
For to all knighthood it is foule disgrace,
That such a cursed creature lives so long a space.
xxxii
Far hence (quoth he) in wastfull wildernesse
His dwelling is, by which no living wight
May ever passe, but thorough great distresse.
Now (sayd the Lady) draweth toward night,
And well I wote, that of your later fight
Ye all forwearied be: for what so strong,
But wanting rest will also want of might?
The Sunne that measures heaven all day long,
At night doth baite his steedes the Ocean waves emong.
xxxiii
Then with the Sunne take Sir, your timely rest,
And with new day new worke at once begin:
Untroubled night they say gives counsell best.
Right well Sir knight ye have advised bin,
(Quoth then that aged man;) the way to win
Is wisely to advise: now day is spent;
Therefore with me ye may take up your In
For this same night. The knight was well content:
So with that godly father to his home they went.
xxxiv
A little lowly Hermitage it was,
Downe in a dale, hard by a forests side,
Far from resort of people, that did pas
In travell to and froe: a little wyde
There was an holy Chappell edifyde,
Wherein the Hermite dewly wont to say
His holy things each morne and eventyde:
Thereby a Christall streame did gently play,
Which from a sacred fountaine welled forth alway.
xxxv
Arrived there, the little house they fill,
Ne looke for entertainement, where none was:
Rest is their feast, and all things at their will;
The noblest mind the best contentment has.
With faire discourse the evening so they pas:
For that old man of pleasing wordes had store,
And well could file his tongue as smooth as glas;
He told of Saintes and Popes, and evermore
He strowd an Ave-Mary after and before.
xxxvi
The drouping Night thus creepeth on them fast,
And the sad humour loading their eye liddes,
As messenger of Morpheus on them cast
Sweet slombring deaw, the which to sleepe them biddes.
Unto their lodgings then his guestes he riddes:
Where when all drownd in deadly sleepe he findes,
He to his study goes, and there amiddes
His Magick bookes and artes of sundry kindes,
He seekes out mighty charmes, to trouble sleepy mindes.
xxxvii
Then choosing out few wordes most horrible,
(Let none them read) thereof did verses frame,
With which and other spelles like terrible,
He bad awake blacke Plutoes griesly Dame,
And cursed heaven, and spake reprochfull shame
Of highest God, the Lord of life and light;
A bold bad man, that dar'd to call by name
Great Gorgon, Prince of darknesse and dead night,
At which Cocytus quakes, and Styx is put to flight.
xxxviii
And forth he cald out of deepe darknesse dred
Legions of Sprights, the which like little flyes
Fluttring about his ever damned hed,
A-waite whereto their service he applyes,
To aide his friends, or fray his enimies:
Of those he chose out two, the falsest twoo,
And fittest for to forge true-seeming lyes;
The one of them he gave a message too,
The other by him selfe staide other worke to doo.
xxxix
He making speedy way through spersed ayre,
And through the world of waters wide and peepe,
To Morpheus house doth hastily repaire.
Amid the bowels of the earth full steepe,
And low, where dawning day doth never peepe,
His dwelling is; there Tethys his wet bed
Doth ever wash, and Cynthia still doth steepe
In silver deaw his ever-drouping hed,
Whiles sad Night over him her mantle black doth spred.
xl
Whose double gates he findeth locked fast,
The one faire fram'd of burnisht Yvory,
The other all with silver overcast;
And wakefull dogges before them farre do lye
Watching to banish Care their enimy,
Who oft is wont to trouble gentle Sleepe.
By them the Sprite doth passe in quietly,
And unto Morpheus comes, whom drowned deepe
In drowsie fit he findes: of nothing he takes keepe.
xli
And more, to lulle him in his slumber soft,
A trickling streame from high rocke tumbling downe
And ever-drizling raine upon the loft,
Mixt with a murmuring winde, much like the sowne
Of swarming Bees, did cast him in a swowne:
No other noyse, nor peoples troublous cryes,
As still are wont t'annoy the walled towne,
Might there be heard: but carelesse Quiet lyes,
Wrapt in eternall silence farre from enemyes.
xlii
The messenger approching to him spake,
But his wast wordes returnd to him in vaine:
So sound he slept, that nought mought him awake.
Then rudely he him thrust, and pusht with paine,
Whereat he gan to stretch: but he againe
Shooke him so hard, that forced him to speake.
As one then in a dreame, whose dryer braine
In tost with troubled sights and fancies weake,
He mumbled soft, but would not all his silence breake.
xliii
The Sprite then gan more boldly him to wake,
And threatned unto him the dreaded name
Of Hecate: whereat he gan to quake,
And lifting up his lumpish head, with blame
Halfe angry asked him, for what he came.
Hither (quoth he) me Archimago sent,
He that the stubborne Sprites can wisely tame,
He bids thee to him send for his intent
A fit false dreame, that can delude the sleepers sent.
xliv
The God obayde, and calling forth straight way
A diverse dreame out of his prison darke,
Delivered it to him, and downe did lay
His heavie head, devoide of carefull carke,
Whose sences all were straight benumbed and starke.
He backe returning by the Yvorie dore,
Remounted up as light as chearefull Larke,
And on his litle winges the dreame he bore
In hast unto his Lord, where he him left afore.
xlv
Who all this while with charmes and hidden artes,
Had made a Lady of that other Spright,
And fram'd of liquid ayre her tender partes
So lively, and so like in all mens sight,
That weaker sence it could have ravisht quight:
The maker selfe for all his wondrous witt,
Was nigh beguiled with so goodly sight:
Her all in white he clad, and over it
Cast a blacke stole, most like to seeme for Una fit.
xlvi
Now when that ydle dreame was to him brought,
Unto that Elfin knight he bad him fly,
Where he slept soundly void of evill thought
And with false shewes abuse his fantasy,
In sort as he him schooled privily:
And that new creature borne without her dew,
Full of the makers guile, with usage sly
He taught to imitate that Lady trew,
Whose semblance she did carrie under feigned hew.
xlvii
Thus well instructed, to their worke they hast,
And comming where the knight in slomber lay,
The one upon his hardy head him plast,
And made him dreame of loves and lustfull play,
That nigh his manly hart did melt away,
Bathed in wanton blis and wicked joy:
Then seemed him his Lady by him lay,
And to him playnd, how that false winged boy,
Her chast hart had subdewd, to learne Dame pleasures toy.
xlviii
And she her selfe of beautie soveraigne Queene,
Faire Venus seemde unto his bed to bring
Her, whom he waking evermore did weene,
To be the chastest flowre, that ay did spring
On earthly braunch, the daughter of a king,
Now a loose Leman to vile service bound:
And eke the Graces seemed all to sing,
Hymen {i}{_o} Hymen, dauncing all around,
While freshest Flora her with Yvie girlond crownd.
xlix
In this great passion of unwonted lust,
Or wonted feare of doing ought amis,
He started up, as seeming to mistrust
Some secret ill, or hidden foe of his:
Lo there before his face his Lady is,
Under blake stole hyding her bayted hooke,
And as halfe blushing offred him to kis,
With gentle blandishment and lovely looke,
Most like that virgin true, which for her knight him took.
l
All cleane dismayd to see so uncouth sight,
And halfe enraged at her shamelesse guise,
He thought have slaine her in his fierce despight:
But hasty heat tempring with sufferance wise,
He stayde his hand, and gan himselfe advise
To prove his sense, and tempt her faigned truth.
Wringing her hands in wemens pitteous wise,
Tho can she weepe, to stirre up gentle ruth,
Both for her noble bloud, and for her tender youth.
li
And said, Ah Sir, my liege Lord and my love,
Shall I accuse the hidden cruell fate,
And mightie causes wrought in heaven above,
Or the blind God, that doth me thus amate,
For hoped love to winne me certaine hate?
Yet thus perforce he bids me do, or die.
Die is my dew: yet rew my wretched state
You, whom my hard avenging destinie
Hath made judge of my life or death indifferently.
lii
Your owne deare sake forst me at first to leave
My Fathers kingdome, There she stopt with teares;
Her swollen hart her speach seemd to bereave,
And then againe begun, My weaker yeares
Captiv'd to fortune and frayle worldly feares,
Fly to your faith for succour and sure ayde:
Let me not dye in languor and long teares.
Why Dame (quoth he) what hath ye thus dismayd?
What frayes ye, that were wont to comfort me affrayd?
liii
Love of your selfe, she said, and deare constraint
Lets me not sleepe, but wast the wearie night
In secret anguish and unpittied plaint,
Whiles you in carelesse sleepe are drowned quight.
Her doubtfull words made that redoubted knight
Suspect her truth: yet since no'untruth he knew,
Her fawning love with foule disdainefull spight
He would not shend, but said, Deare dame I rew,
That for my sake unknowne such griefe unto you grew.
liv
Assure your selfe, it fell not all to ground;
For all so deare as life is to my hart,
I deeme your love, and hold me to you bound;
Ne let vaine feares procure your needlesse smart,
Where cause is none, but to your rest depart.
Not all content, yet seemd she to appease
Her mournefull plaintes, beguiled of her art,
And fed with words, that could not chuse but please,
So slyding softly forth, she turnd as to her ease.
lv
Long after lay he musing at her mood,
Much griev'd to think that gentle Dame so light,
For whose defence he was to shed his blood.
At last dull wearinesse of former fight
Having yrockt a sleepe his irkesome spright,
That troublous dreame gan freshly tosse his braine,
With bowres, and beds, and Ladies deare delight:
But when he saw his labour all was vaine,
With that misformed spright he backe returnd againe.
@@ -0,0 +1,201 @@
EDMUND SPENSER
from The Shepheardes Calender: April
THENOT & HOBBINOLL
Tell me good Hobbinoll, what garres thee greete?
What? hath some Wolfe thy tender Lambes ytorne?
Or is thy Bagpype broke, that soundes so sweete?
Or art thou of thy loved lasse forlorne?
Or bene thine eyes attempred to the yeare,
Quenching the gasping furrowes thirst with rayne?
Like April shoure, so stremes the trickling teares
Adowne thy cheeke, to quenche thy thristye payne.
HOBBINOLL
Nor thys, nor that, so muche doeth make me mourne,
But for the ladde, whome long I lovd so deare,
Nowe loves a lasse, that all his love doth scorne:
He plongd in payne, his tressed locks dooth teare.
Shepheards delights he dooth them all forsweare,
Hys pleasaunt Pipe, whych made us meriment,
He wylfully hath broke, and doth forbeare
His wonted songs, wherein he all outwent.
THENOT
What is he for a Ladde, you so lament?
Ys love such pinching payne to them, that prove?
And hath he skill to make so excellent,
Yet hath so little skill to brydle love?
HOBBINOLL
Colin thou kenst, the Southerne shepheardes boye:
Him Love hath wounded with a deadly darte.
Whilome on him was all my care and joye,
Forcing with gyfts to winne his wanton heart.
But now from me hys madding mynd is starte,
And woes the Widdowes daughter of the glenne:
So nowe fayre Rosalind hath bredde hys smart,
So now his frend is chaunged for a frenne.
THENOT
But if hys ditties bene so trimly dight,
I pray thee Hobbinoll, recorde some one:
The whiles our flockes doe graze about in sight,
And we close shrowded in thys shade alone.
HOBBINOLL
Contented I: then will I singe his laye
Of fayre Elisa, Queene of shepheardes all:
Which once he made, as by a spring he laye,
And tuned it unto the Waters fall.
Ye dayntye Nymphs, that in this blessed Brooke
doe bathe your brest,
Forsake your watry bowres, and hether looke,
at my request:
And eke you Virgins, that on Parnasse dwell,
Whence floweth Helicon the learned well,
Helpe me to blaze
Her worthy praise,
Which in her sexe doth all excell.
Of fayre Eliza be your silver song,
that blessed wight:
The flowre of Virgins, may shee florish long,
In princely plight.
For shee is Syrinx daughter without spotte,
Which Pan the shepheards God of her begot:
So sprong her grace
Of heavenly race,
No mortall blemishe may her blotte.
See, where she sits upon the grassie greene,
(O seemely sight)
Yclad in Scarlot like a mayden Queene,
And Ermines white.
Upon her head a Cremosin coronet,
With Damaske roses and Daffadillies set:
Bayleaves betweene,
And Primroses greene
Embellish the sweete Violet.
Tell me, have ye seene her angelick face,
Like Ph{oe}be fayre?
Her heavenly haveour, her princely grace
can you well compare?
The Redde rose medled with the White yfere,
In either cheeke depeincten lively chere.
Her modest eye,
Her Majestie,
Where have you seene the like, but there?
I sawe Ph{oe}bus thrust out his golden hedde,
upon her to gaze:
But when he sawe, how broade her beames did spredde,
it did him amaze.
He blusht to see another Sunne belowe,
Ne durst againe his fyrye face out showe:
Let him, if he dare,
His brightnesse compare
With hers, to have the overthrowe.
Shewe thy selfe Cynthia with thy silver rayes,
and be not abasht:
When shee the beames of her beauty displayes,
O how art thou dasht?
But I will not match her with Latonaes seede,
Such follie great sorow to Niobe did breede.
Now she is a stone,
And makes dayly mone,
Warning all other to take heede.
Pan may be proud, that ever he begot
such a Bellibone,
And Syrinx rejoyse, that ever was her lot
to beare such an one.
Soone as my younglings cryen for the dam,
To her will I offer a milkwhite Lamb:
Shee is my goddesse plaine,
And I her shepherds swayne,
Albee forswonck and forswatt I am.
I see Calliope speede her to the place,
where my Goddesse shines:
And after her the other Muses trace,
with their Violines.
Bene they not Bay braunches, which they doe beare,
All for Elisa in her hand to weare?
So sweetely they play,
And sing all the way,
That it a heaven is to heare.
Lo how finely the graces can it foote
to the Instrument:
They dauncen deffly, and singen soote,
in their meriment.
Wants not a fourth grace, to make the daunce even?
Let that rowme to my Lady be yeven:
She shalbe a grace,
To fyll the fourth place,
And reigne with the rest in heaven.
And whither rennes this bevie of Ladies bright,
raunged in a rowe?
They bene all Ladyes of the lake behight,
that unto her goe.
Chloris, that is the chiefest Nymph of al,
Of Olive braunches beares a Coronall:
Olives bene for peace,
When wars doe surcease:
Such for a Princesse bene principall.
Ye shepheards daughters, that dwell on the greene,
hye you there apace:
Let none come there, but that Virgins bene,
to adorne her grace.
And when you come, whereas shee is in place,
See, that your rudeness doe not you disgrace:
Binde your fillets faste,
And gird in your waste,
For more finesse, with a tawdrie lace.
Bring hether the Pincke and purple Cullambine,
With Gelliflowres:
Bring Coronations, and Sops in wine,
worne of Paramoures.
Strowe me the ground with Daffadowndillies,
And Cowslips, and Kingcups, and loved Lillies:
The pretie Pawnce,
And the Chevisaunce,
Shall match with the fayre flowre Delice.
Now ryse up Elisa, decked as thou art,
in royall aray:
And now ye daintie Damsells may depart
echeone her way,
I feare, I have troubled your troupes to longe:
Let dame Eliza thanke you for her song.
And if you come hether,
When Damsines I gether,
I will part them all you among.
THENOT
And was thilk same song of Colins owne making?
Ah foolish boy, that is with love yblent:
Great pittie is, he be in such taking,
For naught caren, that bene so lewdly bent.
HOBBINOLL
Sicker I hold him, for a greater fon,
That loves the thing, he cannot purchase.
But let us homeward: for night draweth on,
And twincling starres the daylight hence chase.
THENOTS EMBLEME
O quam te memorem virgo?
HOBBINOLLS EMBLEME
O dea certe.
@@ -0,0 +1,157 @@
EDMUND SPENSER
from The Shepheardes Calender: October
PIERCE & CUDDIE
Cuddie, for shame hold up thy heavye head,
And let us cast with what delight to chace,
And weary thys long lingring Phoebus race.
Whilome thou wont the shepheards laddes to leade,
In rymes, in ridles, and in bydding base:
Now they in thee, and thou in sleepe art dead.
CUDDY
Piers, I have pyped erst so long with payne,
That all mine Oten reedes bene rent and wore:
And my poore Muse hath spent her spared store,
Yet little good hath got, and much lesse gayne,
Such pleasaunce makes the Grashopper so poore,
And ligge so layd, when Winter doth her straine.
The dapper ditties, that I wont devise,
To feede youthes fancie, and the flocking fry,
Delighten much: what I the bett for thy?
They han the pleasure, I a sclender prise.
I beate the bush, the byrds to them doe flye:
What good thereof to Cuddie can arise?
PIERS
Cuddie, the prayse is better, then the price,
The glory eke much greater then the gayne:
O what an honor is it, to restraine
The lust of lawlesse youth with good advice:
Or pricke them forth with pleasaunce of thy vaine,
Whereto thou list their trayned willes entice.
Soone as thou gynst to sette thy notes in frame,
O how the rurall routes to thee doe cleave:
Seemeth thou dost their soule of sence bereave,
All as the shepheard, that did fetch his dame
From Plutoes balefull bowre withouten leave:
His musicks might the hellish hound did tame.
CUDDIE
So praysen babes the Peacoks spotted traine,
And wondren at bright Argus blazing eye:
But who rewards him ere the more for thy?
Or feedes him once the fuller by a graine?
Sike prayse is smoke, that sheddeth in the skye,
Sike words bene wynd, and wasten soone in vayne.
PIERS
Abandon then the base and viler clowne,
Lyft up thy selfe out of the lowly dust:
And sing of bloody Mars, of wars, of giusts.
Turne thee to those, that weld the awful crowne,
To doubted Knights, whose woundlesse armour rusts,
And helmes unbruzed wexen dayly browne.
There may thy Muse display her fluttryng wing,
And stretch her selfe at large from East to West:
Whither thou list in fayre Elisa rest,
Or if thee please in bigger notes to sing,
Advaunce the worthy whome shee loveth best,
That first the white beare to the stake did bring.
And when the stubborne stroke of stronger stounds,
Has somewhat slackt the tenor of thy string:
Of love and lustihed tho mayst thou sing,
And carrol lowde, and leade the Myllers rownde,
All were Elisa one of thilke same ring.
So mought our Cuddies name to Heaven sownde.
CUDDYE
Indeed the Romish Tityrus, I heare,
Through his Mecoenas left his Oaten reede,
Whereon he earst had taught his flocks to feede,
And laboured lands to yield the timely eare,
And eft did sing of warres and deadly drede,
So as the Heavens did quake his verse to here.
But ah Mecoenas is yclad in claye,
And great Augustus long ygoe is dead:
And all the worthies liggen wrapt in leade,
That matter made for Poets on to play:
For ever, who in derring doe were dreade,
The loftie verse of hem was loved aye.
But after vertue gan for age to stoupe,
And mighty manhode brought a bedde of ease:
The vaunting Poets found nought worth a pease,
To put in preace emong the learned troupe.
Tho gan the streames of flowing wittes to cease,
And sonnebright honour pend in shamefull coupe.
And if that any buddes of Poesie,
Yet of the old stocke gan to shoote agayne:
Or it mens follies mote be forst to fayne,
And rolle with rest in rymes of rybaudrye:
Or as it sprong, it wither must agayne:
Tom Piper makes us better melodie.
PIERS
O pierlesse Poesye, where is then thy place?
If nor in Princes pallace thou doe sitt:
(And yet is Princes pallace the most fitt)
Ne brest of baser birth doth thee embrace.
Then make thee winges of thine aspyring wit,
And, whence thou camst, flye backe to heaven apace.
CUDDIE
Ah Percy it is all to weake and wanne,
So high to sore, and make so large a flight:
Her peeced pyneons bene not so in plight,
For Colin fittes such famous flight to scanne:
He, were he not with love so ill bedight,
Would mount as high, and sing as soote as Swanne.
PIERS
Ah fon, for love does teach him climbe so hie,
And lyftes him up out of the loathsome myre:
Such immortall mirrhor, as he doth admire,
Would rayse ones mynd above the starry skie.
And cause a caytive corage to aspire,
For lofty love doth loath a lowly eye.
CUDDIE
All otherwise the state of Poet stands,
For lordly love is such a Tyranne fell:
That where he rules, all power he doth expell.
The vaunted verse a vacant head demaundes,
Ne wont with crabbed care the Muses dwell.
Unwisely weaves, that takes two webbes in hand.
Who ever casts to compasse weightye prise,
And thinks to throwe out thondring words of threate:
Let powre in lavish cups and thriftie bitts of meate,
For Bacchus fruite is frend to Phoebus wise.
And when with Wine the braine begins to sweate,
The nombers flowe as fast as spring doth ryse.
Thou kenst not Percie howe the ryme should rage.
O if my temples were distaind with wine,
And girt in girlonds of wild Yvie twine,
How I could reare the Muse on stately stage,
And teache her tread aloft in buskin fine,
With queint Bellona in her equipage.
But ah my corage cooles ere it be warme,
For thy, content us in thys humble shade:
Where no such troublous tydes han us assayde,
Here we our slender pipes may safely charme.
PIERS
And when my Gates shall han their bellies layd:
Cuddie shall have a Kidde to store his farme.
CUDDIES EMBLEME
Agitante calescimus illo
@@ -0,0 +1,24 @@
EDMUND SPENSER
Iambicum Trimetrum
Unhappy verse, the witness of my unhappy state,
Make thy self flutt'ring wings of thy fast flying
Thought, and fly forth unto my love, wheresoever she be:
Whether lying restless in heavy bed, or else
Sitting so cheerless at the cheerful board, or else
Playing alone careless on her heavenly virginals.
If in bed, tell her, that my eyes can take no rest:
If at board, tell her, that my mouth can eat no meat:
If at her virginals, tell her, I can hear no mirth.
Asked why? say: waking love suffereth no sleep:
Say that raging love doth appal the weak stomach:
Say, that lamenting love marreth the musical.
Tell her, that her pleasures were wont to lull me asleep:
Tell her, that her beauty was wont to feed mine eyes:
Tell her, that her sweet tongue was wont to make me mirth.
Now do I nightly waste, wanting my kindly rest:
Now do I daily starve, wanting my lively food:
Now do I always die, wanting thy timely mirth.
And if I waste, who will bewail my heavy chance?
And if I starve, who will record my cursed end?
And if I die, who will say: "This was Immerito"?
@@ -0,0 +1,17 @@
EDMUND SPENSER
['Joy of my life, full oft for loving you']
Joy of my life, full oft for loving you
I bless my lot, that was so lucky placed:
But then the more your own mishap I rue,
That are so much by so mean love embased.
For had the equal heavens so much you graced
In this as in the rest, ye might invent
Some heavenly wit, whose verse could have enchased
Your glorious name in golden monument.
But since ye deignd so goodly to relent
To me your thrall, in whom is little worth,
That little that I am shall all be spent
In setting your immortal praises forth;
Whose lofty argument uplifting me
Shall lift you up unto an high degree.
@@ -0,0 +1,192 @@
EDMUND SPENSER
Prothalamion
CALM was the day, and through the trembling air
Sweet breathing Zephyrus did softly play,
A gentle spirit, that lightly did delay
Hot Titan's beams, which then did glister fair;
When I whose sullen care,
Through discontent of my long fruitless stay
In prince's court, and expectation vain
Of idle hopes, which still do fly away
Like empty shadows, did afflict my brain,
Walked forth to ease my pain
Along the shore of silver streaming Thames,
Whose rutty bank, the which his river hems,
Was painted all with variable flowers,
And all the meads adorned with dainty gems,
Fit to deck maidens' bowers,
And crown their paramours,
Against the bridal day, which is not long:
Sweet Thames, run softly, till I end my song.
There, in a meadow, by the river's side,
A flock of nymphs I chanced to espy,
All lovely daughters of the flood thereby,
With goodly greenish locks, all loose untied,
As each had been a bride;
And each one had a little wicker basket,
Made of fine twigs, entrailed curiously,
In which they gathered flowers to fill their flasket,
And with fine fingers cropt full featously
The tender stalks on high.
Of every sort, which in that meadow grew,
They gathered some; the violet pallid blue,
The little daisy, that at evening closes,
The virgin lily, and the primrose true,
With store of vermeil roses,
To deck their bridegrooms' posies
Against the bridal day, which was not long:
Sweet Thames, run softly, till I end my song.
With that, I saw two swans of goodly hue
Come softly swimming down along the Lee;
Two fairer birds I yet did never see.
The snow which doth the top of Pindus strew,
Did never whiter shew,
Nor Jove himself, when he a swan would be
For love of Leda, whiter did appear:
Yet Leda was they say as white as he,
Yet not so white as these, nor nothing near.
So purely white they were,
That even the gentle stream, the which them bare,
Seemed foul to them, and bade his billows spare
To wet their silken feathers, lest they might
Soil their fair plumes with water not so fair,
And mar their beauties bright,
That shone as heaven's light,
Against their bridal day, which was not long:
Sweet Thames, run softly, till I end my song.
Eftsoons the nymphs, which now had flowers their fill,
Ran all in haste, to see that silver brood,
As they came floating on the crystal flood.
Whom when they saw, they stood amazed still,
Their wondering eyes to fill.
Them seemed they never saw a sight so fair,
Of fowls so lovely, that they sure did deem
Them heavenly born, or to be that same pair
Which through the sky draw Venus' silver team;
For sure they did not seem
To be begot of any earthly seed,
But rather angels, or of angels' breed:
Yet were they bred of Somers-heat they say,
In sweetest season, when each flower and weed
The earth did fresh array,
So fresh they seemed as day,
Even as their bridal day, which was not long:
Sweet Thames, run softly, till I end my song.
Then forth they all out of their baskets drew
Great store of flowers, the honour of the field,
That to the sense did fragrant odours yield,
All which upon those goodly birds they threw,
And all the waves did strew,
That like old Peneus' waters they did seem,
When down along by pleasant Tempe's shore,
Scattered with flowers, through Thessaly they stream,
That they appear through lilies' plenteous store,
Like a bride's chamber floor.
Two of those nymphs meanwhile, two garlands bound,
Of freshest flowers which in that mead they found,
The which presenting all in trim array,
Their snowy foreheads therewithal they crowned,
Whilst one did sing this lay,
Prepared against that day,
Against their bridal day, which was not long:
Sweet Thames, run softly, till I end my song.
'Ye gentle birds, the world's fair ornament,
And heaven's glory, whom this happy hour
Doth lead unto your lovers' blissful bower,
Joy may you have and gentle heart's content
Of your love's complement:
And let fair Venus, that is queen of love,
With her heart-quelling son upon you smile,
Whose smile, they say, hath virtue to remove
All love's dislike, and friendship's faulty guile
For ever to assoil.
Let endless peace your steadfast hearts accord,
And blessed plenty wait upon your board,
And let your bed with pleasures chaste abound,
That fruitful issue may to you afford,
Which may your foes confound,
And make your joys redound
Upon your bridal day, which is not long:
Sweet Thames, run softly, till I end my song.'
So ended she; and all the rest around
To her redoubled that her undersong,
Which said their bridal day should not be long.
And gentle echo from the neighbour ground
Their accents did resound.
So forth those joyous birds did pass along,
Adown the Lee, that to them murmured low,
As he would speak, but that he lacked a tongue,
Yet did by signs his glad affection show,
Making his stream run slow.
And all the fowl which in his flood did dwell
Gan flock about these twain, that did excel
The rest so far as Cynthia doth shend
The lesser stars. So they, enranged well,
Did on those two attend,
And their best service lend,
Against their wedding day, which was not long:
Sweet Thames, run softly, till I end my song.
At length they all to merry London came,
To merry London, my most kindly nurse,
That to me gave this life's first native source;
Though from another place I take my name,
An house of ancient fame.
There when they came, whereas those bricky towers,
The which on Thames' broad aged back do ride,
Where now the studious lawyers have their bowers
There whilom wont the Templar Knights to bide,
Till they decayed through pride:
Next whereunto there stands a stately place,
Where oft I gained gifts and goodly grace
Of that great lord, which therein wont to dwell,
Whose want too well now feels my friendless case.
But ah, here fits not well
Old woes but joys to tell
Against the bridal day, which is not long:
Sweet Thames, run softly, till I end my song.
Yet therein now doth lodge a noble peer,
Great England's glory, and the world's wide wonder,
Whose dreadful name late through all Spain did thunder,
And Hercules' two pillars standing near
Did make to quake and fear:
Fair branch of honour, flower of chivalry,
That fillest England with thy triumph's fame,
Joy have thou of thy noble victory,
And endless happiness of thine own name
That promiseth the same:
That through thy prowess and victorious arms,
Thy country may be freed from foreign harms;
And great Elisa's glorious name may ring
Through all the world, filled with thy wide alarms,
Which some brave Muse may sing
To ages following,
Upon the bridal day, which is not long:
Sweet Thames, run softly, till I end my song.
From those high towers this noble lord issuing,
Like radiant Hesper when his golden hair
In th'Ocean billows he hath bathed fair,
Descended to the river's open viewing,
With a great train ensuing.
Above the rest were goodly to be seen
Two gentle knights of lovely face and feature
Beseeming well the bower of any queen,
With gifts of wit and ornaments of nature,
Fit for so goodly stature;
That like the twins of Jove they seemed in sight,
Which deck the baldric of the heavens bright.
They two forth pacing to the river's side,
Received those two fair birds, their love's delight;
Which, at th' appointed tide,
Each one did make his bride
Against their bridal day, which is not long:
Sweet Thames, run softly, till I end my song.
@@ -0,0 +1,113 @@
EDMUND SPENSER
The Shepheardes Calender: January
Januarie. gloga prima. ARGVMENT.
IN this fyrst glogue Colin clout a shepheardes boy complaineth him of his vnfortunate loue, being but newly (as semeth) enamoured of a countrie lasse called Rosalinde: with which strong affection being very sore traueled, he compareth his carefull case to the sadde season of the yeare, to the frostie ground, to the frosen trees, and to his owne winterbeaten flocke. And lastlye, fynding himselfe robbed of all former pleasaunce and delights, hee breaketh his Pipe in peeces, and casteth him selfe to the ground.
COLIN Cloute.
A Shepeheards boye (no better doe him call)
when Winters wastful spight was almost spent,
All in a sunneshine day, as did befall,
Led forth his flock, that had been long ypent.
So faynt they woxe, and feeble in the folde,
That now vnnethes their feete could them vphold.
All as the Sheepe, such was the shepeheards looke,
For pale and wanne he was, (alas the while,)
May seeme he lovd, or els some care he tooke:
Well couth he tune his pipe, and frame his stile.
Tho to a hill his faynting flocke he ledde,
And thus him playnd, the while his shepe there fedde.
Ye gods of loue, that pitie louers payne,
(if any gods the paine of louers pitie:)
Looke from aboue, where you in ioyes remaine,
And bowe your eares vnto my doleful dittie.
And Pan thou shepheards God, that once didst loue,
Pitie the paines, that thou thy selfe didst proue.
Thou barrein ground, whome winters wrath hath wasted,
Art made a myrrhour, to behold my plight:
Whilome thy fresh spring flowrd, and after hasted
Thy sommer prowde with Daffadillies dight.
And now is come thy wynters stormy state,
Thy mantle mard, wherein thou mas-kedst late.
Such rage as winters, reigneth in my heart,
My life bloud friesing wtih vnkindly cold:
Such stormy stoures do breede my balefull smarte,
As if my yeare were wast, and woxen old.
And yet alas, but now my spring begonne,
And yet alas, yt is already donne.
You naked trees, whose shady leaves are lost,
Wherein the byrds were wont to build their bowre:
And now are clothd with mosse and hoary frost,
Instede of bloosmes, wherwith your buds did flowre:
I see your teares, that from your boughes doe raine,
Whose drops in drery ysicles remaine.
All so my lustfull leafe is drye and sere,
My timely buds with wayling all are wasted:
The blossome, which my braunch of youth did beare,
With breathed sighes is blowne away, & blasted,
And from mine eyes the drizling teares descend,
As on your boughes the ysicles depend.
Thou feeble flocke, whose fleece is rough and rent,
Whose knees are weak through fast and evill fare:
Mayst witnesse well by thy ill gouernement,
Thy maysters mind is ouercome with care.
Thou weak, I wanne: thou leabe, I quite forlorne:
With mourning pyne I, you with pyning mourne.
A thousand sithes I curse that carefull hower,
Wherein I longd the neighbour towne to see:
And eke tenne thousand sithes I blesse the stoure,
Wherein I sawe so fayre a sight, as shee.
Yet all for naught: snch [such] sight hath bred my bane.
Ah God, that loue should breede both ioy and payne.
It is not Hobbinol, wherefore I plaine,
Albee my loue he seeke with dayly suit:
His clownish gifts and curtsies I disdaine,
His kiddes, his cracknelles, and his early fruit.
Ah foolish Hobbinol, thy gyfts bene vayne:
Colin them gives to Rosalind againe.
I loue thilke lasse, (alas why doe I loue?)
And am forlorne, (alas why am I lorne?)
Shee deignes not my good will, but doth reproue,
And of my rurall musick holdeth scorne.
Shepheards deuise she hateth as the snake,
And laughes the songes, that Colin Clout doth make.
Wherefore my pype, albee rude Pan thou please,
Yet for thou pleasest not, where most I would:
And thou vnlucky Muse, that wontst to ease
My musing mynd, yet canst not, when thou should:
Both pype and Muse, shall sore the while abye.
So broke his oaten pype, and downe dyd lye.
By that, the welked Phoebus gan availe,
His weary waine, and nowe the frosty Night
Her mantle black through heauen gan overhaile.
Which seene, the pensife boy halfe in despight
Arose, and homeward drove his sonned sheepe,
Whose hanging heads did seeme his carefull case to weepe.
@@ -0,0 +1,26 @@
ELINOR WYLIE
Full Moon
My bands of silk and miniver
Momently grew heavier;
The black gauze was beggarly thin;
The ermine muffled mouth and chin;
I could not suck the moonlight in.
Harlequin in lozenges
Of love and hate, I walked in these
Striped and ragged rigmaroles;
Along the pavement my footsoles
Trod warily on living coals.
Shouldering the thoughts I loathed,
In their corrupt disguises clothed,
Morality I could not tear
From my ribs, to leave them bare
Ivory in silver air.
There I walked, and there I raged;
The spiritual savage caged
Within my skeleton, raged afresh
To feel, behind a carnal mesh,
The clean bones crying in the flesh.
@@ -0,0 +1,37 @@
ELINOR WYLIE
Valentine
Too high, too high to pluck
My heart shall swing.
A fruit no bee shall suck,
No wasp shall sting.
If on some night of cold
It falls to ground
In apple-leaves of gold
Ill wrap it round.
And I shall seal it up
With spice and salt,
In a carven silver cup,
In a deep vault.
Before my eyes are blind
And my lips mute,
I must eat core and rind
Of that same fruit.
Before my heart is dust
At the end of all,
Eat it I must, I must
Were it bitter gall.
But I shall keep it sweet
By some strange art;
Wild honey I shall eat
When I eat my heart.
O honey cool and chaste
As clovers breath!
Sweet Heaven I shall taste
Before my death.
@@ -0,0 +1,76 @@
ELINOR WYLIE
Wild Peaches
1
When the world turns completely upside down
You say well emigrate to the Eastern Shore
Aboard a river-boat from Baltimore;
Well live among wild peach trees, miles from town,
Youll wear a coonskin cap, and I a gown
Homespun, dyed butternuts dark gold color.
Lost, like your lotus-eating ancestor,
Well swim in milk and honey till we drown.
The winter will be short, the summer long,
The autumn amber-hued, sunny and hot,
Tasting of cider and of scuppernong;
All seasons sweet, but autumn best of all.
The squirrels in their silver fur will fall
Like falling leaves, like fruit, before your shot.
2
The autumn frosts will lie upon the grass
Like bloom on grapes of purple-brown and gold.
The misted early mornings will be cold;
The little puddles will be roofed with glass.
The sun, which burns from copper into brass,
Melts these at noon, and makes the boys unfold
Their knitted mufflers; full as they can hold
Fat pockets dribble chestnuts as they pass.
Peaches grow wild, and pigs can live in clover;
A barrel of salted herrings lasts a year;
The spring begins before the winters over.
By February you may find the skins
Of garter snakes and water moccasins
Dwindled and harsh, dead-white and cloudy-clear.
3
When April pours the colors of a shell
Upon the hills, when every little creek
Is shot with silver from the Chesapeake
In shoals new-minted by the ocean swell,
When strawberries go begging, and the sleek
Blue plums lie open to the blackbirds beak,
We shall live well we shall live very well.
The months between the cherries and the peaches
Are brimming cornucopias which spill
Fruits red and purple, sombre-bloomed and black;
Then, down rich fields and frosty river beaches
Well trample bright persimmons, while you kill
Bronze partridge, speckled quail, and canvasback.
4
Down to the Puritan marrow of my bones
Theres something in this richness that I hate.
I love the look, austere, immaculate,
Of landscapes drawn in pearly monotones.
Theres something in my very blood that owns
Bare hills, cold silver on a sky of slate,
A thread of water, churned to milky spate
Streaming through slanted pastures fenced with stones.
I love those skies, thin blue or snowy gray,
Those fields sparse-planted, rendering meagre sheaves;
That spring, briefer than apple-blossoms breath,
Summer, so much too beautiful to stay,
Swift autumn, like a bonfire of leaves,
And sleepy winter, like the sleep of death.
@@ -0,0 +1,160 @@
FORD MADOX FORD
In October 1914 [Antwerp]
I
GLOOM!
An October like November;
August a hundred thousand hours,
And all September,
A hundred thousand, dragging sunlit days,
And half October like a thousand years . . .
And doom!
That then was Antwerp. . .
In the name of God,
How could they do it?
Those souls that usually dived
Into the dirty caverns of mines;
Who usually hived
In whitened hovels; under ragged poplars;
Who dragged muddy shovels, over the grassy mud,
Lumbering to work over the greasy sods. . .
Those men there, with the appearance of clods
Were the bravest men that a usually listless priest of God
Ever shrived. . .
And it is not for us to make them an anthem.
If we found words there would come no wind that would fan them
To a tune that the trumpets might blow it,
Shrill through the heaven that's ours or yet Allah's,
Or the wide halls of any Valhallas.
We can make no such anthem. So that all that is ours
For inditing in sonnets, pantoums, elegiacs, or lays
Is this:
In the name of God, how could they do it?
II
For there is no new thing under the sun,
Only this uncomely man with a smoking gun
In the gloom. . .
What the devil will he gain by it?
Digging a hole in the mud and standing all day in the rain by it
Waiting his doom;
The sharp blow, the swift outpouring of the blood,
Till the trench of gray mud
Is turned to a brown purple drain by it.
Well, there have been scars
Won in many wars . . .
Punic,
Lacedmonian, wars of Napoleon, wars for faith, wars for honour, for love, for possession,
But this Belgian man in his ugly tunic,
His ugly round cap, shooting on, in a sort of obsession,
Overspreading his miserable land,
Standing with his wet gun in his hand . . .
Doom!
He finds that in a sudden scrimmage,
And lies, an unsightly lump on the sodden grass . . .
An image that shall take long to pass!
III
For the white-limbed heroes of Hellas ride by upon their horses
Forever through our brains.
The heroes of Cressy ride by upon their stallions;
And battalions and battalions and battalions
The Old Guard, the Young Guard, the men of Minden and of Waterloo,
Pass, for ever staunch,
Stand, for ever true;
And the small man with the large paunch,
And the gray coat, and the large hat, and the hands behind the back,
Watches them pass
In our minds for ever . . .
But that clutter of sodden corses
On the sodden Belgian grass
That is a strange new beauty.
IV
With no especial legends of marchings or triumphs or duty,
Assuredly that is the way of it,
The way of beauty . . .
And that is the highest word you can find to say of it.
For you cannot praise it with words
Compounded of lyres and swords,
But the thought of the gloom and the rain
And the ugly coated figure, standing beside a drain,
Shall eat itself into your brain:
And you will say of all heroes, They fought like the Belgians!
And you will say: He wrought like a Belgian his fate out of gloom.
And you will say: He bought like a Belgian his doom.
And that shall be an honourable name;
Belgian shall be an honourable word;
As honourable as the fame of the sword,
As honourable as the mention of the many-chorded lyre,
And his old coat shall seem as beautiful as the fabrics woven in Tyre.
V
And what in the world did they bear it for?
I don't know.
And what in the world did they dare it for?
Perhaps that is not for the likes of me to understand.
They could very well have watched a hundred legions go
Over their fields and between their cities
Down into more southerly regions.
They could very well have let the legions pass through their woods,
And have kept their lives and their wives and their children and cattle and goods.
I don't understand.
Was it just love of their land?
Oh, poor dears!
Can any man so love his land?
Give them a thousand thousand pities
And rivers and rivers of tears
To wash off the blood from the cities of Flanders.
VI
This is Charing Cross;
It is midnight;
There is a great crowd
And no light.
A great crowd, all black that hardly whispers aloud.
Surely, that is a dead womana dead mother!
She has a dead face;
She is dressed all in black;
She wanders to the bookstall and back,
At the back of the crowd;
And back again and again back,
She sways and wanders.
This is Charing Cross;
It is one o'clock.
There is still a great cloud, and very little light;
Immense shafts of shadows over the black crowd
That hardly whispers aloud. . .
And now! . . That is another dead mother,
And there is another and another and another. . .
And little children, all in black,
All with dead faces, waiting in all the waiting-places,
Wandering from the doors of the waiting-room
In the dim gloom.
These are the women of Flanders.
They await the lost.
They await the lost that shall never leave the dock;
They await the lost that shall never again come by the train
To the embraces of all these women with dead faces;
They await the lost who lie dead in trench and barrier and foss,
In the dark of the night.
This is Charing Cross; it is past one of the clock;
There is very little light.
There is so much pain.
LEnvoi
And it was for this that they endured this gloom;
This October like November,
That August like a hundred thousand hours,
And that September,
A hundred thousand dragging sunlit days,
And half October like a thousand years. . .
Oh, poor dears!
@@ -0,0 +1,17 @@
GEORGE CHAPMAN
A Coronet for his Mistress, Philosophy
Muses that sing love's sensual empery,
And lovers kindling your enraged fires
At Cupid's bonfires burning in the eye,
Blown with the empty breath of vain desires;
You that prefer the painted cabinet
Before the wealthy jewels it doth store ye,
That all your joys in dying figures set,
And stain the living substance of your glory;
Abjure those joys, abhor their memory,
And let my love the honour'd subject be
Of love, and honour's complete history.
Your eyes were never yet let in to see
The majesty and riches of the mind,
But dwell in darkness; for your god is blind.
@@ -0,0 +1,20 @@
GEORGE CHAPMAN
Bridal Song
O come, soft rest of cares! come, Night!
Come, naked Virtues only tire,
The reaped harvest of the light
Bound up in sheaves of sacred fire,
Love calls to war:
Sighs his alarms,
Lips his swords are,
The fields his arms.
Come, Night, and lay thy velvet hand
On glorious Days outfacing face;
And all thy crowned flames command
For torches to our nuptial grace.
Love calls to war:
Sighs his alarms,
Lips his swords are,
The field his arms.
@@ -0,0 +1,32 @@
GEORGE GASCOIGNE
And If I Did, What Then?
And if I did, what then?
Are you aggrievd therefore?
The sea hath fish for every man,
And what would you have more?
Thus did my mistress once,
Amaze my mind with doubt;
And poppd a question for the nonce
To beat my brains about.
Whereto I thus replied:
Each fisherman can wish
That all the seas at every tide
Were his alone to fish.
And so did I (in vain)
But since it may not be,
Let such fish there as find the gain,
And leave the loss for me.
And with such luck and loss
I will content myself,
Till tides of turning time may toss
Such fishers on the shelf.
And when they stick on sands,
That every man may see,
Then will I laugh and clap my hands,
As they do now at me.
@@ -0,0 +1,44 @@
GEORGE GASCOIGNE
Fie, Pleasure, Fie!
Fie pleasure, fie! thou cloyest me with delight,
Thou fillst my mouth with sweetmeats overmuch;
I wallow still in joy both day and night:
I deem, I dream, I do, I taste, I touch,
No thing but all that smells of perfect bliss;
Fie pleasure, fie! I cannot like of this.
To taste (sometimes) a bait of bitter gall,
To drink a draught of sour ale (some season)
To eat brown bread with homely hands in hall,
Doth much increase mens appetites, by reason,
And makes the sweet more sugard that ensues,
Since minds of men do still seek after news.
The pamperd horse is seldom seen in breath,
Whose manger makes his grace (oftimes) to melt;
The crammed fowl comes quickly to his death;
Such colds they catch in hottest haps that swelt;
And I (much like) in pleasure scawled still,
Do fear to starve although I feed my fill.
It might suffice that Love hath built his bower
Between my ladys lively shining eyes;
It were enough that beautys fading flower
Grows ever fresh with her in heavenly wise;
It had been well that she were fair of face,
And yet not rob all other dames of grace.
To muse in mind, how wise, how fair, how good,
How brave, how frank, how courteous, and how true
My lady is, doth but inflame my blood
With humours such as bid my health adieu;
Since hap always when it is clomb on high,
Doth fall full low, though erst it reachd the sky.
Lo, pleasure, lo! lo thus I lead a life
That laughs for joy, and trembleth oft for dread;
Thy pangs are such as call for changes knife
To cut the twist, or else to stretch the thread,
Which holds yfeer the bundle of my bliss:
Fie, pleasure, fie! I dare not trust to this.
@@ -0,0 +1,17 @@
GEORGE GASCOIGNE
For That He Looked Not upon Her
You must not wonder, though you think it strange,
To see me hold my louring head so low,
And that mine eyes take no delight to range
About the gleams which on your face do grow.
The mouse which once hath broken out of trap
Is seldom ticed with the trustless bait,
But lies aloof for fear of more mishap,
And feedeth still in doubt of deep deceit.
The scorched fly, which once hath scaped the flame,
Will hardly come to play again with fire,
Whereby I learn that grievous is the game
Which follows fancy dazzled by desire:
So that I wink or else hold down my head,
Because your blazing eyes my bale have bred.
@@ -0,0 +1,56 @@
GEORGE GASCOIGNE
The Lullaby of a Lover
Sing lullaby, as women do,
Wherewith they bring their babes to rest,
And lullaby can I sing too
As womanly as can the best.
With lullaby they still the child,
And if I be not much beguiled,
Full many wanton babes have I
Which must be stilled with lullaby.
First lullaby my youthful years;
It is now time to go to bed,
For crooked age and hoary hairs
Have won the haven within my head.
With lullaby, then, youth be still;
With lullaby content thy will;
Since courage quails and comes behind,
Go sleep, and so beguile thy mind.
Next, lullaby my gazing eyes,
Which wonted were to glance apace.
For every glass may now suffice
To show the furrows in my face;
With lullaby then wink awhile,
With lullaby your looks beguile;
Let no fair face nor beauty bright
Entice you eft with vain delight.
And lullaby, my wanton will;
Let reason's rule now reign thy thought,
Since all too late I find by skill
How dear I have thy fancies bought;
With lullaby now take thine ease,
With lullaby thy doubts appease.
For trust to this: if thou be still,
My body shall obey thy will.
Eke lullaby, my loving boy,
My little Robin, take thy rest;
Since age is cold and nothing coy,
Keep close thy coin, for so is best;
With lullaby be thou content,
With lullaby thy lusts relent,
Let others pay which hath mo pence;
Thou art too poor for such expense.
Thus lullaby, my youth, mine eyes,
My will, my ware, and all that was.
I can no mo delays devise,
But welcome pain, let pleasure pass;
With lullaby now take your leave,
With lullaby your dreams deceive;
And when you rise with waking eye,
Remember then this lullaby.
@@ -0,0 +1,53 @@
GEORGE SANTAYANA
Before a Statue of Achilles
I
Behoild Pelides with his yellow hair,
Proud child of Thetis, hero loved of Jove;
Above the frowning of his brows of wove
A crown of gold, well combed, with Spartan care.
Who might have seen him, sullen, great, and fair,
As with the wrongful world he proudly strove,
And by high deeds his wilder passion shrove,
Mastering love, resentment, and despair.
He knew his end, and Phoebus arrow sure
He braved for fame immortal and a friend,
Despising life; and we, who know our end,
Know that in our decay he shall endure
And all our childrens hearts to grief inure,
With whose first bitter battles his shall blend.
II
Who brought thee forth, immortal vision, who
In Phthia or in Tempe brought thee forth?
Out of the sunlight and the sapful earth
What god the simples of thy spirit drew?
A goddess rose from the green waves, and threw
Her arms about a king, to give thee birth;
A centaur, patron of thy boyish mirth,
Over the meadows in thy footsteps flew.
Now Thessaly forgets thee, and the deep
Thy keeled bark furrowed answers not thy prayer;
But far away new generations keep
Thy laurels fresh; where branching Isis hems
The lawns of Oxford round about, or where
Enchanted Eton sits by pleasant Thames.
III
I gaze on thee as Phidias of old
Or Polyclitus gazed, when first he saw
These hard and shining limbs, without a flaw,
And cast his wonder in heroic mould.
Unhappy me who only may behold,
Nor make immutable and fix in awe
A fair immortal form no worm shall gnaw,
A tempered mind whose faith was never told!
The godlike mien, the lions lock and eye,
The well-knit sinew, utter a brave heart
Better than many words that part by part
Spell in strange symbols what serene and whole
In nature lives, nor can in marble die.
The perfect body itself the soul.

Some files were not shown because too many files have changed in this diff Show More