From 5d6a7d602788d7176d156bd7d33658d83d2c2458 Mon Sep 17 00:00:00 2001 From: Rafael Aguayo Date: Tue, 4 Jun 2019 11:25:21 -0700 Subject: [PATCH] bootstrap basic docs --- AUTHORS.md | 15 ++ AUTHORS.rst | 13 -- CHANGELOG.md | 71 ++++++++ CONTRIBUTING.md | 101 +++++++++++ CONTRIBUTING.rst | 112 ------------ HISTORY.rst | 8 - MANIFEST.in | 4 + README.md | 2 - docs/authors.rst | 5 +- docs/changelog.rst | 3 + docs/conf.py | 156 +++++++++++------ docs/contributing.rst | 2 +- docs/dev/concepts_and_definitions.rst | 55 ++++++ docs/dev/data_syncing.rst | 56 ++++++ docs/dev/fast_forward.rst | 15 ++ docs/dev/img/FSM.png | Bin 0 -> 17629 bytes docs/dev/img/fast_forward.png | Bin 0 -> 11387 bytes docs/dev/img/merge_conflict.png | Bin 0 -> 9088 bytes docs/dev/img/operations.png | Bin 0 -> 25013 bytes docs/dev/img/pull_request.png | Bin 0 -> 9713 bytes docs/dev/img/push_request.png | Bin 0 -> 10490 bytes docs/dev/img/record_max_counters.png | Bin 0 -> 14603 bytes docs/dev/img/sync_process.png | Bin 0 -> 27192 bytes docs/dev/index.rst | 38 ++++ docs/dev/merge_conflict.rst | 16 ++ docs/history.rst | 1 - docs/index.rst | 23 +-- docs/installation.rst | 51 ------ docs/make.bat | 242 -------------------------- docs/usage.rst | 7 - morango/settings.py | 121 +++++++++++++ tox.ini | 3 +- 32 files changed, 609 insertions(+), 511 deletions(-) create mode 100644 AUTHORS.md delete mode 100644 AUTHORS.rst create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md delete mode 100644 CONTRIBUTING.rst delete mode 100644 HISTORY.rst create mode 100644 docs/changelog.rst create mode 100644 docs/dev/concepts_and_definitions.rst create mode 100644 docs/dev/data_syncing.rst create mode 100644 docs/dev/fast_forward.rst create mode 100755 docs/dev/img/FSM.png create mode 100755 docs/dev/img/fast_forward.png create mode 100755 docs/dev/img/merge_conflict.png create mode 100755 docs/dev/img/operations.png create mode 100755 docs/dev/img/pull_request.png create mode 100755 docs/dev/img/push_request.png create mode 100755 docs/dev/img/record_max_counters.png create mode 100755 docs/dev/img/sync_process.png create mode 100644 docs/dev/index.rst create mode 100644 docs/dev/merge_conflict.rst delete mode 100644 docs/history.rst delete mode 100644 docs/installation.rst delete mode 100644 docs/make.bat delete mode 100644 docs/usage.rst create mode 100644 morango/settings.py diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 00000000..b5aa9455 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,15 @@ +# Credits + +## Development Lead and Copyright Holder + +Learning Equality – info@learningequality.org + +## Community + +Please feel free to add your name to this list if you make a PR + +* Rafael Aguayo (ralphiee22) +* Jamie Alexandre (jamalex) +* Benjamin Bach (benjaoming) +* Jose Rodriguez (jredrejo) +* Aron Asor (aronasorman) diff --git a/AUTHORS.rst b/AUTHORS.rst deleted file mode 100644 index e79cb0a4..00000000 --- a/AUTHORS.rst +++ /dev/null @@ -1,13 +0,0 @@ -======= -Credits -======= - -Development Lead ----------------- - -* Learning Equality - -Contributors ------------- - -None yet. Why not be the first? diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..8007a9f3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,71 @@ +Release Notes +============= + +List of the most important changes for each release. + +## 0.4.5 + +- fixes issue where GET requests with body payload fails + +## 0.4.4 + +- adds gzipping capability on buffer post requests +- parametrizes chunk size to allow it to be set when initiating sync sessions + +## 0.4.3 + +- remove unused files in dist + +## 0.4.2 + +- Added fix for writing CACHE file on windows + +## 0.4.1 + +- Added fix for writing CACHE file to user directory + +## 0.4.0 + +- Added inverse CSR endpoints for pushing data to a server +- various performance improvements +- allow for hard deletion which purges data and is able to propagate to other devices + +## 0.3.3 + +- Add transactions around queuing into buffer and dequeuing into store + +## 0.3.2 + +- Mute signals before deserialization/saving store models + +## 0.3.1 + +- removed logic of loading scope definition fixtures (delegated to main application) + +## 0.3.0 + +- added support for postgres database backend + +## 0.2.4 + +## 0.2.3 + +## 0.2.2 + +## 0.2.1 + +## 0.2.0 + +## 0.1.1 + +## 0.1.0 + +- First working version for morango + +## 0.0.2: content-curation compatibility! + +- make requirements more flexible + +## 0.0.1: the initial release! + +- Add in model name to uuid calc. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..0d7693db --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,101 @@ +# Contributing + +Contributions are welcome, and they are greatly appreciated\! Every +little bit helps, and credit will always be given. + +You can contribute in many ways: + +## Types of Contributions + +### Report Bugs + +Report bugs at . + +If you are reporting a bug, please include: + + - Your operating system name and version. + - Any details about your local setup that might be helpful in + troubleshooting. + - Detailed steps to reproduce the bug. + +### Fix Bugs + +Look through the GitHub issues for bugs. Anything tagged with "bug" and +"help wanted" is open to whoever wants to implement it. + +### Implement Features + +Look through the GitHub issues for features. Anything tagged with +"enhancement" and "help wanted" is open to whoever wants to implement +it. + +### Write Documentation + +morango could always use more documentation, whether as part of the +official morango docs, in docstrings, or even on the web in blog posts, +articles, and such. + +### Submit Feedback + +The best way to send feedback is to file an issue at +. + +If you are proposing a feature: + + - Explain in detail how it would work. + - Keep the scope as narrow as possible, to make it easier to + implement. + +## Get Started\! + +Ready to contribute? Here's how to set up +morango for local development. + +1. Fork the morango repo on GitHub. + +2. Clone your fork locally: + + $ git clone git@github.com:your_name_here/morango.git + +3. Install your local copy into a virtualenv. Assuming you have + virtualenvwrapper installed, this is how you set up your fork for + local development: + + $ mkvirtualenv morango + $ cd morango/ + $ python setup.py develop + +4. Create a branch for local development: + + $ git checkout -b name-of-your-bugfix-or-feature + + Now you can make your changes locally. + +5. When you're done making changes, check that your changes pass flake8 + and the tests, including testing other Python versions with tox: + + $ flake8 morango tests + $ python setup.py test or py.test + $ tox + + To get flake8 and tox, just pip install them into your virtualenv. + +6. Commit your changes and push your branch to GitHub: + + $ git add . + $ git commit -m "Your detailed description of your changes." + $ git push origin name-of-your-bugfix-or-feature + +7. Submit a pull request through the GitHub website. + +## Pull Request Guidelines + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests. +2. If the pull request adds functionality, the docs should be updated. + Put your new functionality into a function with a docstring, and add + the feature to the list in README.rst. +3. The pull request should work for Python 2.7, 3.4 and 3.5. Check + and + make sure that the tests pass for all supported Python versions. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 7832c2c3..00000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,112 +0,0 @@ -.. highlight:: shell - -============ -Contributing -============ - -Contributions are welcome, and they are greatly appreciated! Every -little bit helps, and credit will always be given. - -You can contribute in many ways: - -Types of Contributions ----------------------- - -Report Bugs -~~~~~~~~~~~ - -Report bugs at https://github.com/learningequality/morango/issues. - -If you are reporting a bug, please include: - -* Your operating system name and version. -* Any details about your local setup that might be helpful in troubleshooting. -* Detailed steps to reproduce the bug. - -Fix Bugs -~~~~~~~~ - -Look through the GitHub issues for bugs. Anything tagged with "bug" -and "help wanted" is open to whoever wants to implement it. - -Implement Features -~~~~~~~~~~~~~~~~~~ - -Look through the GitHub issues for features. Anything tagged with "enhancement" -and "help wanted" is open to whoever wants to implement it. - -Write Documentation -~~~~~~~~~~~~~~~~~~~ - -morango could always use more documentation, whether as part of the -official morango docs, in docstrings, or even on the web in blog posts, -articles, and such. - -Submit Feedback -~~~~~~~~~~~~~~~ - -The best way to send feedback is to file an issue at https://github.com/learningequality/morango/issues. - -If you are proposing a feature: - -* Explain in detail how it would work. -* Keep the scope as narrow as possible, to make it easier to implement. - -Get Started! ------------- - -Ready to contribute? Here's how to set up `morango` for local development. - -1. Fork the `morango` repo on GitHub. -2. Clone your fork locally:: - - $ git clone git@github.com:your_name_here/morango.git - -3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: - - $ mkvirtualenv morango - $ cd morango/ - $ python setup.py develop - -4. Create a branch for local development:: - - $ git checkout -b name-of-your-bugfix-or-feature - - Now you can make your changes locally. - -5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: - - $ flake8 morango tests - $ python setup.py test or py.test - $ tox - - To get flake8 and tox, just pip install them into your virtualenv. - -6. Commit your changes and push your branch to GitHub:: - - $ git add . - $ git commit -m "Your detailed description of your changes." - $ git push origin name-of-your-bugfix-or-feature - -7. Submit a pull request through the GitHub website. - -Pull Request Guidelines ------------------------ - -Before you submit a pull request, check that it meets these guidelines: - -1. The pull request should include tests. -2. If the pull request adds functionality, the docs should be updated. Put - your new functionality into a function with a docstring, and add the - feature to the list in README.rst. -3. The pull request should work for Python 2.7, 3.4 and 3.5. Check - https://travis-ci.org/learningequality/morango/pull_requests - and make sure that the tests pass for all supported Python versions. - -Tips ----- - -To run a subset of tests:: - - - $ python -m unittest tests.test_morango diff --git a/HISTORY.rst b/HISTORY.rst deleted file mode 100644 index 7284b267..00000000 --- a/HISTORY.rst +++ /dev/null @@ -1,8 +0,0 @@ -======= -History -======= - -0.1.0 (2016-09-16) ------------------- - -* First release on PyPI. diff --git a/MANIFEST.in b/MANIFEST.in index ba17b888..7751014a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,7 @@ +include AUTHORS.md +include CONTRIBUTING.md +include CHANGELOG.md +include LICENSE include README.md include requirements.txt diff --git a/README.md b/README.md index 57963b20..ef75784a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ # Morango [![image](https://img.shields.io/travis/learningequality/morango.svg)](https://travis-ci.org/learningequality/morango) - [![image](http://codecov.io/github/learningequality/morango/coverage.svg?branch=master)](http://codecov.io/github/learningequality/morango?branch=master) - [![image](https://readthedocs.org/projects/morango/badge/?version=latest)](http://morango.readthedocs.org/en/latest/) Pure Python Django DB replication engine. diff --git a/docs/authors.rst b/docs/authors.rst index e122f914..5f2eec2b 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -1 +1,4 @@ -.. include:: ../AUTHORS.rst +.. _authors: + + +.. mdinclude:: ../AUTHORS.md diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 00000000..932b7e3b --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1,3 @@ +.. _changelog: + +.. mdinclude:: ../CHANGELOG.md diff --git a/docs/conf.py b/docs/conf.py index d560258f..a6fdb65b 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,15 +12,19 @@ # # All configuration values have a default; values that are commented out # serve to show the default. - -import sys +import inspect import os +import sys + +import django +from django.utils.encoding import force_text +from django.utils.html import strip_tags # If extensions (or modules to document with autodoc) are in another # directory, add these directories to sys.path here. If the directory is # relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # Get the project root dir, which is the parent dir of this cwd = os.getcwd() @@ -31,31 +35,71 @@ # version is used. sys.path.insert(0, project_root) -import morango +import morango # noqa -# -- General configuration --------------------------------------------- +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "morango.settings") + +django.setup() + +# Auto list fields from django models - from https://djangosnippets.org/snippets/2533/#c5977 +def process_docstring(app, what, name, obj, options, lines): + # This causes import errors if left outside the function + from django.db import models + + # Only look at objects that inherit from Django's base model class + if inspect.isclass(obj) and issubclass(obj, models.Model): + # Grab the field list from the meta class + fields = obj._meta.get_fields() + + for field in fields: + # Skip ManyToOneRel and ManyToManyRel fields which have no 'verbose_name' or 'help_text' + if not hasattr(field, 'verbose_name'): + continue -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' + # Decode and strip any html out of the field's help text + help_text = strip_tags(force_text(field.help_text)) + + # Decode and capitalize the verbose name, for use if there isn't + # any help text + verbose_name = force_text(field.verbose_name).capitalize() + + if help_text: + # Add the model field to the end of the docstring as a param + # using the help text as the description + lines.append(u':param %s: %s' % (field.attname, help_text)) + else: + # Add the model field to the end of the docstring as a param + # using the verbose name as the description + lines.append(u':param %s: %s' % (field.attname, verbose_name)) + + # Add the field's type to the docstring + if isinstance(field, models.ForeignKey): + to = field.rel.to + lines.append(u':type %s: %s to :class:`~%s`' % (field.attname, type(field).__name__, to)) + else: + lines.append(u':type %s: %s' % (field.attname, type(field).__name__)) + + return lines + + +# -- General configuration --------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode", "m2r"] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +source_suffix = [".rst", ".md"] # The master toctree document. master_doc = 'index' # General information about the project. -project = u'morango' +project = u'Morango Developer Docs' copyright = u"2016, Learning Equality" # The version info for the project you're documenting, acts as replacement @@ -69,13 +113,13 @@ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to # some non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -83,28 +127,28 @@ # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built # documents. -#keep_warnings = False +# keep_warnings = False # -- Options for HTML output ------------------------------------------- @@ -116,27 +160,27 @@ # Theme options are theme-specific and customize the look and feel of a # theme further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as # html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the # top of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon # of the docs. This file should be a Windows icon file (.ico) being # 16x16 or 32x32 pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) # here, relative to this directory. They are copied after the builtin @@ -146,46 +190,46 @@ # If not '', a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names # to template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. # Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. # Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages # will contain a tag referring to it. The value of this option # must be the base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'morangodoc' @@ -195,13 +239,13 @@ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', + # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', + # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - #'preamble': '', + # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples @@ -215,23 +259,23 @@ # The name of an image file (relative to this directory) to place at # the top of the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings # are parts, not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output ------------------------------------ @@ -245,7 +289,7 @@ ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ---------------------------------------- @@ -263,13 +307,15 @@ ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False + +suppress_warnings = ['image.nonlocal_uri'] diff --git a/docs/contributing.rst b/docs/contributing.rst index e582053e..4fc50161 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1 +1 @@ -.. include:: ../CONTRIBUTING.rst +.. mdinclude:: ../CONTRIBUTING.md diff --git a/docs/dev/concepts_and_definitions.rst b/docs/dev/concepts_and_definitions.rst new file mode 100644 index 00000000..cfa50d82 --- /dev/null +++ b/docs/dev/concepts_and_definitions.rst @@ -0,0 +1,55 @@ +Concepts and Definitions +======================== + +Sync Process +------------ + +.. image:: ./img/sync_process.png + +The Application layer is where app logic and app data (in the form of App Models) resides. +There is the Morango layer where the store, outgoing buffer, and incoming buffer reside. +The application models are serialized in JSON format and saved to the Morango DB Store layer. Sync between +2 Morango instances proceeds through a handshake. Morango instance A, which is responsible for sending the data, +queues this data to the Outgoing Buffer from the Store layer. The transfer happens from the +sender's (Instance A) Outgoing Buffer to receiver’s (Instance B) Incoming Buffer. The data which +is received during a sync session is stored in an Incoming buffer for processing and is later integrated +in the Store as well as App Models. + +Store +~~~~~ +The store is a table in the default database that holds the serialized versions +of the models on the installed application. Whenever a sync happens, we +serialize the latest models and put them into the Store for transfer. The Store data structure is +where data that is on the current device and data synced from other devices +lives. + +Outgoing Buffer +~~~~~~~~~~~~~~~ +The outgoing buffer mimics the schema of the store, with an added transfer +session identifier. This transfer session identifier is used to identify groups +of data that are being synced together to other morango instances. + +Incoming Buffer +~~~~~~~~~~~~~~~ +The incoming buffer also mimics the schema of the store, with an added transfer +session identifier. This transfer session identifier is used to identify groups +of data that are being synced together to other morango instances. + +Operations +---------- + +.. image:: ./img/operations.png + +1. Serialization: This is the process of serializing data that is associated with Django models + in the Application layer, and storing it in JSON format in a record in the Store layer, along + with additional metadata fields needed to facilitate syncing and integration. +2. Queueing: Queuing is similar to snapshotting where a chunk of serialized records that need + to be sent during the sync process are stored in Outgoing Buffer. This prevents inconsistencies + caused by a record being sent on network and its copy being changed by an in-process serialization. +3. Sending data through Network: The morango models will be serialized into JSON to send them over + the network to another morango instance. We will be sending them by x number of records at a time, or another batch number specified + by the user. +4. Integration: Process of merging the data received in an Incoming Buffer(by another morango instance) + to Store layer as well as Application layer. +5. Deserialize: After integrating the received data into the store, we can then deserialize the data into models + to be used in the application. diff --git a/docs/dev/data_syncing.rst b/docs/dev/data_syncing.rst new file mode 100644 index 00000000..45c7d071 --- /dev/null +++ b/docs/dev/data_syncing.rst @@ -0,0 +1,56 @@ +Efficient Data Syncing +====================== + + +Instance ID +----------- +Each morango instance is identified by its own unique instance ID. This ID is +calculated as a function of a number of system properties. This ID may change if +system properties change. It is not a big deal if the “Instance ID” changes +occasionally within an installation, though we want to minimize the frequency of +this, to avoid data bloat. + +These IDs will be used with counters that will allow us to efficiently sync data +across devices. + +Counters +-------- +We implement a counter system which will help us in identifying what data needs +to be synced, as well as determining how to resolve conflicting data. + + +Database Max Counters +~~~~~~~~~~~~~~~~~~~~~ +Database Max Counters is an external data structure that is a hashmap with +filters as key mapped to a list of instance ID, counter pairs. These instance +ID, counter pairs reflect different morango instances that have been synced +with before at their respective counters. To efficiently find out the difference +of data between 2 devices, we would like to exchange Database Max Counters. As +exchanging all this data can be costly and unnecessary, we instead send the +highest counters associated to all the unique instance IDs for a filter and all +filter’s supersets. This is what we call Filter Max Counters. + +Filter Max Counters +~~~~~~~~~~~~~~~~~~~ +We calculate highest counters associated to all the unique instance IDs for a +filter and all filter’s supersets. We generate a list of instance ID and +associated highest counters pertaining to a filter, which the requesting morango +instance should send to another morango instance that it would like data from. +This becomes an efficient way to determine what data a morango instance already +has, so we can only send the data that the morango instance needs. + +Record Max Counters +~~~~~~~~~~~~~~~~~~~ +Whenever a serialized model record is modified and saved by an instance, a +combination of the instance ID and its counter position is assigned to the +record, this combination specifies the record version. The record version is +unique across the universe and is used to determine fast-forwards and merge +conflicts during the sync process. 2 records having same record ID but different +Last Saved By Instance and Last Saved By Counter will defer to 1 of the +following resolutions: + +.. toctree:: + :maxdepth: 1 + + fast_forward + merge_conflict diff --git a/docs/dev/fast_forward.rst b/docs/dev/fast_forward.rst new file mode 100644 index 00000000..6f63f9de --- /dev/null +++ b/docs/dev/fast_forward.rst @@ -0,0 +1,15 @@ +Fast-Forward +============ + + +.. image:: ./img/fast_forward.png + +In this diagram, Device A(green) produces record with record ID r, r@A and +assigns it a record version of A1. Device A further makes changes to r@A and the +record version changes to A2, the history of r@A is [A2, A1] at this point. +Device B(red) now syncs data with Device A and both the devices have same +version of the record(r@A and r@B). Device B makes modifications to r@B which +changes record version to B1.The history of r@B grows to [ B1, A2, A1]. When +device A syncs data with device B, the situation is known as a Fast-Forward. We +can determine this by checking if r@A’s current version is in r@B’s history or +vice-versa. diff --git a/docs/dev/img/FSM.png b/docs/dev/img/FSM.png new file mode 100755 index 0000000000000000000000000000000000000000..12e53b3cfe4d4839edc88a02b229f1eb2843b785 GIT binary patch literal 17629 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 literal 0 HcmV?d00001 diff --git a/docs/dev/img/fast_forward.png b/docs/dev/img/fast_forward.png new file mode 100755 index 0000000000000000000000000000000000000000..18b931fc1be76635e2bf34333345e0382fe148d5 GIT binary patch literal 11387 zcmd6NXIN8R*CwE-fC^Ftlp;0sDk8lnks3Nk6OblddQ*xt5eT7oNWh?g(mM|z(nNs- zP^wY|r1w52!EfI0op*lB{F!ThaL9Ge-sh~n_F8-2_qunqwx-$*QU+220)iV5uriE* zfDjG*-MV%KxYJf`q(nf#rwCD2(DNNz%?@~`H`=`3-!#3x`Pxo8c!sVfOxTs`3#RFg z^@q0mY4X>Fue7ttU%w1yp>Sb&5FSb<1HrII@`xcFh7!hiZi(yj_)}-A7B}l_C7Y|L z4eNXHRKrZOmvhXs<$`@qz3n_E+5|VIa()Dagbb-^KK=aJ{CM++(`m3%Y1W;~MES>V z3v(yTrkY>Z3A;J@Bqh&7-%-7kcN>r+NKiQ;SNJ+D&q8r+f|`&$LY{>MM8E>NOhgDF zECu&Eo=r=7j|07Un##WYya6VahYj^OoaUwyb~Er<1Tahn;%+5Szd%ypE(9--`0fM{ zR^UH`kN~0pBanv?z!h` za&Dm^&tl+Njke;o9>KZFXFUvKV*zP5vv23wT`@wAc$vik?uy}Dl{mTx~7|n$x8Q1KH$}eRF2F=QXcK1x2x2a6(`h`^6XDS|N4hf!q z!Vpa!awLULrTO+q+lyOK?Ye4}3_CI4X?F33tOs3l)H206Qyp;dT#D{Pxx-(?L}Cs!PUXRJhas}j&&!jh@|T>Co?b5Vzy3cMhh`!nq=VLRG}K}3D} z{koGBqM)g$SsL3t=P}gKaw#c8s6Unt)>)!YT^G?r1NcVciXiEen_M!RSk!w2Mq4xM zm^9)N>qBcXMVNnQpf??Tvx~_{vrHk0ZoC|rJZm`;2yHO*S9HC;qPA%*bGN?&>gPo5 z^lTy7Lx!U;Bs{IbFp>XGfs^Z*kQ8N61WN2(5S!n01QN&^C<*QNKUKbi(BW%5#B`4H zksc^>7IxIt7QdITJsr8t<=A+sicrHC^adj?1K>$soK*S<1L$b_7<=bN)FZP8JiAv| zL2-s_^iQlzzE^WJQWbI7>K!iQ1K;K+@sK=LvH8l*9Pv!_}h7JuDQRuD}&r@Mb~mDj5j z%A&y;n1<^qArPY;gA30gQn&2&Vd}P4pw*X1tZBa;So!ytN3IUb$UwIq2A=8KOSqNG zT6>usV!C8+4C~S|EBe7OF>FW&7g=4+JNRQfrk-|mX(&q&H>w-o{9cZ(4u0Y81#isR zL=GbBS>?>Yy|>9Q!>)mEd#JYaYa-G1T~Bds^y;tDLyvI-4>%B;GBVzZv|^ zT1%RD6;%9bUH8r#Z8>&S3o73Cmk~dgdUN7iF(e6YacT79HeiWXSaXW!B~Du8s&-z! zyN?V!3tVqWikToE5wC__1^W5vkTupiHe_0uNkldkdn@65bDM#x6MhGAyYqw8;~~X? z6R-Epi@tX?3kQ*JkvH!?d=!^}=zVq6OZvMvZr#xY)>LD0wxxobTLza>*})`uqkSmd zB}-v`lNJMphFR|wIWNCYr9O_I!q`KKf?Wy=;0%GMmr91d7e!^HAm(>5Hhar#R*s&H z;u3RLaSo>-3;(^!d;;6Ms^s#{PH;Mp`FuueZu=^_s>%QRw~7Q`bGH43sng%0Djc1i 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 Qp<)7vil%azqGjm+0QjHgxc~qF literal 0 HcmV?d00001 diff --git a/docs/dev/img/merge_conflict.png b/docs/dev/img/merge_conflict.png new file mode 100755 index 0000000000000000000000000000000000000000..3420ba57ed47807d5b9ceb753ca4431f158d6668 GIT binary patch literal 9088 zcmbVycT|(jwmwBfK*T~(qzR!U6cH&B1f)ch&_e)00Z~9Hg7gjw0s;z22rWoYLKUP7 zQv5(ZI!Koy2-2%GAxQbX!E@I+zjM#Mf84cLv))B!&&=L?_MZJbGZFf_cUYOZnQ3Tf zSP^hd6b%h+F7VxV>Lk!AO)bM|XoT({G}X}FBP%IBjyyvF&8;c5&V23Wt5R!PHNt#Q z@Zx(owpucl9c)^n8BEq}eF#F5rIJgmO&OmOundav$v5(t+YQEAB7WQm$DWiQYk)`c z-985jJv#Lzla@OjY_@glXxAe!*8Gme+Q!+(@k-Yx_bN z(#y`y?!+ymRpp@}x1gOBQtP+!suITj)y~Xg{~#RYayK1DCb5wB%{cMZG(#=TEoPUE zm=dH=yPqKq@w5a44x!+DS)a2{F~FH`p-xd7np-FgI}L{YIq@vDp?OXe0Mh_}h%3}a z4Ml@fPd7Yq+y%ry17Z*WpP)8C7dSJ`e;WlD=zr=3;qXRS!-;o@eGf?kQfx-mwd}4{ z;C5Tlv~P$j*-?|ZwFtufiOHXZ zE@n((yQN%Y(TP|Xp9{Whr8q#=XGtYsYhi66*7B(PEoFG(Fj~YZFc~WErImRvekS(z z-6sxzgzX1wATk0-@I7|)C|Ro7V<&qnp?<$R{Jf!{%5IZ0$-r1lAttZ%V5>~+)~E*6 zZnsc<*X_Mf*ls;mo&5Qw9TmKh_WA?Ly1UgU{>*_YD{Xpp)aLT7H4DMMBzkNA4FegE zN^EHWN7Z6}3zlCb`D*eqt*Ro+MoZ}j!p(bwSW0V(b+zkDi5<}|fq>>XVhhm(CJdP|*gN)rb!8+>5>BChnfVB&efXn$>b zr4|D-P0ykPdC!$NVXKj<+L&c2h0vjQBHiVWo;(I-HJe|kE#TSsP`fo2`jkD z5#hmHv%WI($rF^j9Kn&U`^!=6U0oSV7<}{x?^gvDdPouNsQe}H{vZex`kZKO-Rqd4 zFMvmN@8ADAtN_ms_QBx!-m`jOhxp+uFYR0|#nrm7Qa6lDF|iB1&iEJ(FAiNok1M zar^9+$zWgPpr_6$2z12+W2r90J&rf_!r|IF8r6(MwJ$4GU=C`RFzj?V0=;1{)?cL_ zt(?z+xK?vN%u6qvC>#7SBmNg#8frV)uxeNStBfZdRV%j#CgvBO4p*5N21h!bJbPxg zFX#3h!)hG+nwbUKJUilLu7Xfh4v zQl@R=?9+g<_9wwabZc$u3QUewD^%Eg`zd)pP z_6)o~lvq&bs3WSKZ#G07A42;(s?E-Chjutkc^oO}8idr+u-&{~vlXhUy4$Y^+Y8xi z^Mx`aatpGOxk<}4{(xwT6PwLM?MWa9=iYD>&(F-tE^IkmF5Y$Y6n(e$6@1Vdp4f$6 z2A#SM6CNmacwQ|4j`MI2xV#WCc}=Gqw&||%twjyaOp9o;((x%@j@qHjV4BKo8|Cd5 zqeoY!chL=5UiO?<<5c?I7Z@2J))5m9vc@+vd=OR0D0i&1q?2P9U}iLrJ&Tr&rEf#u z@|dxNYGK)oN0e~p=^p{{q4=3it+ar-tAV5(qSIJl8mH+~4Bj4EHPnq&YA(8K!yEJ9 ze64a*$PP35VbgE^@kJi%DpgvlIv0cMXbvcPhiZe5qwn0liF>F9V-fqXGF5wavtDUW zktEzywUgd?29e9~BSUKB3rX9Ezg}*AUuGglA|gqp`{TR0FlOT4##8m-+2>p>FNRXr zd0O7Z`dad1cPYVFlJVcU^bh&?(a>+*5J~Xifl3qy4#m>Ywe9Y`T(Yd7z7@7SHm#}y<6fsoFVIg~2Ys4hQQ+PXz?Pv&vBKrx+t zOvqm4f9dsn^4AX!eHLLb-^>g_|3*eCtY$l|L{yt%>s3{Yp7`K8Qkgf;+Ny9pA@6WL zHt4XX=a-0R^bM<61uJe29mir#8=Wj!uFfn{QlK#yvEG?>?)0Bgj3(860~fn$ z(u%!Q_qDmfu*U{df4NS{TPI1rB!=zX$pKO%n=8wUiPT-MzvHoPlb^NSdRj5~<~3^g zqEDw}_?vpZ{XXYMRtI;P&YV!kb=r@)o+dZDhPLH*cOUmlej?xbe;s6M*C`*|bD?r+eD-p{nwc(j{=BC8q-vN%nr zGJKxgqX0@Bj7pH6dC2UfF@9im1=QrW`a(F0n(jCnn_6;f%*H)L2=tXKbmrkibbsqW zTzkCqn=UywIm^s<5#;13V>8tK7VOaQpJ;q}^OB4Bv+~bwb47-7y0b>Z?v@Vp=81cT zrcTeF40O3Ois~wGy(=Sn*WLW!$4GVE)cb*%p8eLECHv$j{2)>ZuV_V42EAxn@=ntn z$FxM+M%$j9YV&3Xu$kiG+1GgEJ)S5W%RP&}V_0R?$sFmn=9z`H08*E6u*&-sJgbh*cgPxcfZB?q|dCbhS&V>`^axPD&SRp!kL(?98`%?4% zkRrbGWaES=31`dWxS{h*>?pHpl-K!1J7cQYU(~Zirfd>l-c+p(TzgE2XTOT>FdKQk zNzJ&jW8Zu5of%bhk?Va!Ik&R1!~)=Xl_}7ZYz}6qr=z~D(2~p46nXvGCjtF|Of#LC zOn>9cZ|rvoc1OFrCc3!mJpJws{j;uE%BnEcf1SY(v+u<}#i3sOWlrCpzP?2AK_Ien zmrqw89Hcp*P&I+#Sry3Ss~3SnheUI8@zm^eTV2uP5}&oK?iS%wy$@~R$Q7f&-|~jA zd&wfgMrK2|$QOXj4V-q2gUOO*Wp+kmko)EAS{%MIIa-WENG@E-Seih{4TA5?J2qJp z>B$_io@I{^pxPyQ8xaRr)0?Z=a#pJz7fW3=)s%!*8Si1(W605KrhP*!K;eX+ zMG_@a^u~-D-Be|~-_o57nU%+e5(R(eG;*SVpslnk@u{UML^Vsyb$_0kCZry3J*L;t z|J!ALlB0qC)%oSUc_a!&niw3wSNbRAT_F2#7+G_F&7e3O7e71(9K*|H#Q}HPYCmsK zjJ7FF=#*65t4lve=5^VRtDAG$PlB9~gC5EZZ)gxkH8}x` zps+63lP)J>CpW%aPq5T7^LD)ufSecdj%MBCkTU^&l4hva@twZX> zZBI)l*%hl{h_8Ny5vNw+R~+vmlWa)tYocl7m+5tslo+tkML`G4a3@!Nstp%^wpRK( z^)b7+&q&|P$t#Hb#Twn4%c4LmH?CYgMC0__eKB_|_P6uB0<}#ns12re8bOnZ;&>*Hy?(;Fv=6$zlrpu`41k1w4X@V<&G5Sh zcLqDOxdSF`T`!OyC6Hj%gB2Xr?W$@hVB6lhr;dtD(-4-(70|n(t!Ei%)bnz|q)Qib zT^u;T66^!Hn1HfAm`DQ>-ZVy%g`--g-FtBrXShGQ8^*r`ck2vQ6bMJPBf5-OaqKS ziKD}yaTUf>=Q#PvPln3~JmQyIj6S{s01$~KxIaC3SR!D>^uEsOpl!+1ds=_f-)r6K zH93Ys)Yy%8fBhMN7C{<`sI6#0TdIyw z@e>s|$Jv*`po1=D44}Bk;60xFOLH))4|J7`Sw?7aNCYBDC+La(x?YBx@W=^3Mz%u> z%Y%-AXE!19&G~@R6g=%3J9-S6)x!TBGP8tcWPWF3wXeka*s~w6l>0{{yl7ax+*EP; zEUc`eJjHj1FSAiJHT!YVVT3#PPG#V(S8was>7&gzqib5(-fJUn7<+O1*8d+mL+mc@ zxa$)hq;K8)qlqkCjK60@Rz|~XiH#fI{&y4|+i0IgioRQKk$cJ!tmb zIZqmv5KE*QIPSlo^&9bpe}mSXL1+7(WBT`Pfc^FSwVn!+yejWnQ6y**z@fO&Xzlv7 zmG5V4sX)wFRDNrz4R2D~7=kQ*r^PjhZiNx>CfMS1u_n&|J3Ah3=!$FykE6e*zIfDI zHl^k)0&JYljJ}!x3mh&#BTPa{RIbuFGv#;PTj|=JtokEVLz&l+VOfsVrKALshznMZeBXcD0r!U#xg4>IH#>Ut^U{pj# zwXAOU{#{sG0@7Bh+`)dEA^)r%n6C0Xy>c2@9ZQFcROBU19-^@C+vk6yB*uU0K^>L1|R zZW=vYBbdw7H>OW(&>jQmF;BnFO9OWT7a6<-5sbyW4zSxY6IU;0ujyn#@; z^8mi;-@VJ_Gya13ofVG63Nm%6`TR#@P2Q2>1LY6J;+XoT7JZrP<(Q}()ukladt&UT zNd4DUxjcWd_U1j{1CbaVHO!~C8Bt1BX7_K~INuKef*!9e0e**X>lhFd3(JpchuF_E z@fKwDmJ#o6916!KI4C>U;$(=^6;< zR?CH0akphpIR|i1Yo5)oQ8C#R@5x#M!}fP=ty0w!2)n|~kBYbDi%jB}3{&@5YTS6K z9of`^Y?R+Uc{=nmJ+m*6fg&uMIjLjkAqvjzxXFX|XecXw#4ubJeChugDKFTV%)St zXJvuS5s_Y!SMv({G#mPpv9Km*-D9vDzbg~aTbd<@fJNoUzY3rOkv3{~c_!1z=gHek zBh(xv$CBFFg6C{;FwpPui1WuEoB)xgTsJ43>>YhH4Vn5HrkKrcUOQgorTM%9lkMu9 z;rBlG_*Y~I0$?N8H5o-$e}Z=6hRBCwnjjUo|8N0BFR8VdZyA&T`DOt}#%1LwC)@qV z@+(V{mK4jV&Sg1Hpr3@3%||qi3&+^FEI&7d6E@8L9)5ehIh+V7ej%qvG1al{;(;fZb2WT`( z`QynP7OM16r2#Zhqus4%|9k%%9x7Xb<{8ABv{!hmVu_j0u3d-{`!%0JXwo93Iouu0 z%OUO(*W|dxQ@_*@?*oS}JdsmDUW1Ac&y=#{Mwu3tSDc+&A9Smi?>E=6%p%Y!D`(t=rZM zGjn)?dg?tqwMSQ?>=prPf@#0ypRMu#N}^9Gq!M;r>2@do`@F6@w-Z(;;%nTmA1Eb}~ zcW>_}d6SB6Ds%>k&IMhLDtXu}e~bwq$S2vB2inysf>TFgIN{pk)%60nso~`N7nnuS zA+>d=U$uL?wsW7w>J`_A0In3ldeLwH=EVDMy>Ag8+Zlq=g2HTsA2*bx7c)`!*0tT* zq`pFPTgrgyA*Pk8w8J+rGEheH}l}Hm)MvPg`U^6L!>ALr5HaF4%V#fj8QGVnM0K4Cqedi0W8Sk2S-*@j;)e%I0h$=Z$Lx<_+dzgB+;LJBv2)c@e|$mB`v z#f|h-r1%Pew;xEiCrI0PAJA7`n9Jg;QS-TsFKekYj|hwx56n~*uLKfSKvHNZHBKWl znr*XJo7uqCUi{s}_iuL<=lr+SjdtX?;`+{lNSV4)-(w}M+BAGDF8`(QBVeG zE26rOxJEYanV4DYT@^mTp_6zrUgDT#I?W}NyOpmo4$Z|tnOBedNx(G znOPYNXLMh$O8wS+D=C&^rkRh1%K6#o|IqcLp)9^95{QmjGhRm#V$g`$?P7V}1IE@4DS|@_49A^Zz>?M-p~U;nNA}spUyB3K|KAUYQP(2S!iT$IMH`B_tDSyWZ{8|cL@bT zACC_=ddAaqMv{4bXsNcxmF9n5U2RsEA$0 zr7^i%tlae$gao`Sp{*-@bmFK=M7U|GQpP^Nj1o*Of|);MML*Cje8{pC+vLX|a9c_Z z!zr$TvM<^gtxST9jL3p>d#g{%qKjYhA!`tGHmt z-gOe{EU2}ptcjq_g6ryGCP+v_6#PK?iPHsBID{?+x_o6@R6FSBx-(FgA*14s4XE1n z%3IPH3T=#*VNq@xs$Dl|<7C(l?kbEa1PL4MJvG;%v?t_4tq3LtF!BptLj5t;?l@O~yWl33$4v(#4~SXkI9IaBmz6=Xvh2VLS8w+lV(wr4`M%Ix0V!@hePWf8I&lXwE$g# zl1JvIlQd>@HvLg{QLAss&i(Iw0XsXaI4$Yk_gzKdD#A^?-&Zz!1t;7T4z)Rgxp{+< z94S{ip9-=7{>*Lp01vql-1^LiNDqsR<9h(+m?vpgKG>jpFsTlPieU4P~Ab`x3bU%*?pW zf%#>ifJA1z!{?bhx!x_H!WN+5B%p1S(&m!8(=ICq#1Zm2V;il>O()fGf+Lr4kspOZ z-&=ug;^TU2)BFkNgZE~=RLHL%yebIbt!`BVb`LtQQFLOXN=N*2Ph6v8MqUYIMBxT9 zTWSn5Xto|PCXqJ3B@k1yyJWJqpIBJqnxGr4XJEM|z_A-LEti}NJNrbe_FNiKTAEaJ}HQP|)JZ~y!+RH$f(E06B^ z((R#0j6zj|FuY;AE_ZgNRoJYNQ?Md8RaK-kpla}18@?crcj#h2%d8b=S-U&!e_-Y7w(3ixddERQRG9Z~Nu9nk=*dt?gO{Z6Udx>xs)<>kYr;@V4^8%O65@^6~L_ z1sTC%j!PM15!xvWrkYe^K98>QN_y=F73;K0E;dv^bG2W|)fC(_0cPaK^7K~XzuZ9w==IznjM8_UZdYBbAq$OUQziKTIr8jh}X?thSjQ@ z881HxU0v9z2{6jr|IsKwS(emT!Z8m07Q2#p6kT9g&2M^3iFn~0m7Jl2nl5d1(2&9p zHgTaDH)OMW5>5;Hf=U|c>8MWsvZy|`RdTbb>motuh-(C*;y0M6Ctu5PwtvY#uc)}c-=la^G62pqDt~}T-4Uvjt`?klR0OO zA2xufS=HTHpfR(-j%&K@T5y8_@9`^$M3W@NxvbaW)$p$$-uAM%+Hi2(1{ff~W0(M9 zlTl#JQECP$wYRjEO)}T}awnCRI{vL*#X?DVt0Fd|*wy%+5J~v!6Dk!7ytlZ8g3#-T z{z7v2MQq$#mnVc$St$W9<~-%yKjq;`op!+WIQ7Xz&SSz^s^l@x1{`(3)fMnx935aX zYFz>}|Mm)lYJpSkk-+a%$_tp0hKdyc`Qsq~2T>2qe;MWf-beV2OAOQ>`T(x7xG(vnLzQi8++tB4>V2!fOXQc5n}EG1pirF7?# zyY%ng_4|FE=kt5t_a8sYy|XiC&dh!0%yq8I_s^cH5EIf9fq_vR$u$K$Z|S#YcL+(>sks@%m%Q#f?9>cPHEvGalVg!lkDqpjQ>76?)X}8>vo7 zDe!~!m-W>bl;qW7bxor`N%jqCG&Tp|MZF6=1tmuNZteA}sI4Oib?hIvN@l@>}-P~MPVxsYZT5;GrI)6Y zLMbBO4^f{bqVr8qgRT%eO5!dE!dns3g@Dq~9Vs|R#MyccVkuO6^bo}<$vd|n-Y1#~ z40v@W*KmE+#;z8pw}HJb9L)TxdVOx1bJKza5~s(JPmN0e=TM7_c&s>jhKz|OgQ%_K zA8U_R29K6CEjfMAl-i6b;!xAk;bWizzH86c)_zctlU48ZMnEktJM)b|qQkE+cy>ir z%5ZcXhuQ%|?TvtFOCr#tG&qi9FcI@qU5XIS;RheR0X#xCi5reqmr{@8=swhMBL0xM za8{Cd1B~erXoYSV?-LL7u%;2We0m#b&OrcA8JboaVh&u_P?yT*+TjGA4JLA+bSTi@ zb|2madc`~i44Kyee)t4&_iq!fogWoh7;FCjrWuk~q{$S(ezBMUE&mQX{iD*2rD%f1 z=FwhQovV5xZ39yYrEe&|Irh)#Kqa_iT?{Ku!Kl8e)_6FAT26nPj zaD6es*#H>8p%(f>w=?=WT^f7<5jDEF-FUuR4?Kuz08*KIhTMaFFiy=_ zXbamS{RVXWzHK6$Q*!v)%<$7%!Ol++>2p$;>W5!-->+m1MsX+#?99*g&~2)$y+5Yv#h=YH@lKIRRC^>% zy~MggGgDym>}a0u5`$ZV&}{uH7(*{(pZAawO|3o2S}fqGWsN6}onr4`^+9Fa%mJ+g z9!O@HMXWH!+v$NVp(M(LjaU73fA&-Er@4^dq<^^Z6IDAg$L&8z6U_TuU;QP|L{h1B zXGf}-tNIhOxQH9!P}Z$A(IL@0k(4WkgK~Rp#trvcJ0zez9iOgjNY2Ox^>lTYR`Gkp zg9l}hHd!zGB1xpSOZ*QV5(*6()q!2}1Tppw;obgwucOf)8SU2S<=Ai>nz-1R7Sz!~ zbEnGj+zYqgV=a(}@j>N{8~w?_W*5V5a{^8%Y!_7~*@G^2zs`Nu7up3jXK`J6{HVIc z2%azEG5od5w-bwbZ@@vEQcW*6bS9c?y5oGWE>5SeOxzkpso=iXdvcdAm7F_MM2&q} z(Q&~KZcGY?7Hp=__hojOqh>Brr~PBg^tXanGd_4M1n$U&PehrW{%YI*gOqaz#R~~&*W-&x?+%0_ z-S|*tUD~X6=Nlv6>pAtxSW2+pdA87izduR+9LlYjQbLAWoO;|vv{n+7X<0kJCE(Ve zJ%rti4o-uKDbnB~Jn)>6y8@(deJF1Y%CkCk)#JQ7=@b^a@o1j#2b=9wHMq%lHNmjf z>*3`*3C$Cnd8qI}y5Fv!kp;casCIG8Vbu97(ye!ZVVra6nCAY|h^CVdj=K`IokVVp zTOC-&rU3`Q-Vq42^@O0v+ZG>%;8$})V)1UgAQY{}QI4t}U4BbI!FY7EG18fXEfMot zPE(g&5X-?bCGP0%8h_)F&O}&ZB&Q)O0=Fg1X#1N;;byGlh5p)z)p2BanHP@&`{ud%oHLIji-q$5MxcMP_=%y@`*W z%c6Gv#T!%Q-wz`#r|r`o&-YT}3(5`lLC_)PZxF&KfQQSj2oF8Pg{zWVO>3R?+=7Qc zqkEPN;!5Qq08{%B?bU8w&eeNa_QZ`^JGV`o?=|gRslLs8d&8DpJaJ311EeP9v+ZuJ zW>&^6B;9!|Pt!>~WhGrk6?yZfwKSOg(1Xd!6vfzQYbzwUP4RjuNk7SP;~6HR{S9Zr zkXUAplz5-$9UnwU@?icm6n0@8+1vNC^O0Vt#yB2EuNK2;ah;g%HLTkv3~+V*W*Ty# zO!p*&-&edy%tSD8(~zf)hO8~Wqx}`1+?`F_^|u=>HrWIY8X*E~`tl~UrDq56x@Cw^ zxk%NduWioYFEF2s3>->kmw zh}}Zr!7T-8!Y$WW{-3{}juL*vPP+B>xkor1Ge{UrGa*8ADBRRS^Rd11%aW)Co*owD z!)t*CFzs&b{Q^ELAX**L%r>q&<&4dQJWkI@>@z9a;1*BM#iN89G4mPR*^ z-fZYM1%-~O`r0!@SWjrz`J9v$BdsH9s+I%8TaEIE4Ww3$rGJ^C2#NPFjss5TJfQW< z0IAz!t)Fmj#TI897z)RYo04y^?Su<_c*()lY11;E+nQMPAp7=3S1kL|$<7QBW+1ME zoZJd)54S?%o2A&LzxX0j*fO1ehrB6RrE}(o6q(hF?T#0v2K39mzY5lR5o(e0j)ch= zwri+UmF%6unN4qyp%o!%R;w5qI1|Ll)huLmn_aJ1H4S}~0wJj~GX#dt$3)#N#{Pg& zkH`Ak!VLR~&e!@jq?tWTf?_AH1$IJ&c0%G)w7N-Wfivn1O6n}zH6lCzNxoTRzE*M) zWS~yS4lcZvz3!OEZ)Q5$8WMZ4`y@K@pK z)FEBE#`vN8N0l$9g-9Vgu;S<|=;L5A2Cn3~O?2oWyXUx~Q8ZFPK0jmTO z9fA`tGqc@;i7pWR;`VNn@h*QZ)MZF@H6+i5*jT+SjC5iU{&Ruo`SjNzX*S;XEQnzX(+@Eh9Ki&#gm?1A zJc`Aj>EAssZu6=6!A&69T#U%7urjhA%ukZtRIrN&2!=y*1DRV1U1x;P`sSJvgUtfE zSVeVl!KVv6MpUz6qq)$$u^sIE)*UFXFrEdL)5M>$t|IAW`hsU}p}KTha^z(tN!*vF zZH%K^P8&Lu==Gg1s0pf03-$_VUoS0+Sx5f3B@Nz^ei^v<`Yq*5O_VIcTII}xdOw*) z@mub>bM@)c>sf~On)g@YglEObLz5f*yF$GCkaHO*@sYnERM;7bj~MTl87O-l38Vf2Iqbcc1k}PYD>4}O)5Be z@mfC-UF>0rHp{)kZ!J?d&h5{vaWY!odl=$cd-}ndkD71im@=G?#V#Dmq{WFv;dE`K zLg6K@C+<|rg?RTmZXHd?88;)hKmQaN&K;U4wSL(&&m#xH(pp7YmAiW@7Bw@OFnQoIWqX5UKvOO|60Zl5$fDUrt$kVRs=qo-BT%ToA}6R zOmSO4F>ad&sa(}E#TCo9r z6+y?oH?ZGx)u`(R?E~!Q9y&NLA?4Y3+2f%sOX6n3hrv60x8Y?mUdVr#QOUY3N?*ICxKS2N|)RJPeAX*CaT8Ny;W>03Ploei8tFQiNmgrI17f*q6 zgLhM;U8QN3B-66-pm~C1u6j(RAopxv#DpAvhKFQ~Q#nncJ4-xAQbizHUagZgvZI_B zA%Pn_pUQLCpgHbsP6oo%gkZ(7R`qjKS8>w0nSBGz-$`KhCLdIv5VTIW_y$p$7DOyze}dl7emh6|)SNAsApC?Gj)hCo`o zsgwhkUZG6%v1w8~bQF3AgHC97GMWfNN(qNSQ4dxpDW1Ap*poj%pTw9oB!H_k!Nt~| zvpOI|`LV!lw=<3$A~phFQ7rHrJUdov)tu`^27WB-5q25zqCFp>#^LP~&9EQLFQEH$ zTK5Ryo$=gKRb6PbA@pIbe#C-!gK^T@dnlHzCH-xM#v;9J4kh1#dE$&Ef5H;uT7u0t zp>~k}9hw~8;TtnyPAVEH)9~E2X!+!E{pBhB-f_fberK|*6)s0(n&7}gJa{guYxKS> zU(IOD6pP|Q9WHWqGySwBqoQM8dahu?t8llk>guv!&}oAIOhfs)eRTr39{w}E8^8tc z?hGxdpa?}?({#M&EioUb%sp)u@97=DOsg?=nBm#9vD6#RiMshZCU}L?{cC@8q^Q1Xp?S+{iy~^p;<+P?;nj1bx!3H3n<&_I&bzc+5BF+kTZ)5{O|i4E#2) z@pn(Q6N9gh1onQa#4wW2d3HW-F=StGKFD5LVt}RQ00EQ@?8G-&(fAR4YyfE^K{_9qhiTDx%8G|{Cf z)OX~cFFQ^1zjgoY|D@=wnMj9J$jmftpVaQZrBJSQE(9ZT#|&MCU_U98@BZOW5=@s*6?Owynl#_wt1hzOn7IvTlGd&J7t z-enjfFyGU0o0Yv?HCSB5xww$>Z_YQ0jW`ae_4xkN>gV z9c8&Y%0Ht@@vIWC!PT>ZQda{BYb?Klr@8L8zq)pZhwwHNYSGN&I?zGLh1z`O4wBf* z?%W%k03&6$Q`aC5!M>Fy1n$4)L-xNUY@WttkH3TY(SWx*g0EAY=@}yjd1`C0R2P4{ zJ#>rijG^~#_M7K>TcFm-vUgPZ>1j`Nt=ARg6$u%854HKA(B&K00asZMqc0qkT5?0F zIEc#V(ydJf5z@CrmCL?Cnq`;3e2Q&wavE`9S+GC03f8(P^_R-oys!XQy!88p)WI=1 zsnFA)wlqumQ3eBcPl6x>iwjS>lhH#Fa#?7^zZf6oV5G;*cc66rOM%pzxwOfoqU)Ia zPuUN;t5Pz!r1$!K$EVF3XW<`ZnqGVrIbD)t@3GT<0F4eZCxZ9j!|6u^Q2C@_$IJXf zZ;P4jgs7K|%W@aNYp?Bc!wR$@!O!;t!}m-Q?TIqR9U^sG0~@6^2dE)xI(~&d98TUH z%iScNtz*&9;pw{?B(&*A5G-xW8$6Wvf(ATDLjejnUrgB~TJ&ha1O@Xq) zwXr_K1qV}Y{1jZIIw68@R(D^KP9-T`kFPfevM2}!w5O-X;=`vii+W?7&9+%f(fFL6 ztT+7Xw07-_VPrT}EZ6zN$MHPr3u%W(rJlkP_Yu^&_g@QGaDO2s7i9=sj-8UU{ubVK zyfLPM$Z2G%thNr-uVJB5QV1-`(=Hkh(VM(?Cg(77VEV8xCa)g{oXs|JqIn}c_f&Pd zM*2#4IPL4j^E+-f>iLIx>rD@_NoAaWClZ&hCFHL;_rynkCxUad7zXY5Zwuio_R%N< z*KymSLWrzTkKyEVb$yOrGfEw4Lrf6Xr-l^8WENj$t%r9Y-e8R$zrQ*Uyp|v~mCGb> zR1urK;@!vJ^1kLBx5Lw}YeUQ5W6u9abA#n+(|c#pWYnyFj7R7+!P{S*T4q-GVHz5b4GNQNTV*h|(K(+*1vqFNsj<=idwn4UA8=@V2%V zn@$Vt=QZ?UoA4VD$~B#jtTT^KbRfCoA;ZJMBf3)~sM0f}6A{QD1i%vBMJ(lGZ3g#A zebZ5;UvDFhlY=`fujrg9@&+KW0@Hj~zr%IHU{AkhCPq@h(IDf_o0N=iZSR0n2t*mR zZx^JMi`6zvUgac212OZyI-T;Q?A{U@_1b;UaxH!z!m4?lK6nBDE`yWz?9NlPrS0NQ zfuZLjWrOTvJ5x=i&rn$NpNksU*ZcI_qFp6K~m6AQm?!IlQcY8iI8+BUd34jSe)(+oB%59urzBS+_) zt#|H?p0*;=j$Fv;G(@_*80qI<6&igi`pEK_(atX;;&D-xzc65Sz>w05XdBAtoe$fm zDTH7Et&G@fy1qgkjcCQ3pX_X%Xi}+G%0l`ZHWyL5`n_d=_GtliGcGgpTMOwhk5E0W zvxB#&^WGN&(OJ~Afl>Basv!bmYpb+I4|v}Sn0qm;VKsWb5wM6jGao&)Vo~AY+W$RL zV9F$zzc}}5;&}gaXYe**Sy?CGgMQ^drkxX7a#KbpX|TDKn)xgPD9i&(oLH?ZV>9mt zB#?)%Ile|k7FFh#7@xUT5I?{5Rfa|50~zQZiklG*Wh)p|qP!)J-KDDHsVQd>AEh(p zq*~Bod)yi=wMv_4m2DIHq5OxTEQ+vN0((2?<>fJdW`~GiOwngvJ-s#iV*a4W?35IG zrBD;q(AEiS6Bdt>b|G@XDq8FYvQT}sCs&?pt0

CJ`bFz0Uih1V@6oDucTu`Gx7N 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 literal 0 HcmV?d00001 diff --git a/docs/dev/img/pull_request.png b/docs/dev/img/pull_request.png new file mode 100755 index 0000000000000000000000000000000000000000..7336466c02028efb9b48cd804649e67cdc12911f GIT binary patch literal 9713 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 L_n=J0`qlpe;THcQ literal 0 HcmV?d00001 diff --git a/docs/dev/img/sync_process.png b/docs/dev/img/sync_process.png new file mode 100755 index 0000000000000000000000000000000000000000..2fc78543a81a21705dc1cf475e7526f72467233e GIT binary patch literal 27192 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 ZH~l#GRfS?!!HG}=8Y+*JOYd6;|38!CmWKcU literal 0 HcmV?d00001 diff --git a/docs/dev/index.rst b/docs/dev/index.rst new file mode 100644 index 00000000..d7e963a8 --- /dev/null +++ b/docs/dev/index.rst @@ -0,0 +1,38 @@ +Developer Guide +=============== + +Overview +-------- + +Morango is a database replication engine for Django, written in pure Python, that +supports P2P syncing of data. Morango is structured as a Django application that +can be included in a Django project in order to make specific application models syncable. + +Morango includes the following features: + +1. a certificate-based authentication system to protect privacy and integrity of data +2. change-tracking system to support calculation of differences between databases + across low-bandwidth connections, and handle merge conflict resolution + +Architecture and Algorithms +--------------------------- + +.. toctree:: + :maxdepth: 1 + + concepts_and_definitions + data_syncing + +Models +------ +The Django models used by the application (Kolibri) are stored in their own +tables as usual, and inherit from the abstract SyncableModel class provided by +Morango. Morango then adds an additional table (SerializedModel) to store the +serialized versions of the models. +Models in Kolibri are serialized and stored on a per record basis in Morango +Store along with some metadata. This is the table that is used during the actual +sync process by a Morango instance I. + +.. automodule:: morango.models + :members: + :noindex: diff --git a/docs/dev/merge_conflict.rst b/docs/dev/merge_conflict.rst new file mode 100644 index 00000000..c937c210 --- /dev/null +++ b/docs/dev/merge_conflict.rst @@ -0,0 +1,16 @@ +Merge-Conflict +============== + + +.. image:: ./img/merge_conflict.png + +Device A(green) produces record with record ID r, r@A and assigns it a record +version of A1 and history of [A1]. Device B(red) now syncs data with Device A +and both the devices have same copy of the record(r@A and r@B) at this point. +Device B makes modifications to r@B and the record version changes to B1, with +history growing up to [B1, A1]. Device A makes modification to its copy of +record r@A and saves it as A2. r@A’s history after the second modification by A +is [ A2, A1 ]. Now when device A syncs data with device B, this situation is +known as a Merge-Conflict. We can determine this from the history by noting that +r@A’s record version is A2 which does not reside in r@B’s history and r@B’s +record version is B1 which does not reside in r@A’s history. diff --git a/docs/history.rst b/docs/history.rst deleted file mode 100644 index 25064996..00000000 --- a/docs/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../HISTORY.rst diff --git a/docs/index.rst b/docs/index.rst index 52a97d80..c66e6515 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,25 +1,16 @@ -.. morango documentation master file, created by - sphinx-quickstart on Tue Jul 9 22:26:36 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. -Welcome to morango's documentation! -====================================== +.. mdinclude:: ../README.md -Contents: + +Table of contents +----------------- .. toctree:: :maxdepth: 2 - installation - usage + dev/index contributing authors - history - -Indices and tables -================== + changelog -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. include:: ../README.rst diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index 934a1570..00000000 --- a/docs/installation.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. highlight:: shell - -============ -Installation -============ - - -Stable release --------------- - -To install morango, run this command in your terminal: - -.. code-block:: console - - $ pip install morango - -This is the preferred method to install morango, as it will always install the most recent stable release. - -If you don't have `pip`_ installed, this `Python installation guide`_ can guide -you through the process. - -.. _pip: https://pip.pypa.io -.. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ - - -From sources ------------- - -The sources for morango can be downloaded from the `Github repo`_. - -You can either clone the public repository: - -.. code-block:: console - - $ git clone git://github.com/learningequality/morango - -Or download the `tarball`_: - -.. code-block:: console - - $ curl -OL https://github.com/learningequality/morango/tarball/master - -Once you have a copy of the source, you can install it with: - -.. code-block:: console - - $ python setup.py install - - -.. _Github repo: https://github.com/learningequality/morango -.. _tarball: https://github.com/learningequality/morango/tarball/master diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 579c56b5..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,242 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\morango.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\morango.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/docs/usage.rst b/docs/usage.rst deleted file mode 100644 index dfb86e50..00000000 --- a/docs/usage.rst +++ /dev/null @@ -1,7 +0,0 @@ -===== -Usage -===== - -To use morango in a project:: - - import morango diff --git a/morango/settings.py b/morango/settings.py new file mode 100644 index 00000000..bd4b4f99 --- /dev/null +++ b/morango/settings.py @@ -0,0 +1,121 @@ +""" +Django settings for testapp project. + +Generated by 'django-admin startproject' using Django 1.9.7. + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.9/ref/settings/ +""" +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '-#()od3p8n@o&9kcj(s63!#^tziq+j!nuwlyptw#o06t&wrk$q' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'morango', +] + +MIDDLEWARE_CLASSES = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'testapp.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.9/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'testapp.db'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.9/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.9/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/tox.ini b/tox.ini index b7fe9c74..76831276 100644 --- a/tox.ini +++ b/tox.ini @@ -8,12 +8,11 @@ commands = flake8 morango [testenv:docs] - changedir = docs deps = -r{toxinidir}/requirements/docs.txt commands = - sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html + make docs [travis] python =