#!/usr/bin/env python3

import os

scriptpath = os.path.realpath(__file__)
aptdir = os.path.dirname(scriptpath)

import email.utils
import git
import shutil
import subprocess
import sys
import json

class cd:
    """Context manager for changing the current working directory"""
    def __init__(self, newPath):
        self.newPath = os.path.expanduser(newPath)

    def __enter__(self):
        self.savedPath = os.getcwd()
        os.chdir(self.newPath)

    def __exit__(self, etype, value, traceback):
        os.chdir(self.savedPath)

repo = os.path.expanduser('~/OpenModelica-source')
debianapt = os.path.expanduser('/var/www/build.openmodelica.org/apt')
aptbuild = os.getcwd()
target = debianapt + '/pool/contrib'
control = os.path.expanduser('~/OpenModelicaBuildScripts')
debfiles = control + '/debian'

if not os.path.exists(repo):
  subprocess.check_call(['git', 'clone', '--recursive', 'https://openmodelica.org/git-readonly/OpenModelica.git', repo])
if not os.path.exists(control):
  subprocess.check_call(['git', 'clone', '--recursive', 'https://openmodelica.org/git-readonly/OpenModelicaBuildScripts.git', control])

with cd(debfiles):
  subprocess.check_call(['git', 'reset', "--hard"])
  subprocess.check_call(['git', 'checkout', "--force", "master"])
  subprocess.check_call(['git', 'clean', '-fdx'])
  subprocess.check_call(['git', 'pull', '--ff'])
  subprocess.check_call(['git', 'reset', "--hard", "origin/master"])

filesToKeep = []

def build(hash, buildScriptsBranch=None):
  global filesToKeep
  if buildScriptsBranch is None:
    buildScriptsBranch="master"
  with cd(repo):
    subprocess.check_call(['git', 'fetch'])
    subprocess.check_call(['git', 'fetch', '--tags'])

  r = git.repo.Repo(repo)
  revision = r.git.describe(["--abbrev=7", "--tags","--match=v*.*.*",hash])[1:].replace('-', '~', 1)

  filesToKeepLocal = [(target + "/openmodelica_" + revision + f) for f in [".orig.tar.xz", "-1.debian.tar.xz", "-1.dsc"]]
  filesToKeep += filesToKeepLocal
  if sum(not os.path.exists(f) for f in filesToKeepLocal) == 0:
    print("Up-to-date " + ", ".join(filesToKeepLocal))
    return revision
  print("Missing " + ", ".join(filesToKeepLocal))

  with cd(repo):
    subprocess.check_call(['git', 'reset', '--hard', hash])
    subprocess.check_call(['git', 'submodule', 'update', '--force', '--init', '--recursive'])
    subprocess.check_call(['git', 'submodule', 'foreach', '--recursive', "git fetch --tags && git clean -fdxq -e /git -e /svn -e 'runtest.db*'"])
    subprocess.check_call(['git', 'clean', '-fdxq'])

  try:
    romedit = git.repo.Repo(repo+"/OMEdit")
  except git.exc.InvalidGitRepositoryError:
    romedit = r
  omedit_revision = "OMEdit " + romedit.git.describe(["--tags","--match=v*.*.*"])[1:].replace('-', '~', 1)
  roms = git.repo.Repo(repo+"/OMSimulator")
  omsimulator_revision = roms.git.describe(["--tags","--match=v*.*.*"])[1:].replace('-', '~', 1)

  print("Need to create tarball")
  print([target + "/openmodelica_" + revision + f for f in [".orig.tar.xz", "-1.debian.tar.xz", "-1.dsc"]])

  tmpdir = os.path.expanduser('~/tmp/' + revision)
  if os.path.exists(tmpdir):
    shutil.rmtree(tmpdir)
  os.makedirs(tmpdir)

  with cd(debfiles):
    subprocess.check_call(['git', 'reset', "--hard"])
    subprocess.check_call(['git', 'clean', '-fdx'])
    subprocess.check_call(['git', 'checkout', '--force', buildScriptsBranch])
    subprocess.check_call(['git', 'clean', '-fdx'])
    subprocess.check_call(['git', 'reset', "--hard", "origin/%s" % buildScriptsBranch])
  with cd(repo):
    subprocess.check_call([aptdir + '/git-archive-all', '%s/openmodelica_%s.tar' % (tmpdir, revision)])
  with cd(tmpdir):
    subprocess.check_call(['tar', 'xf', 'openmodelica_%s.tar' % revision])
    os.remove('openmodelica_%s.tar' % revision)
    for d in ['testsuite', 'doc', 'OMOptim',
              'OMSimulator/OMTLMSimulator/CompositeModels',
              'OMSimulator/testsuite'
             ]:
      if os.path.exists('openmodelica_%s/%s' % (revision,d)): # delete only if is there!
        shutil.rmtree('openmodelica_%s/%s' % (revision,d))
    open('openmodelica_%s/REVISION' % revision, "w").write(revision)
    open('openmodelica_%s/OMEdit/REVISION' % revision, "w").write(omedit_revision)
    open('openmodelica_%s/OMSimulator/version.txt' % revision, "w").write(omsimulator_revision)
    subprocess.check_call(['tar', 'cJf', 'openmodelica_%s.orig.tar.xz' % revision, 'openmodelica_%s' % revision])
    shutil.copytree(debfiles, 'openmodelica_%s/debian' % revision, ignore=shutil.ignore_patterns(".git"))
    with cd(tmpdir+"/openmodelica_" + revision):
      subprocess.check_call(['sed', '-i', 's/@REV@/%s/' % revision, 'debian/changelog'])
      subprocess.check_call(['sed', '-i', '-e', 's/@REV@/%s/' % revision, '-e', "s/@TIME@/%s/" % email.utils.formatdate(), 'debian/changelog'])
      subprocess.check_call(['debuild', '-d', '-us', '-uc', '-S'])
    for f in [".orig.tar.xz", "-1.debian.tar.xz", "-1.dsc"]:
      shutil.copyfile('openmodelica_' + revision + f, target + '/openmodelica_' + revision + f)
    shutil.rmtree(tmpdir)
  with cd(debfiles):
    subprocess.check_call(['git', 'checkout', 'master'])

  open(aptbuild + "/apt-ftparchive/nightly.sources", "w").write("pool/contrib/openmodelica_%s-1.dsc" % revision)
  with cd(debianapt):
    subprocess.check_call(['apt-ftparchive', 'generate', aptbuild + "/apt-ftparchive/apt-ftparchive.conf"])
    res = subprocess.check_output(['apt-ftparchive', '-c', aptbuild + '/apt-ftparchive/apt-nightly.conf', 'release', debianapt + '/dists/nightly/'])
    open(debianapt + '/dists/nightly/Release', 'wb').write(res)
    if os.path.exists('dists/nightly/Release.gpg'):
      os.remove('dists/nightly/Release.gpg')
    subprocess.check_call(['gpg', '--batch=yes', '-abs', '-o', 'dists/nightly/Release.gpg', 'dists/nightly/Release'])
  open(control + "/nightly-macports", "w").write(revision)
  return revision

projects = json.load(open(aptbuild + "/projects.json"))

build("v"+projects["Projects"]["OpenModelica"]["release"].replace("~","-"),
      buildScriptsBranch=projects["Projects"]["OpenModelica"].get("release-buildscriptbranch"))

stablebranch = projects["Projects"]["OpenModelica"].get("stable-followbranch")
if stablebranch:
  revision = build("origin/"+stablebranch, buildScriptsBranch=projects["Projects"]["OpenModelica"].get("stable-buildscriptbranch"))
  if revision is not None:
    if revision != projects["Projects"]["OpenModelica"]["stable"]:
      projects["Projects"]["OpenModelica"]["stable"] = revision
      json.dump(projects, open(aptbuild + "/projects.json", "w"), sort_keys = True, indent = 2)
else:
  build("v"+projects["Projects"]["OpenModelica"]["stable"].replace("~","-"),
        buildScriptsBranch=projects["Projects"]["OpenModelica"].get("stable-buildscriptbranch"))

eb = projects["Projects"]["OpenModelica"].get("extra-branches")
for branch in (eb or {}).keys():
  revision = build("origin/"+branch, buildScriptsBranch=eb[branch]["scriptbranch"])
  if revision is not None:
    if revision != eb[branch]["revision"]:
      eb[branch]["revision"] = revision
      json.dump(projects, open(aptbuild + "/projects.json", "w"), sort_keys = True, indent = 2)

revision = build("origin/master")
if revision is not None:
  if revision != projects["Projects"]["OpenModelica"]["nightly"]:
    projects["Projects"]["OpenModelica"]["nightly"] = revision
    json.dump(projects, open(aptbuild + "/projects.json", "w"), sort_keys = True, indent = 2)

open(target+"/.keep", "w").write("\n".join(filesToKeep))
