Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ee740e2
Showing
8 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
*.py[cod] | ||
# Packages | ||
*.egg | ||
*.egg-info | ||
dist | ||
build | ||
eggs | ||
develop-eggs | ||
.installed.cfg | ||
|
||
# Unit test / coverage reports | ||
.coverage | ||
.tox | ||
nosetests.xml | ||
|
||
#Translations | ||
*.mo | ||
# Ex | ||
tra files | ||
.DS_Store | ||
*~ | ||
*- | ||
\#* | ||
\.\#* | ||
*.orig | ||
*.log | ||
*.sql |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Copyright (C) 2013, Alfredo Aguirre | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
Mercurio | ||
======== | ||
|
||
Mercurio is a set of components to run commands in a host. Also known as the deployment machine. It is designed to be plugglable, so you can run whatever you want to in the host. | ||
|
||
The aim of Mercurio is to transmit a message to the host. It is most useful used as a deployment machine. | ||
|
||
The other component is the Mercurio box | ||
|
||
|
||
Mercurio listener | ||
----------------- | ||
|
||
Python listener on the serial port that translates the slugs passed into commands in the host machine. | ||
|
||
|
||
Installation | ||
------------ | ||
|
||
The installation can be done with the source:: | ||
|
||
|
||
python setup.py install | ||
|
||
|
||
Configuration | ||
------------- | ||
|
||
The most important value in the configuration is the ``port`` where the ``mercurio box`` is attached. | ||
|
||
This can be determined by running, after the ``mercurio listener`` has been installed: | ||
|
||
python -m serial.tools.list_ports | ||
|
||
The box by default will only send four possible targets: | ||
|
||
* Test - Used to run the tests of the application. | ||
* Development - Used to deploy to the development environment. | ||
* Staging - Used to deploy to the staging environment. | ||
* Production - Used to deploy to the producton environment. | ||
|
||
These settings must be expressed in a ``mercurio.cfg`` file, located where the listener is run. | ||
|
||
e.g. | ||
|
||
[mercurio] | ||
# Use python -m serial.tools.list_ports`` to determine it. | ||
port: /dev/tty.usbserial-A900cfep | ||
# Command to be run when this destination is targeted. | ||
test : ls | ||
development: ls | ||
staging: ls | ||
production: fab production deploy | ||
|
||
Please note that at the moment the functionality of the host scripts that it can run is limited, at the moment it only runs a single command. | ||
|
||
|
||
Start the listener | ||
------------------ | ||
|
||
The listener can be run with the following command:: | ||
|
||
|
||
$ mercurio-run.py | ||
|
||
|
||
It will show some output once the instruction has been received and the command is being executed. | ||
|
||
|
||
|
||
Behind the scenes | ||
----------------- | ||
|
||
The listener expects the target to be passed in the following form:: | ||
|
||
target=production | ||
|
||
After that it determines from the confing file what command needs to be run according to the target passed | ||
|
||
If you require more complex functionality on your deployment, I suggest you look into fabric. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import os | ||
import ConfigParser | ||
import subprocess | ||
|
||
from datetime import datetime | ||
from serial import Serial, serialutil | ||
from clint.textui import puts, colored | ||
|
||
TIMEOUT = 1 | ||
MERCURIO_CONFIG_NAME = 'mercurio.cfg' | ||
|
||
|
||
def _dict_from_readline(line): | ||
"""Creates a dictionary from the raw input from the serial. | ||
e.g. | ||
target=something | ||
Is transformed into | ||
{ 'target': 'something' } | ||
""" | ||
try: | ||
items = ''.join(line.splitlines()).split('=', 1) | ||
except ValueError: | ||
items = None | ||
if items and len(items) == 2: | ||
return dict([items]) | ||
return {} | ||
|
||
|
||
def _find_relative_file(filename): | ||
config_path = os.path.join(os.getcwd(), MERCURIO_CONFIG_NAME) | ||
if os.path.exists(config_path): | ||
return os.path.abspath(config_path) | ||
return None | ||
|
||
|
||
def _read_config_file(): | ||
"""Reads the config file from the current directory""" | ||
filename = _find_relative_file(MERCURIO_CONFIG_NAME) | ||
if not filename: | ||
raise ValueError('``mercurio.cfg`` file is missing.') | ||
config = ConfigParser.ConfigParser() | ||
config.readfp(open(filename)) | ||
config_dict = { | ||
'port': config.get('general', 'port'), | ||
'targets': dict([(i[0], i[1]) for i in config.items('targets')]), | ||
} | ||
return config_dict | ||
|
||
|
||
def _prepare_command(command): | ||
"""Prepares a single command to be executed by a subprocess""" | ||
return command.split(' ') | ||
|
||
|
||
def listen(): | ||
config = _read_config_file() | ||
if not 'port' in config or not config['port']: | ||
puts(colored.red('ERROR: port missing in ``mercurio.cfg`` file. ' | ||
'Try running ``python -m serial.tools.list_ports``' | ||
' to figure out the port of the device.')) | ||
exit(0) | ||
port = config['port'] | ||
try: | ||
serial = Serial(port, 9600, timeout=TIMEOUT) | ||
except serialutil.SerialException: | ||
puts(colored.red('ERROR: Mercurio device ' | ||
'not connected nor detected.')) | ||
exit(0) | ||
puts(colored.yellow('Mercurio is listening on %s.' % serial.portstr)) | ||
while True: | ||
data = _dict_from_readline(serial.readline()) | ||
if not 'target' in data: | ||
# Ignore any other output that doesn't have a target | ||
continue | ||
destination = data['target'].lower().rstrip() | ||
if not destination in config: | ||
# Inform that we received an unknown target | ||
puts(colored.red("Target %s not found" % destination)) | ||
puts(colored.yellow("Instructions received.")) | ||
targets = config['targets'] | ||
command_args = _prepare_command(targets[destination]) | ||
puts(colored.yellow("Mercurio delivering to target:" | ||
" %s" % destination.title())) | ||
puts(colored.green(targets[destination])) | ||
puts('-' * 60) | ||
# ``subprocess.call`` will wait for the command to complete. | ||
# no need of blocking the next execution since | ||
# it won't be available until this is completed | ||
subprocess.call(command_args) | ||
puts('-' * 60) | ||
puts(colored.yellow("Mercurio sucessfuly delivered on" | ||
" %s." % datetime.now())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/usr/bin/env python | ||
from mercurio import engine | ||
|
||
if __name__ == "__main__": | ||
engine.listen() | ||
print "Done..." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#!/usr/bin/env python | ||
from setuptools import setup, find_packages | ||
|
||
setup(name='mercurio', | ||
version='0.1', | ||
description='Transmits messages between the arduino box and this listener', | ||
long_description='Transmit messages between Arduino and this listener', | ||
author='Alfredo Aguirre', | ||
author_email='alfredo@madewithbyt.es', | ||
scripts=['mercurio/mercurio-run.py'], | ||
license='MIT', | ||
eurl='http://github.com/alfredo/mercurio_listener/', | ||
include_package_data=True, | ||
classifiers=[ | ||
'Development Status :: 0.1 Alpha', | ||
'Intended Audience :: Makers', | ||
'License :: MIT License', | ||
'Operating System :: OS Independent', | ||
'Programming Language :: Python', | ||
'Topic :: Utilities', | ||
], | ||
packages=find_packages(exclude=['tests']), | ||
requires=['pyserial', 'clint'], | ||
install_requires=['pyserial', 'clint'], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from mercurio import engine | ||
|
||
|
||
def test_dict_from_readline_with_valid_input(): | ||
value = "target=something" | ||
result = engine._dict_from_readline(value) | ||
assert result, {'target': 'something'} | ||
|
||
|
||
def test_dict_from_readline_with_empty_input(): | ||
value = "\n\r" | ||
result = engine._dict_from_readline(value) | ||
assert result == {} | ||
|
||
|
||
def test_dict_from_readline_with_invalid_input(): | ||
value = "somethinginvalid" | ||
result = engine._dict_from_readline(value) | ||
assert result == {} | ||
|
||
|
||
def test_prepare_command(): | ||
command = "fab production deploy" | ||
result = engine._prepare_command(command) | ||
assert result == ['fab', 'production', 'deploy'] |