summaryrefslogblamecommitdiff
path: root/scripts/jobs/integrate/bootstrap
blob: 85be794276d1cb287f867672a5ad5112289416bf (plain) (tree)
1
2
3
4
5
6
7
8
9
              
 


                              


                                                                                                                 
                           
                 




                                                                                                            








                                                                                                                                             
 

                                                                                       






                                                                                                                            
 
                                                                                                                










                                                                                                                             
 








                                                                                                                        
 
                                                                                                           

 










                                                                                                        


              
                                              


                                                                                                               
                                                            
 

                                                                                                                             
 

                                                          




                                                                                                                                                               

                               
                                                                                                                                      

                                                       


                             









                                                                                                                  






                                                                                                 
              
                 


                                                                                                                                                                                            


               








                                                                                                       
 













                                                                            
                                                                                                                                                































                                                                                                                                                                                              
                                                                                                                                                                               

            

                                                                                                    




                                

                                                                                                                             

                                                                                                                          










                                                                                                                                
                                                                                                              
                                                                                                            
                                                                                              


                                                                                                            
                                                                                                                        
                                                                                                                           
                                   





                                                                                                                               
                                                                                                                








                                                                                                                                                      
                                                                                                                       








                                                                                                                                           
                                                                                                                                                                                         



                       





                                                                                                                                                                     
                                                                                       
                                                                                                                                                    






                                                                                                                                                                
                                                                                        
                                                                            








                                                                                                                                     
                                                                           








                                                                                                                                                              

                                                                                                                                                             




                                                                                                                                                  
                                                                   




                                                                                                                                      
                                                                                                                                                                                       



                          
                                                                                                              
                
                                                                                                                                                                         
                                  






                      

 








                                                                                                                                   

 


               









                                                   


                                                                                                                               
   

                                                                                                                 
   
                                                                                                                           
   

                                                                                                                        
 
                                                                                                    





                  
                         
               
                                            

                                                                                                                      
 
                                                                                                                                         


                                       
                                                    


                         
                                                        

                                                                   





                                                       

                                                     
                                                                                                                       
                            




















                                                                                                                                        

                                                                                   


                                                                                           






                                                                
                                                               



                              
                                                    



                                             

                                                                                       







                                                                                         





                                                  
                                                                  
       
                                                                           





                                                       
                                                 







                                                                                        










                                                                          

 






                                                                          
                                                                                                              
                        


















                                                                                                                                                 
        


                                                        

 




















                                                                                                                                             

 
                                                                                


                          
               











                                                                                                         

                                                       











                                                                                         







                                             
                                                                                                                                  






                                                                                                   


                                                                            

                                                                                           
                                 
                                      
                                           




                                                       

                                                       









                                                                                                         
                                                                 













                                                                                                                                     
                       


















                                                             
                                        
 



                                    
  
#!/bin/bash -e

# Script Overview
#  - determine scala version
#  - determine module versions
#  - build minimal core (aka locker) of Scala, use the determined version number, publish to scala-integration
#  - build those modules where a binary compatible version doesn't exist, publish to scala-integration
#  - build Scala using the previously built core and bootstrap modules, publish to scala-integration, overwriting
#    the existing artifacts
#  - for releases
#    - stage Scala on sonatype
#    - rebuild modules that needed a rebuild with this Scala build, and stage them on sonatype
#  - for nightlies
#    - force rebuild all modules and publish them locally (for testing purposes)
#  - the Scala version is serialized to jenkins.properties, which is passed downstream to scala-release jobs


# Specifying the Scala version:
#  - To build a release (this enables publishing to sonatype):
#    - Either specify SCALA_VER_BASE. You may also specify SCALA_VER_SUFFIX, the Scala version is SCALA_VER=$SCALA_VER_BASE$SCALA_VER_SUFFIX.
#    - Or have the current HEAD tagged as v$base$suffix
#    - To prevent staging on sonatype (for testing), set publishToSonatype to anything but "yes"
#    - Note: After building a release, the jenkins job provides an updated versions.properties file as artifact.
#      Put this file in the Scala repo and create a pull request, and also update the file build.number.
#
# - Otherwise, an integration build is performed:
#    - version number is read from the build.number file, extended with -[bin|pre]-$sha


# Specifying module versions: there are two modes
#  - If moduleVersioning="versions.properties" (default): in this mode we use release versions for the modules.
#    - Module versions are read from the versions.properties file.
#    - Set <MODULE>_VER to override the default, e.g. XML_VER="1.0.4".
#    - The git revision is set to <MODULE>_REF="v$<MODULE>_VER". Make sure the tag exists (you can't override <MODULE>_REF).
#
#  - Otherwise (moduleVersioning has some other value): in this mode we use nightly version numbers for modules.
#    - By default the script sets all <MODULE>_REF to "HEAD", override to build a specific revision.
#    - The <MODULE>_VER is set to a nightly version, for example "1.0.3-7-g14888a2-nightly" (you can't override <MODULE>_VER)


# Modules are automatically built if necessary.
#  - A module is built if it doesn't exist in the maven repository. Note that the lookup uses two versions:
#    - The version of the module (see below how it's determined)
#    - The binary version of of the SCALA_VER release that is being built
#  - sbt computes the binary version when looking up / building modules (*). Examples:
#    - 2.12.0-M1, 2.12.0-RC3: the full version is used
#    - 2.12.0, 2.12.1-M1, 2.12.1-RC3, 2.12.1: the binary version 2.12 is used
#
#  - Example: assume that `scala-xml_2.11 % 1.0.3` and `scala-xml_2.12.0-M1 % 1.0.3` both exists
#    - XML_VER=1.0.3 and SCALA_VER=2.11.7    => no rebuild (binary version remains 2.11)
#    - XML_VER=1.0.3 and SCALA_VER=2.12.0-M2 => rebuild (new binary version 2.12.0-M2)
#    - XML_VER=1.0.4 and SCALA_VER=2.11.7    => rebuild (new version for the module, not yet on maven)
#      NOTE: this is not the recommended way of publishing a module. Instead, prefer to release `scala-xml_2.11 % 1.0.4`
#            using the existing scala 2.11.6 compiler before releasing 2.11.7. Sometimes it's necessary though. One
#            example was 2.11.1, which contained a fix in the backend (SerialVersionUID was ignored). All modules needed
#            to be re-built using the 2.11.1 release, we could not use 2.11.0. We could also not release the modules
#            after 2.11.1 was out, because that way the scala-library-all pom of 2.11.1 would depend on the old modules.
#
# (*) https://github.com/sbt/sbt/blob/v0.13.13/util/cross/src/main/input_sources/CrossVersionUtil.scala#L41


# Binary incompatible changes in Modules: example with Scala 2.11 / 2.12 and scala-parser-combinators
#  - The 1.0.x branch on scala-parser-combinators remains binary compatible with 1.0.0
#  - Scala 2.11 will always use 1.0.x releases: we ship scala-parser-combinators with the distribution,
#    so we cannot introduce incompatible changes in a minor release.
#  - The master branch of scala-parser-combinators contains binary incompatible changes, versioned 1.1.x
#  - Scala 2.12 will use 1.1.x releases
#  - No changes to the build script required: just put the 1.1.x version number into versions.properties
#
# Note: It's still OK for a module to release a binary incompatible version to maven, for example
# scala-parser-combinators_2.11 % 1.1.0. Users can depend on this in their sbt build. But for the
# distribution (tar/zip archives, scala-library-all) we have to stay on the binary compatible version.


# Requirements
#  - SBT_CMD must point to sbt from sbt-extras
#  - ~/.sonatype-curl, ~/.m2/settings.xml, ~/.credentials, ~/.credentials-sonatype, ~/.credentials-private-repo
#    as defined by https://github.com/scala/scala-jenkins-infra/tree/master/templates/default
#  - ~/.sbt/0.13/plugins/gpg.sbt with:
#     addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.1")

# Note: private-repo used to be private-repo.typesafe.com. now we're running artifactory on scala-ci.typesafe.com/artifactory


moduleVersioning=${moduleVersioning-"versions.properties"}

publishPrivateTask=${publishPrivateTask-"publish"}
publishSonatypeTaskCore=${publishSonatypeTaskCore-"publish-signed"}
publishSonatypeTaskModules=${publishSonatypeTaskModules-"publish-signed"}
publishLockerPrivateTask=${publishLockerPrivateTask-$publishPrivateTask} # set to "init" to speed up testing of the script (if you already built locker before)

forceRebuild=${forceRebuild-no}

antBuildTask="${antBuildTask-nightly}" # TESTING leave empty to avoid the sanity check (don't set it to "init" because ant will croak)
clean="clean" # TESTING leave empty to speed up testing

baseDir=${WORKSPACE-`pwd`}
scriptsDir="$baseDir/scripts"
. $scriptsDir/common

# we must change ivy home to get a fresh ivy cache, otherwise we get half-bootstrapped scala
# rm it in case it existed (and there's no ivy2-shadow, which indicates we're running in a TESTING environment)...
# we don't nuke the whole ws since that clobbers the git clones needlessly
[[ -d $baseDir/ivy2-shadow ]] || rm -rf $baseDir/ivy2
mkdir -p $baseDir/ivy2

rm -rf $baseDir/resolutionScratch_
mkdir -p $baseDir/resolutionScratch_

function generateRepositoriesConfig(){
    # Used below in sbtArgs since we use a dedicated repository to share artifcacts between jobs,
    # so we need to configure SBT to use these rather than its default, Maven Central.
    # See http://www.scala-sbt.org/0.13/docs/Proxy-Repositories.html
    sbtRepositoryConfig="$scriptsDir/repositories-scala-release"
    jcenterCacheUrl=${jcenterCacheUrl-"https://scala-ci.typesafe.com/artifactory/jcenter/"}
    cat > "$sbtRepositoryConfig" << EOF
[repositories]
  script-repo: $1
  jcenter-cache: $jcenterCacheUrl
  typesafe-ivy-releases: https://dl.bintray.com/typesafe/ivy-releases/, [organisation]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly
  sbt-plugin-releases: https://dl.bintray.com/sbt/sbt-plugin-releases/, [organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
  maven-central
  local
EOF
}

integrationRepoCred="private-repo"

# repo for locker, quick and the modules
integrationRepoUrl=${integrationRepoUrl-"https://scala-ci.typesafe.com/artifactory/scala-integration/"}

# adding `integrationRepoUrl` to find the locker scala version when building modules
generateRepositoriesConfig $integrationRepoUrl

##### git
gfxd() {
  git clean -fxd # TESTING
}

update() {
  [[ -d $baseDir ]] || mkdir -p $baseDir
  cd $baseDir

  if [ ! -d $baseDir/$2 ]; then git clone "https://github.com/$1/$2.git"; fi

  cd $2

  git fetch --tags "https://github.com/$1/$2.git"
  (git fetch "https://github.com/$1/$2.git" $3 && git checkout -fq FETCH_HEAD) #|| git checkout -fq $3 # || fallback is for local testing on tag
  git reset --hard
}

##### sonatype interface

stApi="https://oss.sonatype.org/service/local"

function st_curl(){
  curl -H "Content-Type: application/json" -H "accept: application/json,application/vnd.siesta-error-v1+json,application/vnd.siesta-validation-errors-v1+json"  -K ~/.sonatype-curl -s -o - $@
}

function st_stagingReposOpen() {
 st_curl "$stApi/staging/profile_repositories" | jq '.data[] | select(.profileName == "org.scala-lang") | select(.type == "open")'
}

function st_stagingRepoDrop() {
  repo=$1
  message=$2
  echo "{\"data\":{\"description\":\"$message\",\"stagedRepositoryIds\":[\"$repo\"]}}" | st_curl -X POST -d @- "$stApi/staging/bulk/drop"
}

function st_stagingRepoClose() {
  repo=$1
  message=$2
  echo "{\"data\":{\"description\":\"$message\",\"stagedRepositoryIds\":[\"$repo\"]}}" | st_curl -X POST -d @- "$stApi/staging/bulk/close"
}


# ARGH trying to get this to work on multiple versions of sbt-extras...
# the old version (on jenkins, and I don't want to upgrade for risk of breaking other builds) honors -sbt-dir
# the new version of sbt-extras ignores sbt-dir, so we pass it in as -Dsbt.global.base
# need to set sbt-dir to one that has the gpg.sbt plugin config
sbtArgs="-no-colors -ivy $baseDir/ivy2 -Dsbt.override.build.repos=true -Dsbt.repository.config=$sbtRepositoryConfig -Dsbt.global.base=$HOME/.sbt/0.13 -sbt-dir $HOME/.sbt/0.13"

sbtBuild() {
  echo "### sbtBuild: "$SBT_CMD $sbtArgs "${scalaVersionTasks[@]}" "${publishTasks[@]}" "$@"
  $SBT_CMD $sbtArgs "${scalaVersionTasks[@]}" "${publishTasks[@]}" "$@" >> $baseDir/logs/builds 2>&1
}

sbtResolve() {
  cd $baseDir/resolutionScratch_
  touch build.sbt
  # Can be set to `full` if a module requires cross-versioning against the full Scala version, like the continuations plugin.
  cross=${4-binary}
  echo "### sbtResolve: $SBT_CMD $sbtArgs " "${scalaVersionTasks[@]}" "\"$1\" % \"$2\" % \"$3\" cross CrossVersion.$cross"
  $SBT_CMD $sbtArgs "${scalaVersionTasks[@]}" \
    "set libraryDependencies := Seq(\"$1\" % \"$2\" % \"$3\" cross CrossVersion.$cross)" \
      'show update' >> $baseDir/logs/resolution 2>&1
}

# Oh boy... can't use scaladoc to document scala-xml/scala-parser-combinators
# if scaladoc depends on the same version of scala-xml/scala-parser-combinators.
# Even if that version is available through the project's resolvers, sbt won't look past this project.
# SOOOOO, we set the version to a dummy (-DOC), generate documentation,
# then set the version to the right one and publish (which won't re-gen the docs).
# Also tried publish-local without docs using 'set publishArtifact in (Compile, packageDoc) := false' and republishing, no dice.

# Each buildModule() function is invoked twice: first to build against locker and publish to artifactory, then
# to build against the release and publish to sonatype (or publish-local if publishToSonatype is not "yes").
# In the second round, sbtResolve is always true: the module will be found in the artifactory!
# Therefore, if MODULE_BUILT is "yes" (in the second round), we know that we need to build (and publish) the
# module again.
#
# Note: we tried an alternative solution in which sbtResolve would not look at artifactory, but that fails. For example,
# scala-xml depends on scala-library, so sbt tries to find the scala-library of the version that we are currently building,
# which exists only in artifactory.

buildXML() {
  if [ "$XML_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules"  "scala-xml" $XML_VER )
  then echo "Found scala-xml $XML_VER; not building."
  else
    update scala scala-xml "$XML_REF" && gfxd
    sbtBuild 'set version := "'$XML_VER'-DOC"' $clean doc  'set version := "'$XML_VER'"' test "${buildTasks[@]}"
    XML_BUILT="yes" # ensure the module is built and published when buildXML is invoked for the second time, see comment above
  fi
}

buildParsers() {
  if [ "$PARSERS_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules"  "scala-parser-combinators" $PARSERS_VER )
  then echo "Found scala-parser-combinators $PARSERS_VER; not building."
  else
    update scala scala-parser-combinators "$PARSERS_REF" && gfxd
    sbtBuild 'set version := "'$PARSERS_VER'-DOC"' $clean doc 'set version := "'$PARSERS_VER'"' test "${buildTasks[@]}"
    PARSERS_BUILT="yes"
  fi
}

buildPartest() {
  if [ "$PARTEST_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules"  "scala-partest" $PARTEST_VER )
  then echo "Found scala-partest $PARTEST_VER; not building."
  else
    update scala scala-partest "$PARTEST_REF" && gfxd
    sbtBuild 'set version :="'$PARTEST_VER'"' 'set VersionKeys.scalaXmlVersion := "'$XML_VER'"' 'set VersionKeys.scalaCheckVersion := "'$SCALACHECK_VER'"' $clean test "${buildTasks[@]}"
    PARTEST_BUILT="yes"
  fi
}

buildContinuations() {
  if [ "$CONT_PLUG_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.plugins"  "scala-continuations-plugin" $CONTINUATIONS_VER full )
  then echo "Found scala-continuations-plugin $CONTINUATIONS_VER; not building."
  else
    update scala scala-continuations $CONTINUATIONS_REF && gfxd

    $SBT_CMD $sbtArgs 'project plugin' "${scalaVersionTasks[@]}" "${publishTasks[@]}" \
      'set version := "'$CONTINUATIONS_VER'"' $clean "compile:package" test "${buildTasks[@]}" # https://github.com/scala/scala-continuations/pull/4
    CONT_PLUG_BUILT="yes"
  fi

  if [ "$CONT_LIB_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.plugins"  "scala-continuations-library" $CONTINUATIONS_VER )
  then echo "Found scala-continuations-library $CONTINUATIONS_VER; not building."
  else
    update scala scala-continuations $CONTINUATIONS_REF && gfxd
    $SBT_CMD $sbtArgs 'project library' "${scalaVersionTasks[@]}" "${publishTasks[@]}" \
      'set version := "'$CONTINUATIONS_VER'"' $clean test "${buildTasks[@]}"
    CONT_LIB_BUILT="yes"
  fi
}

buildSwing() {
  if [ "$SWING_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules"  "scala-swing" $SWING_VER )
  then echo "Found scala-swing $SWING_VER; not building."
  else
    update scala scala-swing "$SWING_REF" && gfxd
    sbtBuild 'set version := "'$SWING_VER'"' $clean test "${buildTasks[@]}"
    SWING_BUILT="yes"
  fi
}

buildActorsMigration(){
  if [ "$ACTORS_MIGRATION_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang"  "scala-actors-migration" $ACTORS_MIGRATION_VER )
  then echo "Found scala-actors-migration $ACTORS_MIGRATION_VER; not building."
  else
    update scala actors-migration "$ACTORS_MIGRATION_REF" && gfxd
    # not running tests because
    # [error] Test scala.actors.migration.NestedReact.testNestedReactAkka failed: java.util.concurrent.TimeoutException: Futures timed out after [20 seconds]
    sbtBuild 'set version := "'$ACTORS_MIGRATION_VER'"' 'set VersionKeys.continuationsVersion := "'$CONTINUATIONS_VER'"' $clean "${buildTasks[@]}"
    ACTORS_MIGRATION_BUILT="yes"
  fi
}

# should only be called with publishTasks publishing to artifactory
buildScalacheck(){
  if [ "$SCALACHECK_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scalacheck"  "scalacheck" $SCALACHECK_VER )
  then echo "Found scalacheck $SCALACHECK_VER; not building."
  else
    update rickynils scalacheck $SCALACHECK_REF && gfxd
    sbtBuild 'set version := "'$SCALACHECK_VER'"' 'set VersionKeys.scalaParserCombinatorsVersion := "'$PARSERS_VER'"' $clean publish # test times out NOTE: never published to sonatype
    SCALACHECK_BUILT="yes"
  fi
}

# build modules, using ${buildTasks[@]} (except for Scalacheck, which is hard-coded to publish to artifactory)
buildModules() {
  publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-private-repo")' "set every publishTo := Some(\"publish-repo\" at \"$integrationRepoUrl\")")
  buildTasks=($publishPrivateTask)
  buildXML
  buildParsers
  buildContinuations
  buildSwing
  buildActorsMigration
  buildScalacheck
  buildPartest
}

buildPublishedModules() {
  publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-sonatype")' "set pgpPassphrase := Some(Array.empty)")
  buildTasks=($publishSonatypeTaskModules)
  buildXML
  buildParsers
  buildContinuations
  buildSwing
  buildActorsMigration
  buildPartest
}


## BUILD STEPS:

scalaVerToBinary() {
  # $1 = SCALA_VER
  # $2 = SCALA_VER_BASE
  # $3 = SCALA_VER_SUFFIX

  local RE='\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)'
  local majMin="$(echo $2 | sed -e "s#$RE#\1.\2#")"
  local patch="$(echo $2 | sed -e "s#$RE#\3#")"

  # The binary version is majMin (e.g. "2.12") if
  #  - there's no suffix                         : 2.12.0, 2.12.1
  #  - the suffix starts with "-bin"             : 2.12.1-bin-sha, 2.12.1-bin-sha-custom, 2.12.1-bin-SNAPSHOT
  #  - the suffix is \w+ and patch version is > 0: 2.12.1-M1, 2.12.1-RC2 (also 2.12.1-sha, 2.12.1-SNAPSHOT, which we don't use)
  #
  # Otherwise, the binary version is the full version: 2.12.0-M1, 2.12.0-RC2, 2.12.0-pre-sha, 2.12.0-pre-SNAPSHOT
  # (also 2.12.0-sha, 2.12.0-SNAPSHOT, which we don't use)
  #
  # Adapted from sbt: https://github.com/sbt/sbt/blob/v0.13.13/util/cross/src/main/input_sources/CrossVersionUtil.scala#L42
  #
  # During the pre-release cycle of a major release (e.g. before 2.12.0), the SCALA_BINARY_VER of integration / SNAPSHOT
  # versions is the full version, e.g. 2.12.0-pre-sha, so modules are always re-built.

  if [[ "$3" == "" || "${3:0:4}" == "-bin" || ("$patch" != "0" && "$3" =~ ^-[a-zA-Z0-9_]+$) ]]; then
    echo "$majMin"
  else
    echo "$1"
  fi
}

determineScalaVersion() {
  cd $WORKSPACE
  parseScalaProperties "versions.properties"
  echo "repo_ref=2.11.x" >> $baseDir/jenkins.properties # for the -dist downstream jobs that build the actual archives


  # each of the branches below defines the following vars: SCALA_VER_BASE, SCALA_VER_SUFFIX, SCALADOC_SOURCE_LINKS_VER, publishToSonatype
  if [ -z "$SCALA_VER_BASE" ]; then
    echo "No SCALA_VER_BASE specified."

    scalaTag=$(git describe --tag --exact-match ||:)

    if [ -z "$scalaTag" ]
    then
      echo "No tag found, running an integration build."
      parseScalaProperties "build.number"
      SCALA_VER_BASE="$version_major.$version_minor.$version_patch"
      local shaSuffix=$(git rev-parse HEAD | cut -c1-7)
      local cross="bin"
      if [[ $SCALA_VER_BASE =~ ^.*\.0$ ]]; then
        cross="pre"
      fi
      SCALA_VER_SUFFIX="-$cross-$shaSuffix"
      SCALADOC_SOURCE_LINKS_VER=$(git rev-parse HEAD)

      # TODO: publish nightly snapshot using this script - currently it's a separate jenkins job still running at EPFL.
      publishToSonatype="no"
    else
      echo "HEAD is tagged as $scalaTag."
      # borrowed from https://github.com/cloudflare/semver_bash/blob/master/semver.sh
      local RE='v*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)' # don't change this to make it more accurate, it's not worth it
      SCALA_VER_BASE="$(echo $scalaTag | sed -e "s#$RE#\1.\2.\3#")"
      SCALA_VER_SUFFIX="$(echo $scalaTag | sed -e "s#$RE#\4#")"
      SCALADOC_SOURCE_LINKS_VER=$scalaTag

      if [ "$SCALA_VER_BASE" == "$scalaTag" ]; then
        echo "Could not parse version $scalaTag"
        exit 1
      fi
      publishToSonatype=${publishToSonatype-"yes"} # unless forced previously, publish
    fi
  else
    publishToSonatype=${publishToSonatype-"yes"} # unless forced previously, publish
    # if version base/suffix are provided, we assume a corresponding tag exists for the scaladoc source links
    SCALADOC_SOURCE_LINKS_VER="v$SCALA_VER_BASE$SCALA_VER_SUFFIX"
  fi

  SCALA_VER="$SCALA_VER_BASE$SCALA_VER_SUFFIX"
  SCALA_BINARY_VER=$(scalaVerToBinary $SCALA_VER $SCALA_VER_BASE $SCALA_VER_SUFFIX)

  echo "version=$SCALA_VER" >> $baseDir/jenkins.properties
  echo "sbtDistVersionOverride=-Dproject.version=$SCALA_VER" >> $baseDir/jenkins.properties

  scalaVersionTasks=('set every scalaVersion := "'$SCALA_VER'"')

  echo "Building Scala $SCALA_VER."
}

deriveVersion() {
  update $1 $2 $3 &> /dev/null
  echo "$(git describe --tag --match=v* | cut -dv -f2)-nightly"
}

deriveVersionAnyTag() {
  update $1 $2 $3 &> /dev/null
  echo "$(git describe --tag | cut -dv -f2)-nightly"
}

# determineScalaVersion must have been called
deriveModuleVersions() {
  if [ "$moduleVersioning" == "versions.properties" ]; then
    # use versions.properties as defaults when no version specified on the command line
                  XML_VER=${XML_VER-$scala_xml_version_number}
              PARSERS_VER=${PARSERS_VER-$scala_parser_combinators_version_number}
        CONTINUATIONS_VER=${CONTINUATIONS_VER-$scala_continuations_plugin_version_number}
                SWING_VER=${SWING_VER-$scala_swing_version_number}
     ACTORS_MIGRATION_VER=${ACTORS_MIGRATION_VER-$actors_migration_version_number}
              PARTEST_VER=${PARTEST_VER-$partest_version_number}
           SCALACHECK_VER=${SCALACHECK_VER-$scalacheck_version_number}

                  XML_REF="v$XML_VER"
              PARSERS_REF="v$PARSERS_VER"
        CONTINUATIONS_REF="v$CONTINUATIONS_VER"
                SWING_REF="v$SWING_VER"
     ACTORS_MIGRATION_REF="v$ACTORS_MIGRATION_VER"
              PARTEST_REF="v$PARTEST_VER"
           SCALACHECK_REF="$SCALACHECK_VER" # no `v` in their tags
   else
    # use HEAD as default when no revision is specified on the command line
                 XML_REF=${XML_REF-"HEAD"}
             PARSERS_REF=${PARSERS_REF-"HEAD"}
       CONTINUATIONS_REF=${CONTINUATIONS_REF-"HEAD"}
               SWING_REF=${SWING_REF-"HEAD"}
    ACTORS_MIGRATION_REF=${ACTORS_MIGRATION_REF-"HEAD"}
             PARTEST_REF=${PARTEST_REF-"HEAD"}
          SCALACHECK_REF=${SCALACHECK_REF-"HEAD"}

                 XML_VER=$(deriveVersion scala scala-xml "$XML_REF")
             PARSERS_VER=$(deriveVersion scala scala-parser-combinators "$PARSERS_REF")
       CONTINUATIONS_VER=$(deriveVersion scala scala-continuations "$CONTINUATIONS_REF")
               SWING_VER=$(deriveVersion scala scala-swing "$SWING_REF")
    ACTORS_MIGRATION_VER=$(deriveVersion scala actors-migration "$ACTORS_MIGRATION_REF")
             PARTEST_VER=$(deriveVersion scala scala-partest "$PARTEST_REF")
          SCALACHECK_VER=$(deriveVersionAnyTag rickynils scalacheck "$SCALACHECK_REF")
  fi

  echo "Module versions (versioning strategy: $moduleVersioning):"
  echo "ACTORS_MIGRATION = $ACTORS_MIGRATION_VER at $ACTORS_MIGRATION_REF"
  echo "CONTINUATIONS    = $CONTINUATIONS_VER at $CONTINUATIONS_REF"
  echo "PARSERS          = $PARSERS_VER at $PARSERS_REF"
  echo "PARTEST          = $PARTEST_VER at $PARTEST_REF"
  echo "SCALACHECK       = $SCALACHECK_VER at $SCALACHECK_REF"
  echo "SWING            = $SWING_VER at $SWING_REF"
  echo "XML              = $XML_VER at $XML_REF"

}

createNetrcFile() {
  local netrcFile=$HOME/`basename $1`-netrc
  grep 'host=' $1 | sed 's/host=\(.*\)/machine \1/'          >  $netrcFile
  grep 'user=' $1 | sed 's/user=\(.*\)/login \1/'            >> $netrcFile
  grep 'password=' $1 | sed 's/password=\(.*\)/password \1/' >> $netrcFile
}

# deletes existing artifacts (core and modules) matching the $SCALA_VER from the repository passed as argument
removeExistingBuilds() {
  local repoUrl=$1
  local repoPrefix="https://scala-ci.typesafe.com/artifactory/"
  if [[ $repoUrl == "$repoPrefix"* ]]; then
    local repoId=${1#$repoPrefix}
    local storageApiUrl="${repoPrefix}api/storage/$repoId"

    createNetrcFile "$HOME/.credentials-private-repo"
    local netrcFile="$HOME/.credentials-private-repo-netrc"

    # "module" is not a scala module (like scala-xml), but an artifact of a boostrap build. the variable
    # contains: "org/scala-lang/modules", "org/scala-lang/scala-compiler", "org/scala-lang/scala-library", ...
    local scalaLangModules=`curl -s $storageApiUrl/org/scala-lang | jq -r '.children | .[] | "org/scala-lang" + .uri' | grep -v actors-migration`

    for module in $scalaLangModules; do
      local artifacts=`curl -s $storageApiUrl/$module | jq -r ".children | .[] | select(.uri | endswith(\"$SCALA_VER\")) | .uri"`
      for artifact in $artifacts; do
        echo "Deleting $repoUrl$module$artifact"
        curl -s --netrc-file $netrcFile -X DELETE $repoUrl$module$artifact
      done
    done
  else
    echo "Unknown repo, not deleting anything: $repoUrl"
  fi
}

constructUpdatedModuleVersions() {
  updatedModuleVersions=()

  # force the new module versions for building the core. these may be different from the values in versions.properties,
  # either because the variables (XML_VER) were provided, or because we're building the modules from HEAD.
  # in the common case, the values are the same as in versions.properties.
  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dactors-migration.version.number=$ACTORS_MIGRATION_VER")
  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-continuations-library.version.number=$CONTINUATIONS_VER")
  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-continuations-plugin.version.number=$CONTINUATIONS_VER")
  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-parser-combinators.version.number=$PARSERS_VER")
  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-swing.version.number=$SWING_VER")
  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-xml.version.number=$XML_VER")

  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dpartest.version.number=$PARTEST_VER")
  updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscalacheck.version.number=$SCALACHECK_VER")

  # allow overriding the akka-actors and jline version using a jenkins build parameter
  if [ ! -z "$AKKA_ACTOR_VER" ]; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dakka-actor.version.number=$AKKA_ACTOR_VER"); fi
  if [ ! -z "$JLINE_VER" ]     ; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Djline.version=$JLINE_VER"); fi

  if [ ! -z "$SCALA_BINARY_VER" ]; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala.binary.version=$SCALA_BINARY_VER"); fi
}

# build locker (scala + modules) and quick, publishing everything to artifactory
bootstrap() {
  echo "### Bootstrapping"

  cd $WORKSPACE

  #### LOCKER

  echo "### Building locker"

  # for bootstrapping, publish core (or at least smallest subset we can get away with)
  # so that we can build modules with this version of Scala and publish them locally
  # must publish under $SCALA_VER so that the modules will depend on this (binary) version of Scala
  # publish more than just core: partest needs scalap
  # in sabbus lingo, the resulting Scala build will be used as starr to build the released Scala compiler
  ant -Dmaven.version.number=$SCALA_VER\
      -Dremote.snapshot.repository=NOPE\
      -Dremote.release.repository=$integrationRepoUrl\
      -Drepository.credentials.id=$integrationRepoCred\
      -Dscalac.args.optimise=-optimise\
      -Ddocs.skip=1\
      -Dlocker.skip=1\
      $publishLockerPrivateTask >> $baseDir/logs/builds 2>&1


  echo "### Building modules using locker"

  # build, test and publish modules with this core
  # publish to our internal repo (so we can resolve the modules in the scala build below)
  # we only need to build the modules necessary to build Scala itself
  # since the version of locker and quick are the same
  buildModules

  constructUpdatedModuleVersions

  #### QUICK

  echo "### Bootstrapping Scala using locker"

  # # TODO: close all open staging repos so that we can be reasonably sure the only open one we see after publishing below is ours
  # # the ant call will create a new one
  #
  # Rebuild Scala with these modules so that all binary versions are consistent.
  # Update versions.properties to new modules.
  # Sanity check: make sure the Scala test suite passes / docs can be generated with these modules.
  # don't skip locker (-Dlocker.skip=1), or stability will fail
  # overwrite "locker" version of scala at private-repo with bootstrapped version
  cd $baseDir
  rm -rf build/ # must leave everything else in $baseDir for downstream jobs

  # scala.full.version determines the dependency of scala-dist on the continuations plugin,
  # which is fully cross-versioned (for $SCALA_VER, the version we're releasing)
  ant -Dstarr.version=$SCALA_VER\
      -Dscala.full.version=$SCALA_VER\
      -Dextra.repo.url=$integrationRepoUrl\
      -Dmaven.version.suffix=$SCALA_VER_SUFFIX\
      ${updatedModuleVersions[@]} \
      -Dupdate.versions=1\
      -Dscaladoc.git.commit=$SCALADOC_SOURCE_LINKS_VER\
      -Dremote.snapshot.repository=NOPE\
      -Dremote.release.repository=$integrationRepoUrl\
      -Drepository.credentials.id=$integrationRepoCred\
      -Dscalac.args.optimise=-optimise\
      $antBuildTask $publishPrivateTask

  # clear ivy cache (and to be sure, local as well), so the next round of sbt builds sees the fresh scala
  rm -rf $baseDir/ivy2

  # TODO: create PR with following commit (note that release will have been tagged already)
  # git commit versions.properties -m"Bump versions.properties for $SCALA_VER."
}

# assumes we just bootstrapped, and current directory is $baseDir
# publishes locker to sonatype, then builds modules again (those for which version numbers were provided),
# and publishes those to sonatype as well
# finally, the staging repos are closed
publishSonatype() {
  # stage to sonatype, along with all modules -Dmaven.version.suffix/-Dbuild.release not necessary,
  # since we're just publishing an existing build
  echo "### Publishing core to sonatype"
  ant -Dmaven.version.number=$SCALA_VER $publishSonatypeTaskCore

  echo "### Publishing modules to sonatype"
  # build/test/publish scala core modules to sonatype (this will start a new staging repo)
  # (was hoping we could make everything go to the same staging repo, but it's not timing that causes two staging repos to be opened)
  # NOTE: only publish those for which versions are set
  # test and publish to sonatype, assuming you have ~/.sbt/0.13/sonatype.sbt and ~/.sbt/0.13/plugin/gpg.sbt
  buildPublishedModules

  open=$(st_stagingReposOpen)
  allOpenUrls=$(echo $open | jq  '.repositoryURI' | tr -d \")
  allOpen=$(echo $open | jq  '.repositoryId' | tr -d \")

  echo "Closing open repos: $allOpen"

  for repo in $allOpen; do st_stagingRepoClose $repo; done

  echo "Closed sonatype staging repos: $allOpenUrls."
}


#### MAIN

determineScalaVersion

deriveModuleVersions

removeExistingBuilds $integrationRepoUrl

bootstrap

if [ "$publishToSonatype" == "yes" ]
  then publishSonatype
fi