Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redockerize and deproxify #58

Draft
wants to merge 22 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
45e0a3f
Temporarily (?) disable post-generation setup of git, venv, db and no…
jgonggrijp Oct 30, 2024
4a27342
Generate frontend and backend dependency lists using Docker (#16)
jgonggrijp Oct 31, 2024
db6befc
DROPME temporarily disable subproject bootstrapping
jgonggrijp Nov 1, 2024
cd1fdbe
squash! Generate frontend and backend dependency lists using Docker (…
jgonggrijp Nov 1, 2024
ea08831
squash! Generate frontend and backend dependency lists using Docker (…
jgonggrijp Nov 1, 2024
db63f6f
squash! Generate frontend and backend dependency lists using Docker (…
jgonggrijp Nov 1, 2024
50e350c
Revert "DROPME temporarily disable subproject bootstrapping"
jgonggrijp Nov 1, 2024
8c43343
Move Angular shutil.move to end of function
jgonggrijp Nov 5, 2024
fe957db
Practice slash correctness in dockerfile
jgonggrijp Nov 5, 2024
d0b59f9
DROPME disable subproject initialization
jgonggrijp Nov 5, 2024
5fd98de
fixup hopefully indicate the files to copy more unambiguously
jgonggrijp Nov 5, 2024
53c658b
fixup give other copy same treatment
jgonggrijp Nov 5, 2024
e69f522
Revert "DROPME disable subproject initialization"
jgonggrijp Nov 5, 2024
5bb82f4
fixup indicate which stage of bootstrap is in progress
jgonggrijp Nov 5, 2024
e723a4c
DROPME disable most of angular activation
jgonggrijp Nov 5, 2024
a9cd3ef
DROPME disable file deletion as well
jgonggrijp Nov 5, 2024
aa299e3
Revert "DROPME disable file deletion as well"
jgonggrijp Dec 19, 2024
8b0b458
Revert "DROPME disable most of angular activation"
jgonggrijp Dec 19, 2024
a574ccd
Move all of the Angular activation into the Dockerfile-postgenerate (…
jgonggrijp Dec 19, 2024
05a9ca5
Clean up newly introduced post-generation files (#16)
jgonggrijp Dec 19, 2024
8f0089c
DROPME disable subproject init
jgonggrijp Dec 20, 2024
975fdb7
squash! Move all of the Angular activation into the Dockerfile-postge…
jgonggrijp Dec 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"project_title": "DigHum Pro",
"slug": "{{cookiecutter.project_title | lower | replace('-', '') | replace(' ', '_')}}",
"npm_slug": "{{cookiecutter.slug | replace('_', '-')}}",
"app_prefix": "dh",
"description": "{{cookiecutter.project_title}} will humanize all your digits!",
"author": "Research Software Lab, Centre for Digital Humanities, Utrecht University",
Expand Down
65 changes: 6 additions & 59 deletions hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,71 +35,16 @@ def python_path():

def main(argv):
print('\nFiles generated. Performing final steps.')
boot_sup = bootstrap_subprojects()
if not boot_sup:
print(f'\nSubproject initialization failed. Please see {LOGFILE_NAME} for details.')
return 1
try:
activate_frontend()
except Exception as exception:
print(exception)
print("[ERROR] Activating frontend failed!!")
if '{{cookiecutter.frontend}}' == 'backbone' and not generate_backbone_translations(): return 1
venv = create_virtualenv()
pip_tools = backreq = backpack = clone_req = funcreq = funcpack = False
if venv:
adopt_virtualenv(VIRTUALENV)
pip_tools = install_pip_tools()
if pip_tools:
check_version_pip()
check_version_pip_compile()
backreq = compile_backend_requirements()
if backreq:
backpack = install_backend_packages()
clone_req = copy_backreq_to_func()
if clone_req:
funcreq = compile_functest_requirements()
if funcreq:
funcpack = install_functest_packages()
frontpack = install_frontend_packages()
git = setup_git()
gitflow = develop = stage = commit = remote = False
if git:
gitflow = setup_gitflow()
if not gitflow:
develop = create_develop_branch()
if funcreq and frontpack:
stage = git_add()
if stage:
commit = initial_commit()
remote = add_remote()
db = create_db()
if db:
db = grant_db()
migrate = superuser = False
if db and backpack:
migrate = run_migrations()
if migrate:
superuser = create_superuser()
if not all([superuser, remote, commit, gitflow, funcpack]):
print('\nPlease read {} for information on failed commands.'.format(LOGFILE_NAME))
print('\nAlmost ready to go! Just a couple more commands to run:')
print(cd_into_project)
if not venv: print(create_virtualenv)
print(activate_venv)
if not pip_tools: print(install_pip_tools)
if not backreq: print(compile_backend_requirements)
if not clone_req: print(copy_backreq_to_func)
if not funcreq: print(compile_functest_requirements)
if not (backpack and frontpack and funcpack): print(install_all_packages)
if not git: print(setup_git)
if not gitflow and not develop: print(create_develop_branch)
if not stage: print(git_add)
if not commit: print(initial_commit)
if not remote: print(add_remote)
if not db:
print(create_db)
print(grant_db)
if not migrate: print(run_migrations)
if not superuser: print(create_superuser)
print(git_push)
print(yarn_start)
Comment on lines -44 to -102
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some, but not all, of this logic is or will be restored via the bootstrap_subprojects command, which relies on docker-compose.



def generate_backbone_translations():
Expand All @@ -121,6 +66,8 @@ def generate_backbone_translations():
return True


bootstrap_subprojects = make_bootstrap_command('bootstrap')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make_bootstrap_command is currently defined in the bootstrap.py, but will move here.


cd_into_project = Command('', ['cd', SLUG])

create_virtualenv = make_create_venv_command(VIRTUALENV_COMMAND)
Expand Down
7 changes: 7 additions & 0 deletions {{cookiecutter.slug}}/backend/Dockerfile-postgenerate
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM python:3.9

WORKDIR /usr/src/app/backend
COPY requirements.in .
RUN pip install -U pip pip-tools

CMD pip-compile
107 changes: 40 additions & 67 deletions {{cookiecutter.slug}}/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,83 +205,43 @@ def merge_json(target, source):

def activate_frontend():
framework = '{{cookiecutter.frontend}}'
os.rename('package.{{cookiecutter.frontend}}.json', 'package.json')

if framework == 'backbone':
os.rename('frontend.backbone', 'frontend')
shutil.move(op.join('frontend', 'proxy.json'), 'proxy.json')
override_json('package')
elif framework == 'angular':
project_name = '{{cookiecutter.slug}}'.replace('_', '-')
Command(
'Install dependencies',
['yarn', 'install', '--ignore-scripts']
)()
Command(
'Creating project',
['yarn', 'ng', 'new', project_name, '--prefix={{cookiecutter.app_prefix}}',
'--ssr',
'--skip-git=true',
'--skip-install=true',
'--package-manager=yarn',
'--style=scss',
'--routing=true']
)()
shutil.copytree('frontend.angular', project_name, dirs_exist_ok=True)
os.rename(project_name, 'frontend')
shutil.move(op.join('frontend', 'proxy.conf.json'), 'proxy.conf.json')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part of the old activation logic is implemented in the bootstrap stage of the frontend.angular/Dockerfile-postgenerate. This already works as intended.

override_json('package')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is simpy retained and (still) works as intended. The implementation will be moved to the hooks/post_gen_project.py, though.

Command(
'Install frontend dependencies using Yarn',
['yarn'],
cwd="frontend"
)()
# Remove favicon.ico
os.remove(os.path.join('frontend', 'src', 'favicon.ico'))
# Remove editorconfig
os.remove(os.path.join('frontend', '.editorconfig'))
Command(
'ng add @angular/localize',
['yarn', 'ng', 'add', '@angular/localize', '--skip-confirmation'],
cwd="frontend"
)()
Comment on lines -234 to -247
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is implemented in the bootstrap-2 stage of the frontend.angular/Dockerfile-postgenerate. It doesn't work as intended for a surprising reason, which I'll highlight in the Dockerfile.


override_json('angular')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is retained, but appears as deleted in the current diff because I outcommented it in debugging.

Command(
'Creating localizations',
['yarn', 'i18n'],
cwd="frontend"
)()
Comment on lines -250 to -254
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is implemented in the bootstrap-3 stage of the frontend.angular/Dockerfile-postgenerate. I will probably need to debug this as well after we manage to get stage 2 to work.

for lang in '{{cookiecutter.localizations}}'.split(','):
[code, lang_name] = lang.split(':')
with open(f'frontend/locale/messages.xlf', 'r') as file:
messages = file.read()
if code != '{{cookiecutter.default_localization}}':
with open(f'frontend/locale/messages.{code}.xlf', 'w') as file:
# add the target-language attribute after the source-language attribute
targeted = re.sub(r'(source-language="[^"]+"[^>]*)', f'\\g<1> target-language="{code}"', messages)
try:
with open(f'frontend/locale/messages.{code}.json', 'r') as pretranslated:
translations = json.load(pretranslated)
for key, value in translations.items():
targeted = targeted.replace(f'<source>{key}</source>', f'<source>{key}</source>\n <target state="translated">{value}</target>')
os.remove(f'frontend/locale/messages.{code}.json')
except FileNotFoundError:
pass
file.write(targeted)
Comment on lines -255 to -271
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is retained, but currently appears deleted because I outcommented it.

if '{{cookiecutter.frontend_port}}' != '4200':
Command(
'Set frontend port',
['yarn', 'ng', 'config', "projects.{{cookiecutter.slug | replace('_', '-')}}.architect.serve.options.port", '{{cookiecutter.frontend_port}}'],
cwd="frontend"
)()
Comment on lines -272 to -277
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to just drop this. Frontend port customization should no longer be necessary with the finished Docker setup.

# if not angular_bootstrap_2():
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the part where the bootstrap-2 stage of the Dockerfile-postgenerate gets to do its tricks.

# return false
# override_json('angular')
# if not angular_bootstrap_3():
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise for the bootstrap-3 stage.

# return false
# for lang in '{{cookiecutter.localizations}}'.split(','):
# [code, lang_name] = lang.split(':')
# with open(f'frontend/locale/messages.xlf', 'r') as file:
# messages = file.read()
# if code != '{{cookiecutter.default_localization}}':
# with open(f'frontend/locale/messages.{code}.xlf', 'w') as file:
# # add the target-language attribute after the source-language attribute
# targeted = re.sub(r'(source-language="[^"]+"[^>]*)', f'\\g<1> target-language="{code}"', messages)
# try:
# with open(f'frontend/locale/messages.{code}.json', 'r') as pretranslated:
# translations = json.load(pretranslated)
# for key, value in translations.items():
# targeted = targeted.replace(f'<source>{key}</source>', f'<source>{key}</source>\n <target state="translated">{value}</target>')
# os.remove(f'frontend/locale/messages.{code}.json')
# except FileNotFoundError:
# pass
# file.write(targeted)
# shutil.move(op.join('frontend', 'proxy.conf.json'), 'proxy.conf.json')
else:
print('Unknown framework {{cookiecutter.frontend}} specified!')
# remove other frameworks
for path in glob.glob("frontend.*"):
shutil.rmtree(path)
for path in glob.glob("package.*.json"):
os.remove(path)
# for path in glob.glob("frontend.*"):
# shutil.rmtree(path)
# for path in glob.glob("package.*.json"):
# os.remove(path)


def override_json(filename):
Expand All @@ -297,6 +257,19 @@ def override_json(filename):
os.remove(f'frontend/{filename}.overwrite.json')


def make_bootstrap_command(profile):
return Command(
f'Finalize subproject package configuration ({profile})',
['docker', 'compose',
'-f', 'compose-postgenerate.yml',
'--profile', profile,
'up']
)


angular_bootstrap_2 = make_bootstrap_command('bootstrap-2')
angular_bootstrap_3 = make_bootstrap_command('bootstrap-3')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like activate_frontend, this logic will move to the hooks/post_gen_project.py.


install_pip_tools = Command(
'Install pip-tools',
['yarn', 'preinstall'],
Expand Down
37 changes: 37 additions & 0 deletions {{cookiecutter.slug}}/compose-postgenerate.yml
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this compose file has three profiles:

  • bootstrap, which runs as part of hooks/post_gen_project.py:main.
  • bootstrap-2, which runs as part of bootstrap.py:activate_frontend.
  • bootstrap-3, which also runs as part of bootstrap.py:activate_frontend.

The names of the profiles are the same as, and correspond to, the stages in the frontend.angular/Dockerfile-postgenerate. bootstrap-2 and bootstrap-3 are only needed for Angular.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
services:
backend:
profiles: ['bootstrap']
build:
context: ./backend
dockerfile: Dockerfile-postgenerate
volumes:
- ./backend:/usr/src/app/backend
frontend:
profiles: ['bootstrap']
build:
context: ./frontend.{{cookiecutter.frontend}}
dockerfile: Dockerfile-postgenerate
{% if cookiecutter.frontend == 'angular' %}
target: bootstrap
{% endif %}
volumes: &frontend-volumes
- ./frontend:/usr/src/app/frontend
- frnomo:/usr/src/app/frontend/node_modules
{% if cookiecutter.frontend == 'angular' %}
frontend-2:
profiles: ['bootstrap-2']
build: &angular-staged-build
context: ./frontend
dockerfile: ../frontend.angular/Dockerfile-postgenerate
target: bootstrap-2
volumes: *frontend-volumes
frontend-3:
profiles: ['bootstrap-3']
build:
<<: *angular-staged-build
target: bootstrap-3
volumes: *frontend-volumes
{% endif %}

volumes:
frnomo:
39 changes: 39 additions & 0 deletions {{cookiecutter.slug}}/frontend.angular/Dockerfile-postgenerate
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM node:18 as bootstrap

WORKDIR /usr/src/app
RUN yarn init -yp && \
yarn add "@angular/cli@17" && \
yarn ng new {{cookiecutter.npm_slug}} \
--prefix={{cookiecutter.app_prefix}} \
--ssr \
--skip-git=true \
--skip-install=true \
--package-manager=yarn \
--style=scss \
--routing=true

WORKDIR /usr/src/app/{{cookiecutter.npm_slug}}
COPY . .

VOLUME /usr/src/app/frontend
CMD cp package.json package.overwrite.json ../frontend/

FROM bootstrap as bootstrap-2

WORKDIR /usr/src/app/{{cookiecutter.npm_slug}}
COPY package.json ./
RUN rm src/favicon.ico .editorconfig && \
yarn && \
yarn ng add @angular/localize --skip-confirmation

VOLUME /usr/src/app/frontend
CMD cp angular.json angular.overwrite.json ../frontend/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the surprising part that I'm currently running into. At this point in the image layering, the contents of /usr/src/app/{{cookiecutter.npm_sug}} appear to have been reset to how they were at the WORKDIR on line 15. @BeritJanssen do you understand what is going on here?


FROM bootstrap-2 as bootstrap-3

WORKDIR /usr/src/app/{{cookiecutter.npm_slug}}
COPY angular.json ./
RUN yarn ng extract-i18n --output-path locale

VOLUME /usr/src/app/frontend
CMD cp -r * .* ../frontend/
Loading