Skip to content
Snippets Groups Projects
Commit 7441769d authored by Daniel Lyons's avatar Daniel Lyons
Browse files

merging SSA-6315-skeletal-build

parents d32a5945 e4db8825
No related branches found
No related tags found
No related merge requests found
Showing
with 551 additions and 28 deletions
Makefile 0 → 100644
include conda.mk
include setuptools.mk
include alma_fetch.mk
SHELL := /bin/bash
build-base:
@echo "Building..."
make miniconda-installed
make build-python
@echo "Finished build."
build-almafetch:
@echo "Building ALMA fetcher."
make build-alma
%% Cell type:code id: tags:
``` python
import os
from pathlib import Path
import platform
import sys
from typing import List, Optional, TextIO
```
%% Cell type:markdown id: tags:
A directory contains a project if there is a `setup.py` file in it.
%% Cell type:code id: tags:
``` python
projects = list(proj for (proj, subdirs, files) in os.walk(Path()) if 'setup.py' in files)
projects
```
%% Output
['./shared/schema',
'./shared/support',
'./shared/messaging/events',
'./apps/cli/executables/ingestion',
'./apps/cli/executables/weblog_thumbs',
'./apps/cli/executables/alma_reingester',
'./apps/cli/executables/alma_product_fetch',
'./apps/cli/executables/epilogue',
'./apps/cli/executables/datafetcher',
'./apps/cli/executables/vlba_grabber',
'./apps/cli/utilities/s_code_project_updater',
'./apps/cli/utilities/proprietary_setter',
'./apps/cli/utilities/mr_clean',
'./apps/cli/utilities/faultchecker',
'./apps/cli/utilities/mr_books',
'./apps/cli/utilities/dumplogs',
'./apps/cli/utilities/datafinder',
'./apps/cli/utilities/qa_results',
'./apps/cli/launchers/pymygdala',
'./apps/cli/launchers/wf',
'./services/archive']
%% Cell type:markdown id: tags:
Here are some things we know about projects:
- Every project has a name, which is the same as the name of the directory that contains it.
- Every project has a version, which happens to be in a file in `src/$PROJECT/_version.py` in the same format
- Every project has certain dependencies, which are enumerated in the setup.py as `install_requires`
Let's build up this abstraction.
%% Cell type:code id: tags:
``` python
class Project:
def __init__(self, path: Path):
self.path = path
self.name = path.name
@property
def version(self) -> str:
"""Compute and return the version in the _version.py file under the project."""
# to compute the version, we must locate and parse the _version.py file
version_file = self.path / 'src' / self.name / '_version.py'
# this line is basically cribbed from the standard setup.py file
return version_file.open().readlines()[-1].split()[-1].strip("\"'")
@property
def dependencies(self) -> List[str]:
"""Returns the list of dependencies under this project"""
# to compute the dependencies, we have to do something a bit more gross
# we have to open the setup.py file and look for a line with "install_requires"
# once we have that line, we have to parse out the Python list
# we can go ahead and cheat here with eval() for today.
#
# Unfortunately, this doesn't work if they span multiple lines, which is a
# frequent occurrence
setup_file = self.path / 'setup.py'
for line in setup_file.open().readlines():
if 'install_requires' in line:
return eval(line.split('=')[1].strip().strip(','))
# if we made it here, we never found that line, so this project
# has no dependencies; let's make life easy on ourselves and
# keep the API simple
return []
def __repr__(self) -> str:
return f'<Project name={self.name} version={self.version}>'
p1 = Project(Path('apps/cli/executables/datafetcher'))
p1
```
%% Output
<Project name=datafetcher version=4.0.0a1.dev1>
%% Cell type:code id: tags:
``` python
p1.dependencies
```
%% Output
['requests', 'pycapo']
%% Cell type:markdown id: tags:
The Makefile we want to build is going to have a certain structure. Namely, it should:
- Have a top-level entry point, probably a `.PHONY` that is easy for a parent Makefile to target
- The top-level entry point is going to depend on all the projects we have located
- Each project will be a target, a dependency of the top-level entry point
Based on the project structure we also know this:
- A project rule will depend on that project's dependencies
This should cause the build order to fall out rather naturally.
%% Cell type:code id: tags:
``` python
alma_product_fetch-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz
```
%% Output
'x86_64'
%% Cell type:code id: tags:
``` python
class Makefile:
def __init__(self, projects: List[Project]):
self.projects = projects
def build(self):
output = sys.stdout
self.build_entry_point(output)
self.build_projects(output)
def build_entry_point(self, output: TextIO):
"""This builds the toplevel entry point, ready for inclusion in another Makefile"""
toplevels = ' '.join(self.project_target(project) for project in self.projects)
output.write('.PHONY: all-python-projects\n')
output.write(f'all-python-projects: {toplevels}\n\n')
def project_target(self, project: Project) -> str:
"""This converts a project to a distfile name, so that Make can know if it is up to date"""
return f'{project.path}/dist/{project.name}-{project.version}.macosx-10.9-x86_64.tar.gz'
def build_projects(self, output: TextIO):
"""This generates all of the targets for each project we know about."""
for project in self.projects:
self.build_project(project, output)
def build_project(self, project: Project, output: TextIO):
dependencies = [self.lookup_dependency(dep) for dep in project.dependencies]
target_dependencies = ' '.join(self.project_target(dep) for dep in dependencies if dep)
output.write(f'{self.project_target(project)}: {target_dependencies}\n')
output.write(f'\tcd {project.path} && python setup.py bdist\n\n')
def lookup_dependency(self, project_name: str) -> Optional[Project]:
return next((project for project in self.projects if project.name == project_name), None)
def load_projects() -> List[Project]:
# the next line is commented out due to the fragility of the setup.py parsing logic
# return [Project(Path(proj)) for (proj, subdirs, files) in os.walk(Path()) if 'setup.py' in files]
return [Project(Path('shared/schema')), Project(Path('apps/cli/executables/alma_reingester')), Project(Path('shared/messaging/events'))]
m = Makefile(load_projects())
m.build()
```
%% Output
.PHONY: all-python-projects
all-python-projects: shared/schema/dist/schema-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz apps/cli/executables/alma_reingester/dist/alma_reingester-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz shared/messaging/events/dist/events-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz
shared/schema/dist/schema-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz:
cd shared/schema && python setup.py bdist
apps/cli/executables/alma_reingester/dist/alma_reingester-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz: shared/messaging/events/dist/events-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz shared/schema/dist/schema-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz
cd apps/cli/executables/alma_reingester && python setup.py bdist
shared/messaging/events/dist/events-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz:
cd shared/messaging/events && python setup.py bdist
import os
from pathlib import Path
def setup_project(target, source, env):
dir = str(source[0])[:-9]
home = os.getcwd()
env.Execute("cd {} && python3 setup.py bdist && cd {}".format(dir, home))
builder = Builder(action = setup_project)
env = Environment(BUILDERS = {'Setup' : builder})
projects = list(proj for (proj, subdirs, files) in os.walk(Path()) if "setup.py" in files)
output = []
for path in projects:
name = path.split('/')[-1]
output.append("{}/dist/{}".format(path.replace('.', os.getcwd()), name + "-4.0.0a1.dev1.macosx-10.15-x86_64.tar.gz"))
for src, out in zip(projects, output):
env.Setup(source=src + "/setup.py", target=out)
SHELL := /bin/bash
alma_product_fetch_sources := $(shell find apps/cli/executables/alma_product_fetch -type f)
build-alma: apps/cli/executables/alma_product_fetch/dist/alma_product_fetch-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz
@echo "built"
apps/cli/executables/alma_product_fetch/dist/alma_product_fetch-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz: $(alma_product_fetch_sources)
@echo building alma product fetch
cd apps/cli/executables/alma_product_fetch && \
python setup.py bdist
clean-alma:
rm -f apps/cli/executables/alma_product_fetch/dist/alma_product_fetch-4.0.0a1.dev1.macosx-10.9-x86_64.tar.gz
\ No newline at end of file
......@@ -2,37 +2,25 @@
# -*- coding: utf-8 -*-
from pathlib import Path
from setuptools import setup
VERSION = open('_version.py').readlines()[-1].split()[-1].strip("\"'")
README = Path('README.md').read_text()
requires = [
'pika==1.1.0',
'pycapo==0.3.0',
'bs4==0.0.1',
'beautifulsoup4==4.9.1',
'lxml==4.3.2',
'psycopg2==2.8.5',
'pyinstaller==3.2',
'pyopenssl=19.1.0',
'tox==3.1.3',
'tox-pyenv==1.1.0'
'pika>=1.1,<2',
'pycapo>=0.3.0,<1.0',
'beautifulsoup4>=4.9.1,<5.0',
'lxml>=4.3.2,<5.0',
'psycopg2>=2.8.5,<3.0',
'pyopenssl>=19.1.0,<20.0',
'requests>=2.23,<3.0'
]
tests_require = [
'bs4==0.0.1',
'beautifulsoup4==4.9.1',
'psycopg2==2.8.5',
'pyopenssl=19.1.0',
'pyinstaller==3.2',
'pytest==5.4',
'pytest-runner==4.2',
'tox==3.1.3',
'tox-pyenv==1.1.0',
'pytest>=5.4,<6.0'
]
setup(
name=Path().absolute().name,
version=VERSION,
......@@ -42,10 +30,11 @@ setup(
author_email='dms-ssa@nrao.edu',
url='TBD',
license="GPL",
install_requires=['requests', 'pycapo'],
install_requires=requires,
tests_require=tests_require,
keywords=[],
packages=['datafetcher'],
package_dir={'':'src'},
package_dir={'': 'src'},
classifiers=[
'Programming Language :: Python :: 3.8'
],
......
......@@ -9,11 +9,11 @@ from pathlib import Path
from pycapo import CapoConfig
from src.datafetcher.errors import \
from datafetcher.errors import \
MissingSettingsException, NoProfileException
from src.datafetcher.locations_report import \
from datafetcher.locations_report import \
LocationsReport
from src.datafetcher.utilities import \
from datafetcher.utilities import \
REQUIRED_SETTINGS, get_arg_parser, \
ExecutionSite
......
[buildout]
develop = src
parts = alma-product-fetch
[alma-product-fetch]
recipe = setuprecipe
path = apps/cli/executables/alma_product_fetch
\ No newline at end of file
conda.mk 0 → 100644
SHELL := /bin/bash
os := $(shell uname -s)
conda-install := $(shell which conda)
miniconda-installed conda-install:
# Check if data env is activated
@([ ${CONDA_DEFAULT_ENV} == data ] && conda env update) || \
conda activate data
conda-install:
if [ -z conda-install ]; \
then \
@url="https://repo.anaconda.com/miniconda/" \
if [ "$(os)" == "Darwin" ]; \
then \
file="Miniconda3-latest-MacOSX-x86_64.sh"; \
elif [ "$(os)" == "Linux" ]; \
then \
file="Miniconda3-latest-Linux-x86_64.sh"; \
fi \
wget $(addsuffix $(file),$(url)) -P ${HOME} \
chmod +x ${HOME}/$$file \
$$HOME/$$file \
fi
clean-conda:
conda deactivate
\ No newline at end of file
SHELL := /bin/bash
py := python3
home_dir := $(shell pwd)
setup_dirs := $(shell find . -name setup.py | tr '\n' ' ' | sed "s/setup.py//g")
build-python $(setup_dirs):
@for dir in $(setup_dirs) ; do \
cd $$dir ; \
$(py) setup.py develop ; \
cd $(home_dir) ; \
done
clean-python:
rm -Rf *.pyc *.pyo *~ *.egg-info
\ No newline at end of file
import os
class Recipe:
def __init__(self, buildout, name, options):
options['created'] = "{}/dist/{}".format(options['path'], name + "-4.0.0a1.dev1.tar.bz2")
self.options = options
def install(self):
self.options.created(self.options['created'])
home = os.getcwd()
# cd into correct directory
os.chdir(self.options['path'])
# Run setup.py
os.system("conda run -n data python3 setup.py bdist")
os.chdir(home)
# Deploy conda package to builder
builder_path = "/home/builder.aoc.nrao.edu/content/conda/"
platform = "osx64"
os.system("scp {}/{} builder:{}".format(home, self.options['created'], builder_path + platform))
os.system("ssh builder 'cd {} && conda index'".format(builder_path))
return self.options.created()
update = install
\ No newline at end of file
from setuptools import setup
setup(
name='bdistrecipe',
version='0.1',
py_modules = ['bdistrecipe'],
entry_points = {"zc.buildout": ["default=bdistrecipe:Recipe"]}
)
\ No newline at end of file
import os
class Recipe:
def __init__(self, buildout, name, options):
options['created'] = "{}/envs/{}".format(options['path'], name + options['env'])
self.options = options
def install(self):
self.options.created(self.options['created'])
os.system("source /opt/miniconda3/etc/profile.d/conda.sh && conda activate data")
return self.options.created()
update = install
\ No newline at end of file
from setuptools import setup
setup(
name='condarecipe',
version='0.1',
py_modules = ['condarecipe'],
entry_points = {"zc.buildout": ["default=condarecipe:Recipe"]},
)
\ No newline at end of file
from setuptools import setup
setup(
name='setuprecipe',
version='0.1',
py_modules = ['setuprecipe'],
entry_points = {"zc.buildout": ["default=setuprecipe:Recipe"]},
)
\ No newline at end of file
import os
class Recipe:
def __init__(self, buildout, name, options):
options['created'] = "{}/dist/{}".format(options['path'], name + "-4.0.0a1.dev1.macosx-10.15-x86_64.tar.gz")
self.options = options
def install(self):
self.options.created(self.options['created'])
# home = os.getcwd()
# cd into correct directory
os.chdir(self.options['path'])
os.system("ls -la")
# Run setup.py
os.system("python3 setup.py bdist")
return self.options.created()
update = install
\ No newline at end of file
{% set name = "datafetcher" %}
{% set version = "4.0.0a1.dev1" %}
package:
name: "{{ name|lower }}"
version: "{{ version }}"
build:
entry_points:
- datafetcher = datafetcher.commands:main
script: {{ PYTHON }} setup.py install
source:
path: ../../../apps/cli/executables/datafetcher
requirements:
build:
- python==3.8
- pika>=1.1,<2
- pycapo>=0.3.0,<1.0
- beautifulsoup4>=4.9.1,<5.0
- lxml>=4.3.2,<5.0
- psycopg2>=2.8.5,<3.0
- pyopenssl>=19.1.0,<20.0
- requests>=2.23,<3.0
run:
- python==3.8
- pika>=1.1,<2
- pycapo>=0.3.0,<1.0
- beautifulsoup4>=4.9.1,<5.0
- lxml>=4.3.2,<5.0
- psycopg2>=2.8.5,<3.0
- pyopenssl>=19.1.0,<20.0
- requests>=2.23,<3.0
test:
source_files:
- test/
requires:
- pytest>=5.4,<6.0
commands:
- pytest -vv --log-level=DEBUG --showlocals test/datafetcher_test.py
about:
license: "GPL"
license_family: "GPL"
summary: "NRAO Archive Data Fetcher Script"
{% set name = "events" %}
{% set version = "4.0.0a1.dev1" %}
package:
name: "{{ name|lower }}"
version: "{{ version }}"
source:
path: /Users/nhertz/data/shared/messaging/events
build:
number: 0
script:
- python setup.py install
requirements:
run:
- python=3.8
- pika
- pycapo
about:
license: "GPL"
license_family: "GPL"
summary: "NRAO Archive Data Fetcher Script"
{% set name = "pycapo" %}
{% set version = "0.2.1.post1" %}
{% set version = "0.3.0" %}
package:
name: "{{ name|lower }}"
......@@ -7,7 +7,7 @@ package:
source:
url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz
sha256: 703002d913d4e38a4bcce7748674ef58d4fd63c9fd099316b4643a89955ff361
sha256: 507d47278a66f2a67dc817e2dae533374ad0c8312aed7ab6e23e1b322baef5c6
build:
number: 0
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment