[buildout]
extends =
   ../../component/caddy/buildout.cfg
   ../../component/git/buildout.cfg
   ../../component/bash/buildout.cfg
   ../../component/bash-completion/buildout.cfg
   ../../component/fish-shell/buildout.cfg
   ../../component/tmux/buildout.cfg
   ../../component/tig/buildout.cfg
   ../../component/vim/buildout.cfg
   ../../component/curl/buildout.cfg
   ../../component/coreutils/buildout.cfg
   ../../component/java-jdk/buildout.cfg
   ../../component/fonts/buildout.cfg
   ../../stack/nodejs.cfg
   ../../stack/slapos.cfg
   ../../stack/monitor/buildout.cfg
   ../../stack/resilient/buildout.cfg
   ../../component/defaults.cfg
   ./download-plugins.cfg
   ./buildout.hash.cfg

parts =
  theia-wrapper
  slapos-cookbook
  instance-theia
  instance
  instance-import
  instance-export
  instance-resilient

# default for slapos-standalone
shared-part-list =

# We keep the gcc part in sync with the one from erp5 software, so that when we install
# erp5 inside theia's slapos parts can be shared.
[gcc]
max_version = 0


[nodejs]
<= nodejs-12.18.3

[yarn]
<= yarn-1.17.3

[slapos-standalone]
recipe = zc.recipe.egg
eggs =
  slapos.core
scripts = ${:_buildout_section_name_}
script-path = ${buildout:bin-directory}/${:scripts}
# XXX generate a fake entry point for a non existant module, that will not
# be used because we exit in initialization step
entry-points =
  ${:scripts}=not_used:main
initialization =
  import argparse
  import glob
  import json
  import os
  import signal
  import socket
  import sys
  import time

  import slapos.slap.standalone

  parser = argparse.ArgumentParser()
  parser.add_argument('base_directory')
  parser.add_argument('ipv4')
  parser.add_argument('ipv6')
  parser.add_argument('server_port', type=int)
  parser.add_argument('computer_id')
  parser.add_argument('--sr')
  parser.add_argument('--srtype')
  parser.add_argument('--srparams')
  forwarded_arguments = parser.add_argument_group('forwarded')
  forwarded_arguments.add_argument('master_url')
  forwarded_arguments.add_argument('computer')
  forwarded_arguments.add_argument('partition')
  # cert and key are optional
  forwarded_arguments.add_argument('--cert')
  forwarded_arguments.add_argument('--key')
  args = parser.parse_args()
  shared_part_list = [x.strip() for x in '''${buildout:shared-part-list}'''.splitlines() if x.strip()]
  partition_forward_configuration = (
      slapos.slap.standalone.PartitionForwardAsPartitionConfiguration(
          master_url=args.master_url,
          computer=args.computer,
          partition=args.partition,
          cert=args.cert,
          key=args.key,
          software_release_list=(
            'http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg',
          ),
      ),
  )
  standalone = slapos.slap.standalone.StandaloneSlapOS(
      args.base_directory,
      args.ipv4,
      args.server_port,
      computer_id=args.computer_id,
      shared_part_list=shared_part_list,
      software_root="%s/software" % args.base_directory,
      instance_root="%s/instance" % args.base_directory,
      partition_forward_configuration=partition_forward_configuration,
      slapos_bin="${buildout:bin-directory}/slapos",
  )

  def signal_handler(signum, frame):
    print("Signal {signum} received".format(signum=signum))
    sys.exit()
  signal.signal(signal.SIGTERM, signal_handler)

  standalone.start()
  try:
    partition_count = 20
    if len(glob.glob(os.path.join(standalone.instance_directory, '*'))) < partition_count:
      print("Standalone SlapOS: Formatting {partition_count} partitions".format(
          partition_count=partition_count))
      standalone.format(
          partition_count,
          args.ipv4,
          args.ipv6,
      )
    print("Standalone SlapOS for computer `{}` started".format(args.computer_id))
    # Run instance at least once, to start the supervisor managing instances.
    try:
      standalone.waitForInstance(max_retry=0)
    except slapos.slap.standalone.SlapOSNodeCommandError as e:
      print("Error instanciating: {}".format(e))

    if args.sr:
      try:
        with open(args.srparams) as f:
          params = json.load(f)
      except Exception:
        params = None
      if not isinstance(params, dict):
        params = None
      print("Supplying and Requesting Embedded Software {sr} with type {srtype}".format(
          sr=args.sr, srtype=args.srtype))
      print("With parameters {param_dict} parsed from '{srparams}'".format(
          param_dict=params, srparams=args.srparams))
      standalone.supply(args.sr)
      standalone.request(
          args.sr,
          "Embedded Instance",
          args.srtype,
          partition_parameter_kw=params,
      )

    s = socket.socket(socket.AF_UNIX)
    s.bind('\0' + os.path.join(args.base_directory, 'standalone_ready'))
    s.listen(5)
    print("Standalone SlapOS ready")
    while True:
      s.accept()[0].close()

  finally:
    print("Stopping standalone subsystem")
    standalone.stop()
    print("Exiting")


needs-these-eggs-scripts-in-path =
  ${supervisor:recipe}
  ${slapos-command:recipe}

[supervisor]
recipe = zc.recipe.egg
eggs =
  supervisor
  setuptools

[template-base]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/${:_update_hash_filename_}
output = ${buildout:parts-directory}/${:_buildout_section_name_}

[download-base]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:_update_hash_filename_}
destination = ${buildout:directory}/${:_buildout_section_name_}
output = ${:destination}

[python-language-server]
version = 0.19.0
recipe = plone.recipe.command
command =
  PATH=${git:location}/bin/:$PATH  bash -c "${python3:executable} -m venv --clear ${:location} && \
    . ${:location}/bin/activate && \
    pip install -r ${python-language-server-requirements.txt:output}"
location = ${buildout:parts-directory}/${:_buildout_section_name_}
stop-on-error = true

[python-language-server-requirements.txt]
<= download-base

[theia]
recipe = plone.recipe.command
command = ${bash:location}/bin/bash -c "
  export TMPDIR=${:location}/tmp PATH=${nodejs:location}/bin:$PATH &&
  mkdir -p ${:location} && \
  mkdir -p \$TMPDIR && \
  cd ${:location} && \
  cp ${package.json:rendered} . &&
  cp ${yarn.lock:output} . &&
  ${yarn:location}/bin/yarn && \
  ${yarn:location}/bin/yarn theia build"
location = ${buildout:parts-directory}/${:_buildout_section_name_}
stop-on-error = true
uses = ${yarn.lock:recipe}

[theia-plugins]
recipe = slapos.recipe.build
urls = ${theia-download-plugins:urls}
install =
  import os
  for line in options['urls'].splitlines():
    extension_name, url, md5sum = line.split()
    extract_dir = self.extract(self.download(url, md5sum))
    destination_dir = os.path.join(options['location'], extension_name)
    self.copyTree(guessworkdir(extract_dir), destination_dir)
    os.chmod(destination_dir, 0o750)

[yarn.lock]
<= download-base

[preloadTemplate.html]
<= download-base

[slapos.css.in]
<= download-base

[logo.png]
<= download-base

[package.json]
recipe = slapos.recipe.template:jinja2
template =
  inline:{
      "private": true,
      "theia": {
          "frontend": {
              "config": {
                  "applicationName": "Theia SlapOS",
                  "preferences": {
                      "application.confirmExit": "always",
                      "files.associations": {
                          "*.cfg": "zc-buildout"
                      },
                      "files.enableTrash": false,
                      "files.exclude": {
                          "**.pyc": true,
                          "**.egg-info": true,
                          "__pycache__": true,
                          ".git": true,
                          ".env": true,
                          "**/node_modules/**": true
                      },
                      "files.watcherExclude": {
                          "**/.eggs/**": true,
                          "**/.env/**": true,
                          "**/.git/**": true,
                          "**/node_modules/**": true
                      },
                      "editor.multiCursorModifier": "ctrlCmd",
                      "editor.tabSize": 2,
                      "plantuml.server": "https://plantuml.host.vifib.net/svg/",
                      "plantuml.render": "PlantUMLServer",
                      "gitlens.remotes": [{ "domain": "lab.nexedi.com", "type": "GitLab" }],
                      "java.home": "${java-jdk:location}"
                  }
              }
          },
          "generator": {
              "config": {
                  "preloadTemplate": "${preloadTemplate.html:output}"
              }
          }
      },
      "dependencies": {
          "@theia/callhierarchy": "latest",
          "@theia/console": "latest",
          "@theia/core": "latest",
          "@theia/cpp-debug": "latest",
          "@theia/debug": "latest",
          "@theia/editor": "latest",
          "@theia/editor-preview": "latest",
          "@theia/file-search": "latest",
          "@theia/filesystem": "latest",
          "@theia/getting-started": "latest",
          "@theia/git": "latest",
          "@theia/keymaps": "latest",
          "@theia/markers": "latest",
          "@theia/messages": "latest",
          "@theia/metrics": "latest",
          "@theia/mini-browser": "latest",
          "@theia/monaco": "latest",
          "@theia/navigator": "latest",
          "@theia/outline-view": "latest",
          "@theia/output": "latest",
          "@theia/plugin": "latest",
          "@theia/plugin-ext": "latest",
          "@theia/plugin-ext-vscode": "latest",
          "@theia/preferences": "latest",
          "@theia/preview": "latest",
          "@theia/process": "latest",
          "@theia/scm": "latest",
          "@theia/search-in-workspace": "latest",
          "@theia/task": "latest",
          "@theia/terminal": "latest",
          "@theia/typehierarchy": "latest",
          "@theia/userstorage": "latest",
          "@theia/variable-resolver": "latest",
          "@theia/vsx-registry": "latest",
          "@theia/workspace": "latest",
          "@perrinjerome/theia-open": "latest",
          "@perrinjerome/theia-open-cli": "latest"
      },
      "devDependencies": {
          "@theia/cli": "latest"
      }
    }
rendered = ${buildout:directory}/${:_buildout_section_name_}


[gowork]
install +=
   golang.org/x/tools/gopls@v0.6.6


[cli-utilities]
PATH = ${nodejs:location}/bin:${bash:location}/bin:${fish-shell:location}/bin:${tig:location}/bin:${vim:location}/bin:${tmux:location}/bin:${git:location}/bin:${curl:location}/bin:${python2.7:location}/bin:${buildout:bin-directory}


[theia-wrapper]
recipe = slapos.recipe.template:jinja2
rendered = ${buildout:bin-directory}/${:_buildout_section_name_}
template =
  inline:
  #!/bin/sh
  cd ${theia:location}
  exec ${yarn:location}/bin/yarn theia start "$@"

[theia-open]
recipe = slapos.recipe.template:jinja2
rendered = ${buildout:bin-directory}/${:_buildout_section_name_}
template =
  inline:
  #!/bin/sh
  exec ${nodejs:location}/bin/node ${theia:location}/node_modules/.bin/theia-open "$@"

[instance-theia]
<= template-base
output = ${buildout:directory}/instance-theia.cfg.jinja

[instance]
<= template-base
output = ${buildout:directory}/instance.cfg

[instance-import]
<= template-base
output = ${buildout:directory}/instance-import.cfg.jinja

[instance-export]
<= template-base
output = ${buildout:directory}/instance-export.cfg.jinja

[instance-resilient]
<= download-base