Permalink
Browse files

vivado test runner added

  • Loading branch information...
KennethWilke
KennethWilke committed Mar 17, 2016
1 parent dce7061 commit ee746a5e9e708badfb504bd5716852d5acb51f4b
Showing with 224 additions and 102 deletions.
  1. +1 −0 CHANGES.txt
  2. +3 −0 MANIFEST
  3. +2 −0 README.md
  4. +17 −2 bin/packilog
  5. +17 −2 docs/manifest_format.md
  6. +2 −97 libpackilog/__init__.py
  7. +97 −0 libpackilog/pull.py
  8. +40 −0 libpackilog/test/__init__.py
  9. +44 −0 libpackilog/test/vivado.py
  10. +1 −1 setup.py
@@ -1,2 +1,3 @@
v0.0.3, March 17th 2016 -- Vivado test runner added
v0.0.2, March 2nd 2016 -- Packageurl handler added
v0.0.1, March 2nd 2016 -- Initial prototype
@@ -6,3 +6,6 @@ requirements.txt
setup.py
bin/packilog
libpackilog/__init__.py
libpackilog/pull.py
libpackilog/test/__init__.py
libpackilog/test/vivado.py
@@ -9,3 +9,5 @@ Packilog is currently distributed via [pypi](https://pypi.python.org/pypi/Packil
## Usage

Packilog does not yet offer much functionality, basic usage so far involves creating a local `packilog.json` file following the [manifest format](docs/manifest_format.md), then running `packilog`. The `-f` flag can be used to force overwrite of local files.

The `-t` flag can be used to kick off tests for the local package after handling dependencies, `-T` can be used to override the package default or auto-discovered test runner.
@@ -1,17 +1,32 @@
#!/usr/bin/python
import argparse
import os
import sys
import json
import libpackilog

argparser = argparse.ArgumentParser(description="Pull in SystemVerilog code.")
argparser.add_argument('-f', '--force', action='store_true')
argparser.add_argument('-t', '--test', action='store_true')
argparser.add_argument('-T', '--test-driver', type=str)

args = argparser.parse_args()

manifest = None
if os.path.exists('packilog.json'):
manifest = json.load(open('packilog.json'))
else:
print >> sys.stderr, "Error: packilog.json not found"
sys.exit(1)

if manifest:
libpackilog.pull_in_dependencies(manifest, force=args.force)
if args.test_driver:
manifest['test_driver'] = args.test_driver

libpackilog.pull_in_dependencies(manifest, force=args.force)

if args.test:
if(libpackilog.test_package(manifest)):
print "Package Test Result: PASS"
else:
print "Package Test Result: FAIL"
sys.exit(1)
@@ -4,7 +4,7 @@ This document describes the format of the `packilog.json` manifest files. This f

## Top level object

All Packilog manifest files should be valid JSON, with a JSON object as the root. Currently there are two supported members of this root object, `files` and `dependencies`.
All Packilog manifest files should be valid JSON, with a JSON object as the root. Currently there are four supported members of this root object, `files`, `dependencies`, `tests` and `test_driver`.

```json
{
@@ -20,7 +20,14 @@ All Packilog manifest files should be valid JSON, with a JSON object as the root
"source": "http://awesome.verilog.source/somethingcool.sv",
"filename": "somethingawesome.sv"
}
]
],
"tests":
[
"test_something",
"test_everything"
],
"test_driver": "vivado"
}
```

## Files list
@@ -44,3 +51,11 @@ The `filename` member is the filename that the source code should be saved as.
The `packageurl` type dependency pulls in a package from a remote URL. It requires a `source` object member.

The `source` member is a URL path to a Packilog package, the dependency handler will look for a `packilog.json` manifest file relative to the path specified, then pull in code based on the contents of that manifest.

## Tests

The `tests` member is a list of test module names to use as a top module during simulation.

## Test driver

The `test_driver` member can be used to specify which test driver to use with this library, this can be overridden in the CLI.
@@ -1,97 +1,2 @@
import requests
import os
import json


def pull_in_dependencies(manifest, force=False):
''' Handles pulling in dependencies '''
# Return immediately if there are no dependencies to handle
if 'dependencies' not in manifest:
return

for dependency in manifest['dependencies']:
if dependency['type'] not in dependency_handlers:
error = "ERROR: There is no handler for dependency type '{0}'."
print error.format(dependency['type'])
return
else:
dependency_handlers[dependency['type']](dependency, force)


def file_dependency(dependency, force=False):
''' Pull down a file-type dependency '''
if 'source' not in dependency:
print 'source for a file-based dependency was not defined'
return
if 'filename' not in dependency:
print 'filename for a file-based dependency was not defined'
return

source = dependency['source']
filename = dependency['filename']

# Request file
req = requests.get(source)
if req.status_code != 200:
error = "Failed to download dependency source from {0}: {1} {2}"
print error.format(source, req.status_code, req.reason)
return

# Write file
if os.path.exists(filename) and not force:
if req.text == open(filename).read():
print '{0} is up to date'.format(filename)
else:
error = "File {0} already exists, use -f flag to force overwrite"
print error.format(filename)
return
else:
with open(filename, 'w') as fp:
fp.write(req.text)
print '{0} downloaded from {1}'.format(filename, source)


def packageurl_dependency(dependency, force=False):
''' Pulls down a package via URL '''
if 'source' not in dependency:
print 'source for a packageurl-based dependency was not defined'
return

source = dependency['source']

# Get package manifest
source_manifest = source + '/packilog.json'
req = requests.get(source_manifest)
if req.status_code != 200:
error = "Failed to download dependency manifest from {0}: {1} {2}"
print error.format(source_manifest, req.status_code, req.reason)
return

package_manifest = json.loads(req.text)
# Recursively handle dependencies
pull_in_dependencies(package_manifest)

# Pull in files referenced
if 'files' in package_manifest:
for filename in package_manifest['files']:
sourcepath = '{0}/{1}'.format(source, filename)
req = requests.get(sourcepath)
if req.status_code != 200:
error = "Failed to download dependency source from {0}: {1} {2}"
print error.format(sourcepath, req.status_code, req.reason)
return
if os.path.exists(filename) and not force:
if req.text == open(filename).read():
print '{0} is up to date'.format(filename)
else:
error = "File {0} already exists, use -f flag to force overwrite"
print error.format(filename)
return
else:
with open(filename, 'w') as fp:
fp.write(req.text)
print '{0} downloaded from {1}'.format(filename, source)


dependency_handlers = {'file': file_dependency,
'packageurl': packageurl_dependency}
from .test import *
from .pull import *
@@ -0,0 +1,97 @@
import requests
import os
import json


def pull_in_dependencies(manifest, force=False):
''' Handles pulling in dependencies '''
# Return immediately if there are no dependencies to handle
if 'dependencies' not in manifest:
return

for dependency in manifest['dependencies']:
if dependency['type'] not in dependency_handlers:
error = "ERROR: There is no handler for dependency type '{0}'."
print error.format(dependency['type'])
return
else:
dependency_handlers[dependency['type']](dependency, force)


def file_dependency(dependency, force=False):
''' Pull down a file-type dependency '''
if 'source' not in dependency:
print 'source for a file-based dependency was not defined'
return
if 'filename' not in dependency:
print 'filename for a file-based dependency was not defined'
return

source = dependency['source']
filename = dependency['filename']

# Request file
req = requests.get(source)
if req.status_code != 200:
error = "Failed to download dependency source from {0}: {1} {2}"
print error.format(source, req.status_code, req.reason)
return

# Write file
if os.path.exists(filename) and not force:
if req.text == open(filename).read():
print '{0} is up to date'.format(filename)
else:
error = "File {0} already exists, use -f flag to force overwrite"
print error.format(filename)
return
else:
with open(filename, 'w') as fp:
fp.write(req.text)
print '{0} downloaded from {1}'.format(filename, source)


def packageurl_dependency(dependency, force=False):
''' Pulls down a package via URL '''
if 'source' not in dependency:
print 'source for a packageurl-based dependency was not defined'
return

source = dependency['source']

# Get package manifest
source_manifest = source + '/packilog.json'
req = requests.get(source_manifest)
if req.status_code != 200:
error = "Failed to download dependency manifest from {0}: {1} {2}"
print error.format(source_manifest, req.status_code, req.reason)
return

package_manifest = json.loads(req.text)
# Recursively handle dependencies
pull_in_dependencies(package_manifest)

# Pull in files referenced
if 'files' in package_manifest:
for filename in package_manifest['files']:
sourcepath = '{0}/{1}'.format(source, filename)
req = requests.get(sourcepath)
if req.status_code != 200:
error = "Failed to download dependency source from {0}: {1} {2}"
print error.format(sourcepath, req.status_code, req.reason)
return
if os.path.exists(filename) and not force:
if req.text == open(filename).read():
print '{0} is up to date'.format(filename)
else:
error = "File {0} already exists, use -f flag to force overwrite"
print error.format(filename)
return
else:
with open(filename, 'w') as fp:
fp.write(req.text)
print '{0} downloaded from {1}'.format(filename, source)


dependency_handlers = {'file': file_dependency,
'packageurl': packageurl_dependency}
@@ -0,0 +1,40 @@
import vivado
import sys

test_drivers = {'vivado': vivado}

def test_package(manifest):
''' Runs tests in the package '''
if 'tests' not in manifest:
print "No tests in manifest"
return False

if 'test_driver' in manifest:
driver = test_drivers[mainfest['test_driver']]
else:
for drivername, test_driver in test_drivers.iteritems():
if test_driver.check():
driver = test_driver
print "Using {0} testing driver".format(drivername)

driver.build()

package_passed = True
for test in manifest['tests']:
if not run_test(driver, test):
package_passed = False

if package_passed:
driver.cleanup()

return package_passed


def run_test(driver, test):
print 'Running test module "{0}"'.format(test)
if driver.test(test):
print "Result: PASS"
return True
else:
print "Result: FAIL"
return False
@@ -0,0 +1,44 @@
import subprocess


def check():
''' Returns True if test can be ran '''
try:
subprocess.check_output(['which', 'xvlog'])
subprocess.check_output(['which', 'xelab'])
subprocess.check_output(['which', 'xsim'])
except:
return False

return True


def build():
''' Performs build step '''
print "Building tests."
subprocess.check_output(['xvlog --sv *.sv tests/*.sv'],
shell=True)


def test(test_top):
''' Runs the test '''
print "Simulating test module '{0}'.".format(test_top)
test_result = True
subprocess.check_output(['xelab', test_top])
try:
results = subprocess.check_output(['xsim', '-R', test_top])
for line in results.split('\n'):
print line
if line.startswith('Error: '):
test_result = False
except Exception as err:
print "Exception hit when running test: {0}".format(err)
return test_result


def cleanup():
''' Cleans up files from tests '''
subprocess.check_output(['rm -r webtalk*.log webtalk*.jou xsim*.jou ' +
'xsim*.log xvlog.log xvlog.pb xsim.dir ' +
'xelab.log xelab.pb'],
shell=True)
@@ -5,7 +5,7 @@
version="0.0.2",
author="Kenneth Wilke",
author_email="kenneth.wilke@rackspace.com",
packages=['libpackilog'],
packages=['libpackilog', 'libpackilog.test'],
scripts=['bin/packilog'],
url='https://github.com/KennethWilke/Packilog',
license='LICENSE.txt',

0 comments on commit ee746a5

Please sign in to comment.