Skip to content

Commit

Permalink
Merge pull request #29 from mogproject/develop
Browse files Browse the repository at this point in the history
Develop #17
  • Loading branch information
mogproject committed Jan 11, 2015
2 parents 5488c62 + 48e73af commit b02a32e
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 10 deletions.
12 changes: 6 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ Create ``~/.artifact-cli`` file and write credentials for AWS like this.::
5. Check connection
-------------------

Now, you are ready for using ``art`` command in the shell.
Just list your artifacts.::
| Now, you are ready for using ``art`` command in the shell.
| Just list your artifacts.::
$ art list GROUP_ID
[INFO] No artifacts.
Expand All @@ -112,8 +112,8 @@ Of course, there are no artifacts!
6. Build the artifact
---------------------

Building is outside the reach of this tool.
In other words, you can build as you like.
| Building is outside the reach of this tool.
| In other words, you can build as you like.
7. Upload the artifact
----------------------
Expand All @@ -124,8 +124,8 @@ In the builder's environment, you can upload the artifact to Amazon S3.::

Specify group id and your local file path.

Artifact ID, version and packaging(=extension) are automatically parsed from the given file name.
In this case, artifact ID is ``your-artifact``, version is ``0.0.1`` and packaging is ``jar``.
| Artifact ID, version and packaging(=extension) are automatically parsed from the given file name.
| In this case, artifact ID is ``your-artifact``, version is ``0.0.1`` and packaging is ``jar``.
8. View the artifact information
--------------------------------
Expand Down
14 changes: 10 additions & 4 deletions src/artifactcli/driver/s3driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from boto.s3.key import Key
from boto.s3.connection import OrdinaryCallingFormat
from basedriver import BaseDriver
from artifactcli.util import assert_type
from artifactcli.util import assert_type, ProgressBar

DEFAULT_REGION = 'us-east-1'
DEFAULT_INDEX_PREFIX = '.meta/index-'
Expand Down Expand Up @@ -99,12 +99,16 @@ def upload(self, local_path, remote_path, md5):
"""
k = Key(self.bucket())
k.key = remote_path
logging.info('Uploading file: %s' % self.s3_url(self.bucket_name, remote_path))
k.set_contents_from_filename(local_path)

with ProgressBar():
k.set_contents_from_filename(local_path)

remote_md5 = self.bucket().get_key(remote_path).etag.strip('"')
assert md5 is None or md5 == remote_md5, \
'Failed to check MD5 digest: local=%s, remote=%s' % (md5, remote_md5)

logging.info('Uploaded: %s' % self.s3_url(self.bucket_name, remote_path))

def download(self, remote_path, local_path, md5):
"""
Download file from S3 bucket.
Expand All @@ -121,7 +125,9 @@ def download(self, remote_path, local_path, md5):
assert md5 is None or md5 == remote_md5, \
'Failed to check MD5 digest: local=%s, remote=%s' % (md5, remote_md5)

k.get_contents_to_filename(local_path)
with ProgressBar():
k.get_contents_to_filename(local_path)

logging.info('Downloaded: %s' % local_path)

def delete(self, remote_path, md5):
Expand Down
1 change: 1 addition & 0 deletions src/artifactcli/util/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .caseclass import CaseClass
from .asserttype import assert_type
from .progressbar import ProgressBar
from .unicodeutil import *
65 changes: 65 additions & 0 deletions src/artifactcli/util/progressbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import sys
import threading
from Queue import Queue


class ProgressBar(object):
"""
Print progress bar in the separated thread
"""

def __init__(self, interval=1, fp=sys.stdout):
"""
Start thread for progress bar
:param interval: interval seconds to write dots
:param fp: file pointer to write
"""
self.interval = interval
self.fp = fp
self.ex_queue = Queue() # store all exceptions raised in thread

# create event for handling termination
self.__stop_event = threading.Event()

# create and start new thread
self.thread = threading.Thread(target=lambda: self.__capture_exceptions(self.__target))
self.thread.start()

def stop(self):
"""
Terminate progress bar thread
"""
self.__stop_event.set()
self.thread.join()

# check thread's exceptions
if not self.ex_queue.empty():
raise self.ex_queue.get_nowait()

def __capture_exceptions(self, f):
"""
Wrapper function to capture all exceptions which are raised in the thread
"""
try:
f()
except Exception as e:
self.ex_queue.put(e)
raise e

def __target(self):
"""
Inner method for writing dots in the separated thread
"""
event = self.__stop_event

while not event.is_set():
self.fp.write('.')
self.fp.flush()
event.wait(self.interval)
self.fp.write('\n')

def __enter__(self):
return self

def __exit__(self, *args, **kwargs):
self.stop()
46 changes: 46 additions & 0 deletions tests/artifactcli/util/test_progressbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import unittest
from StringIO import StringIO
import time
from artifactcli.util.progressbar import ProgressBar


class TestProgressBar(unittest.TestCase):
def test_progress_bar(self):
fp = StringIO()
p = ProgressBar(0.6, fp)
time.sleep(1)
p.stop()
s = fp.getvalue()
fp.close()
self.assertEqual(s, '..\n')

def test_progress_bar_with(self):
fp = StringIO()
with ProgressBar(0.6, fp):
time.sleep(1)
s = fp.getvalue()
fp.close()
self.assertEqual(s, '..\n')

def test_progress_bar_runtime_error(self):
fp = StringIO()
try:
with ProgressBar(0.6, fp):
time.sleep(1)
raise RuntimeError
except RuntimeError:
pass

time.sleep(0.5)
s = fp.getvalue()
fp.close()
self.assertEqual(s, '..\n')

def test_progress_bar_io_error(self):
fp = StringIO()
p = ProgressBar(0.6, fp)
time.sleep(1)
fp.close()
time.sleep(1)

self.assertRaises(ValueError, p.stop)

0 comments on commit b02a32e

Please sign in to comment.