From 7d027ec2b2dec33b74ae43d64fbe1e77daccfc38 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 15 Jan 2024 17:29:48 +0800 Subject: [PATCH 01/91] Multiple revisions 1st: AssetManager, Cmd Clone Pull Run Signed-off-by: Dr Marco Claudio De La Pierre --- docs/developer/diagrams/nextflow.scm.mmd | 1 + .../main/groovy/nextflow/cli/CmdClone.groovy | 9 ++++---- .../main/groovy/nextflow/cli/CmdPull.groovy | 8 +++---- .../main/groovy/nextflow/cli/CmdRun.groovy | 9 ++++---- .../groovy/nextflow/scm/AssetManager.groovy | 23 ++++++++++++------- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/docs/developer/diagrams/nextflow.scm.mmd b/docs/developer/diagrams/nextflow.scm.mmd index 1c52075372..dff37b2cda 100644 --- a/docs/developer/diagrams/nextflow.scm.mmd +++ b/docs/developer/diagrams/nextflow.scm.mmd @@ -8,6 +8,7 @@ classDiagram class AssetManager { project : String + revision: String localPath : File mainScript : String repositoryProvider : RepositoryProvider diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index 28c1d209c3..51026ae5b2 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -37,7 +37,7 @@ class CmdClone extends CmdBase implements HubOptions { @Parameter(required=true, description = 'name of the project to clone') List args - @Parameter(names='-r', description = 'Revision to clone - It can be a git branch, tag or revision number') + @Parameter(names='-r', description = 'Revision of the project to clone (either a git branch, tag or commit SHA number)') String revision @Parameter(names=['-d','-deep'], description = 'Create a shallow clone of the specified depth') @@ -52,7 +52,8 @@ class CmdClone extends CmdBase implements HubOptions { Plugins.init() // the pipeline name String pipeline = args[0] - final manager = new AssetManager(pipeline, this) + String revisionSuffix = revision ? ':'+revision : '' + final manager = new AssetManager(pipeline, revision, this) // the target directory is the second parameter // otherwise default the current pipeline name @@ -68,9 +69,9 @@ class CmdClone extends CmdBase implements HubOptions { } manager.checkValidRemoteRepo() - print "Cloning ${manager.project}${revision ? ':'+revision:''} ..." + print "Cloning ${manager.project}${revisionSuffix} ..." manager.clone(target, revision, deep) print "\r" - println "${manager.project} cloned to: $target" + println "${manager.project}${revisionSuffix} cloned to: $target" } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 24f7d552d4..143e792542 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -40,7 +40,7 @@ class CmdPull extends CmdBase implements HubOptions { @Parameter(names='-all', description = 'Update all downloaded projects', arity = 0) boolean all - @Parameter(names=['-r','-revision'], description = 'Revision of the project to run (either a git branch, tag or commit SHA number)') + @Parameter(names=['-r','-revision'], description = 'Revision of the project to pull (either a git branch, tag or commit SHA number)') String revision @Parameter(names=['-d','-deep'], description = 'Create a shallow clone of the specified depth') @@ -73,10 +73,10 @@ class CmdPull extends CmdBase implements HubOptions { Plugins.init() list.each { - log.info "Checking $it ..." - def manager = new AssetManager(it, this) + log.info "Checking $it${revision ? ':'+revision : ''} ..." + def manager = new AssetManager(it, revision, this) - def result = manager.download(revision,deep) + def result = manager.download(revision, deep) manager.updateModules() def scriptFile = manager.getScriptFile() diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index 98b90f5d01..896ee3a9c0 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -518,22 +518,21 @@ class CmdRun extends CmdBase implements HubOptions { /* * try to look for a pipeline in the repository */ - def manager = new AssetManager(pipelineName, this) + def manager = new AssetManager(pipelineName, revision, this) def repo = manager.getProject() boolean checkForUpdate = true if( !manager.isRunnable() || latest ) { if( offline ) throw new AbortOperationException("Unknown project `$repo` -- NOTE: automatic download from remote repositories is disabled") - log.info "Pulling $repo ..." - def result = manager.download(revision,deep) + log.info "Pulling $repo${revision ? ':'+revision : ''} ..." + def result = manager.download(revision, deep) if( result ) log.info " $result" checkForUpdate = false } - // checkout requested revision + // post download operations try { - manager.checkout(revision) manager.updateModules() final scriptFile = manager.getScriptFile(mainScript) if( checkForUpdate && !offline ) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index a38ec5b2ec..5866cb60cc 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -69,6 +69,12 @@ class AssetManager { */ private String project + /** + * The name of the commit/branch/tag as requested via command line + * This is now a first class attribute of a pipeline + */ + private String revision + /** * Directory where the pipeline is cloned (i.e. downloaded) */ @@ -96,18 +102,18 @@ class AssetManager { * * @param pipeline The pipeline to be managed by this manager e.g. {@code nextflow-io/hello} */ - AssetManager( String pipelineName, HubOptions cliOpts = null) { + AssetManager( String pipelineName, String revisionName = null, HubOptions cliOpts = null) { assert pipelineName // read the default config file (if available) def config = ProviderConfig.getDefault() // build the object - build(pipelineName, config, cliOpts) + build(pipelineName, revisionName, config, cliOpts) } - AssetManager( String pipelineName, Map config ) { + AssetManager( String pipelineName, String revisionName = null, Map config) { assert pipelineName // build the object - build(pipelineName, config) + build(pipelineName, revisionName, config) } /** @@ -119,12 +125,13 @@ class AssetManager { * @return The {@link AssetManager} object itself */ @PackageScope - AssetManager build( String pipelineName, Map config = null, HubOptions cliOpts = null ) { + AssetManager build( String pipelineName, String revisionName = null, Map config = null, HubOptions cliOpts = null ) { this.providerConfigs = ProviderConfig.createFromMap(config) this.project = resolveName(pipelineName) - this.localPath = checkProjectDir(project) + this.revision = revisionName + this.localPath = checkProjectDir(project, revision) this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) setupCredentials(cliOpts) @@ -176,13 +183,13 @@ class AssetManager { * @return The project dir {@link File} */ @PackageScope - File checkProjectDir(String projectName) { + File checkProjectDir(String projectName, String revision) { if( !isValidProjectName(projectName)) { throw new IllegalArgumentException("Not a valid project name: $projectName") } - new File(root, project) + new File(root, project + (revision ? ':'+revision : '')) } /** From 106e8dfba28bcbc747a8ad200d6b38f941009ec2 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 16 Jan 2024 15:45:13 +0800 Subject: [PATCH 02/91] removed revision paramter from clone pull run Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/cli/CmdClone.groovy | 2 +- .../main/groovy/nextflow/cli/CmdPull.groovy | 2 +- .../main/groovy/nextflow/cli/CmdRun.groovy | 2 +- .../groovy/nextflow/scm/AssetManager.groovy | 32 ++++++++++--------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index 51026ae5b2..3b4551195c 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -70,7 +70,7 @@ class CmdClone extends CmdBase implements HubOptions { manager.checkValidRemoteRepo() print "Cloning ${manager.project}${revisionSuffix} ..." - manager.clone(target, revision, deep) + manager.clone(target, deep) print "\r" println "${manager.project}${revisionSuffix} cloned to: $target" } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 143e792542..025d4bab49 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -76,7 +76,7 @@ class CmdPull extends CmdBase implements HubOptions { log.info "Checking $it${revision ? ':'+revision : ''} ..." def manager = new AssetManager(it, revision, this) - def result = manager.download(revision, deep) + def result = manager.download(deep) manager.updateModules() def scriptFile = manager.getScriptFile() diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index 896ee3a9c0..b19946b593 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -526,7 +526,7 @@ class CmdRun extends CmdBase implements HubOptions { if( offline ) throw new AbortOperationException("Unknown project `$repo` -- NOTE: automatic download from remote repositories is disabled") log.info "Pulling $repo${revision ? ':'+revision : ''} ..." - def result = manager.download(revision, deep) + def result = manager.download(deep) if( result ) log.info " $result" checkForUpdate = false diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 5866cb60cc..ac1b4334a6 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -100,7 +100,8 @@ class AssetManager { /** * Create a new asset manager with the specified pipeline name * - * @param pipeline The pipeline to be managed by this manager e.g. {@code nextflow-io/hello} + * @param pipelineName The pipeline to be managed by this manager e.g. {@code nextflow-io/hello} + * @param revision Revision ID for the selected pipeline (git branch, tag or commit SHA number) */ AssetManager( String pipelineName, String revisionName = null, HubOptions cliOpts = null) { assert pipelineName @@ -120,6 +121,7 @@ class AssetManager { * Build the asset manager internal data structure * * @param pipelineName A project name or a project repository Git URL + * @param revisionName Revision ID for the selected pipeline (git branch, tag or commit SHA number) * @param config A {@link Map} holding the configuration properties defined in the {@link ProviderConfig#DEFAULT_SCM_FILE} file * @param cliOpts User credentials provided on the command line. See {@link HubOptions} trait * @return The {@link AssetManager} object itself @@ -180,6 +182,7 @@ class AssetManager { * and return the directory where the project is stored locally * * @param projectName A project name matching the pattern {@code owner/project} + * @param revision Revision ID for the selected pipeline (git branch, tag or commit SHA number) * @return The project dir {@link File} */ @PackageScope @@ -374,7 +377,8 @@ class AssetManager { return this } - AssetManager checkValidRemoteRepo(String revision=null) { + // TODO MARCO: refactor init of revision in provider + AssetManager checkValidRemoteRepo() { // Configure the git provider to use the required revision as source for all needed remote resources: // - config if present in repo (nextflow.config by default) // - main script (main.nf by default) @@ -576,19 +580,18 @@ class AssetManager { /** * Download a pipeline from a remote Github repository * - * @param revision The revision to download * @result A message representing the operation result */ - String download(String revision=null, Integer deep=null) { + String download(Integer deep=null) { assert project /* - * if the pipeline already exists locally pull it from the remote repo + * if the pipeline does not exists locally pull it from the remote repo */ if( !localPath.exists() ) { localPath.parentFile.mkdirs() // make sure it contains a valid repository - checkValidRemoteRepo(revision) + checkValidRemoteRepo() final cloneURL = getGitRepositoryUrl() log.debug "Pulling $project -- Using remote clone url: ${cloneURL}" @@ -610,14 +613,14 @@ class AssetManager { // use an explicit checkout command *after* the clone instead of cloning a specific branch // because the clone command does not allow the use of SHA commit id (only branch and tag names) try { git.checkout() .setName(revision) .call() } - catch ( RefNotFoundException e ) { checkoutRemoteBranch(revision) } + catch ( RefNotFoundException e ) { checkoutRemoteBranch() } } // return status message return "downloaded from ${cloneURL}" } - log.debug "Pull pipeline $project -- Using local path: $localPath" + log.debug "Pulling $project -- Using local path: $localPath" // verify that is clean if( !isClean() ) @@ -635,7 +638,7 @@ class AssetManager { * Try to checkout it from a remote branch and return */ catch ( RefNotFoundException e ) { - final ref = checkoutRemoteBranch(revision) + final ref = checkoutRemoteBranch() final commitId = ref?.getObjectId() return commitId ? "checked out at ${commitId.name()}" @@ -673,13 +676,12 @@ class AssetManager { * Clone a pipeline from a remote pipeline repository to the specified folder * * @param directory The folder when the pipeline will be cloned - * @param revision The revision to be cloned. It can be a branch, tag, or git revision number */ - void clone(File directory, String revision = null, Integer deep=null) { + void clone(File directory, Integer deep=null) { def clone = Git.cloneRepository() def uri = getGitRepositoryUrl() - log.debug "Clone project `$project` -- Using remote URI: ${uri} into: $directory" + log.debug "Cloning `$project` -- Using remote URI: ${uri} into: $directory" if( !uri ) throw new AbortOperationException("Cannot find the specified project: $project") @@ -936,13 +938,13 @@ class AssetManager { git.checkout().setName(revision) .call() } catch( RefNotFoundException e ) { - checkoutRemoteBranch(revision) + checkoutRemoteBranch() } } - protected Ref checkoutRemoteBranch( String revision ) { + protected Ref checkoutRemoteBranch() { try { def fetch = git.fetch() @@ -1008,7 +1010,7 @@ class AssetManager { if( provider.hasCredentials() ) update.setCredentialsProvider( provider.getGitCredentials() ) def updatedList = update.call() - log.debug "Update submodules $updatedList" + log.debug "Updating submodules $updatedList" } protected String getRemoteCommitId(RevisionInfo rev) { From 0a9e6f807fffcfc2e8b9b4db89991deb6856723b Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 16 Jan 2024 15:45:24 +0800 Subject: [PATCH 03/91] updated unit tests for AssetManager Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 76 +++++-------------- 1 file changed, 21 insertions(+), 55 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index e17022f58a..66784fd5bf 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -184,15 +184,15 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', "v1.2", [providers: [github: [auth: token]]]) when: - manager.download("v1.2") + manager.download() then: - folder.resolve('nextflow-io/hello/.git').isDirectory() + folder.resolve('nextflow-io/hello:v1.2/.git').isDirectory() when: - manager.download("v1.2") + manager.download() then: noExceptionThrown() } @@ -204,15 +204,15 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', "6b9515aba6c7efc6a9b3f273ce116fc0c224bf68", [providers: [github: [auth: token]]]) when: - manager.download("6b9515aba6c7efc6a9b3f273ce116fc0c224bf68") + manager.download() then: - folder.resolve('nextflow-io/hello/.git').isDirectory() + folder.resolve('nextflow-io/hello:6b9515aba6c7efc6a9b3f273ce116fc0c224bf68/.git').isDirectory() when: - def result = manager.download("6b9515aba6c7efc6a9b3f273ce116fc0c224bf68") + def result = manager.download() then: noExceptionThrown() result == "Already-up-to-date" @@ -227,35 +227,12 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) - - when: - manager.download("mybranch") - then: - folder.resolve('nextflow-io/hello/.git').isDirectory() + def manager = new AssetManager().build('nextflow-io/hello', "mybranch", [providers: [github: [auth: token]]]) when: - manager.download("mybranch") - then: - noExceptionThrown() - } - - // First clone a repo with a tag, then forget to include the -r argument - // when you execute nextflow. - // Note that while the download will work, execution will fail subsequently - // at a separate check - this just tests that we don't fail because of a detached head. - @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) - def testPullTagThenBranch() { - - given: - def folder = tempDir.getRoot() - def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) - - when: - manager.download("v1.2") + manager.download() then: - folder.resolve('nextflow-io/hello/.git').isDirectory() + folder.resolve('nextflow-io/hello:mybranch/.git').isDirectory() when: manager.download() @@ -551,19 +528,14 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/nf-test-branch', [providers: [github: [auth: token]]]) - - when: - manager.download("dev") - then: - folder.resolve('nextflow-io/nf-test-branch/.git').isDirectory() - and: - folder.resolve('nextflow-io/nf-test-branch/workflow.nf').text == "println 'Hello'\n" + def manager = new AssetManager().build('nextflow-io/nf-test-branch', "dev", [providers: [github: [auth: token]]]) when: manager.download() then: - noExceptionThrown() + folder.resolve('nextflow-io/nf-test-branch:dev/.git').isDirectory() + and: + folder.resolve('nextflow-io/nf-test-branch:dev/workflow.nf').text == "println 'Hello'\n" } @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) @@ -571,13 +543,12 @@ class AssetManagerTest extends Specification { given: def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/nf-test-branch', [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/nf-test-branch', 'dev', [providers: [github: [auth: token]]]) expect: - manager.checkValidRemoteRepo('dev') + manager.checkValidRemoteRepo() and: manager.getMainScriptName() == 'workflow.nf' - } @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) @@ -586,19 +557,14 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/nf-test-branch', [providers: [github: [auth: token]]]) - - when: - manager.download("v0.1") - then: - folder.resolve('nextflow-io/nf-test-branch/.git').isDirectory() - and: - folder.resolve('nextflow-io/nf-test-branch/workflow.nf').text == "println 'Hello'\n" + def manager = new AssetManager().build('nextflow-io/nf-test-branch', "v0.1", [providers: [github: [auth: token]]]) when: manager.download() then: - noExceptionThrown() + folder.resolve('nextflow-io/nf-test-branch:v0.1/.git').isDirectory() + and: + folder.resolve('nextflow-io/nf-test-branch:v0.1/workflow.nf').text == "println 'Hello'\n" } } From 5a9b159d09658926b0bc959faa7e8b703aed33c4 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 16 Jan 2024 16:28:45 +0800 Subject: [PATCH 04/91] AssetManager provider.revision assigned at AssetManager object creation Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index ac1b4334a6..344133a03b 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -136,6 +136,7 @@ class AssetManager { this.localPath = checkProjectDir(project, revision) this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) + this.provider.setRevision(revision) setupCredentials(cliOpts) validateProjectDir() @@ -377,12 +378,8 @@ class AssetManager { return this } - // TODO MARCO: refactor init of revision in provider AssetManager checkValidRemoteRepo() { - // Configure the git provider to use the required revision as source for all needed remote resources: - // - config if present in repo (nextflow.config by default) - // - main script (main.nf by default) - provider.revision = revision + // Check that the remote git provider contains the main script file (main.nf by default) final scriptName = getMainScriptName() provider.validateFor(scriptName) return this From 94d34f3bd41f370e4674dc0680d567ef23be4c20 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 16 Jan 2024 21:11:27 +0800 Subject: [PATCH 05/91] Codespell typo in changelog Signed-off-by: Dr Marco Claudio De La Pierre --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 6b2be1e2ef..5eafa10eff 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ NEXTFLOW CHANGE-LOG - Fix bug with Fusion symlink resolution (#4593) [f28c9e48] - Fix Fusion symlinks when publishing files (#4348) [1fa5878a] - Fix Inspect command fails with Singularity [25883df3] -- Fix Allow the use of error build-in function in onComplete handler (#4458) [ci fast] [4be10cd3] +- Fix Allow the use of error built-in function in onComplete handler (#4458) [ci fast] [4be10cd3] - Fix Harden regular expression to used to strip secrets in logs (#4563) [ci fast] [0102d4d6] - Fix custom notification template [40980bcb] - Fix container environment with special chars (#4594) [f4e00601] From 4744774bf29c403994d4b45b707ae8c90a926f01 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 16 Jan 2024 21:37:51 +0800 Subject: [PATCH 06/91] AssetManager: removed checkout method Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 344133a03b..6d2a1c7214 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -909,37 +909,6 @@ class AssetManager { return result } - /** - * Checkout a specific revision - * @param revision The revision to be checked out - */ - void checkout( String revision = null ) { - assert localPath - - def current = getCurrentRevision() - if( current != defaultBranch ) { - if( !revision ) { - throw new AbortOperationException("Project `$project` is currently stickied on revision: $current -- you need to explicitly specify a revision with the option `-r` in order to use it") - } - } - if( !revision || revision == current ) { - // nothing to do - return - } - - // verify that is clean - if( !isClean() ) - throw new AbortOperationException("Project `$project` contains uncommitted changes -- Cannot switch to revision: $revision") - - try { - git.checkout().setName(revision) .call() - } - catch( RefNotFoundException e ) { - checkoutRemoteBranch() - } - - } - protected Ref checkoutRemoteBranch() { From 08718ef0fe8c66bfd90a1fccca3113ae23824c5a Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 17 Jan 2024 12:02:01 +0800 Subject: [PATCH 07/91] assetmanager: fixed build signature, and unit tests Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 4 ++-- .../src/test/groovy/nextflow/cli/CmdInfoTest.groovy | 3 ++- .../src/test/groovy/nextflow/scm/AssetManagerTest.groovy | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 6d2a1c7214..ecf85b881d 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -111,7 +111,7 @@ class AssetManager { build(pipelineName, revisionName, config, cliOpts) } - AssetManager( String pipelineName, String revisionName = null, Map config) { + AssetManager( String pipelineName, String revisionName, Map config) { assert pipelineName // build the object build(pipelineName, revisionName, config) @@ -127,7 +127,7 @@ class AssetManager { * @return The {@link AssetManager} object itself */ @PackageScope - AssetManager build( String pipelineName, String revisionName = null, Map config = null, HubOptions cliOpts = null ) { + AssetManager build( String pipelineName, String revisionName, Map config = null, HubOptions cliOpts = null ) { this.providerConfigs = ProviderConfig.createFromMap(config) diff --git a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy index 3ec57a2427..1ad1d73e3a 100644 --- a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy @@ -45,8 +45,9 @@ class CmdInfoTest extends Specification { def setupSpec() { tempDir = Files.createTempDirectory('test') AssetManager.root = tempDir.toFile() + String revision = null def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) // download the project manager.download() } diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 66784fd5bf..a1f796bd56 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -162,8 +162,9 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() + String revision = null def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) when: manager.download() @@ -246,8 +247,9 @@ class AssetManagerTest extends Specification { given: def dir = tempDir.getRoot() + String revision = null def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', [providers:[github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', revision, [providers:[github: [auth: token]]]) when: manager.clone(dir.toFile()) From 242a600d98116f6a8c6f822f63e813bb2d298153 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 17 Jan 2024 12:07:53 +0800 Subject: [PATCH 08/91] assetmanager: one more build signature fix Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index ecf85b881d..faf5ec1497 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -127,7 +127,7 @@ class AssetManager { * @return The {@link AssetManager} object itself */ @PackageScope - AssetManager build( String pipelineName, String revisionName, Map config = null, HubOptions cliOpts = null ) { + AssetManager build( String pipelineName, String revisionName = null, Map config = null, HubOptions cliOpts = null ) { this.providerConfigs = ProviderConfig.createFromMap(config) From 35ad1e9931c02385c1f67595211ee97fa671a17d Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 17 Jan 2024 17:17:14 +0800 Subject: [PATCH 09/91] AssetManager: fix for multi revs in find() method Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index faf5ec1497..55ac8aa622 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -131,7 +131,7 @@ class AssetManager { this.providerConfigs = ProviderConfig.createFromMap(config) - this.project = resolveName(pipelineName) + this.project = resolveName(pipelineName, revisionName) this.revision = revisionName this.localPath = checkProjectDir(project, revision) this.hub = checkHubProvider(cliOpts) @@ -253,7 +253,7 @@ class AssetManager { * @param name A project name or URL e.g. {@code cbcrg/foo} or {@code https://github.com/cbcrg/foo.git} * @return The fully qualified project name e.g. {@code cbcrg/foo} */ - String resolveName( String name ) { + String resolveName( String name, String revision = null ) { assert name // @@ -295,7 +295,7 @@ class AssetManager { name = parts[0] } - def qualifiedName = find(name) + def qualifiedName = find(name, revision) if( !qualifiedName ) { return "$DEFAULT_ORGANIZATION/$name".toString() } @@ -550,16 +550,19 @@ class AssetManager { return result } - static protected def find( String name ) { + static protected def find( String name, String revision = null ) { def exact = [] def partial = [] list().each { def items = it.split('/') - if( items[1] == name ) - exact << it - else if( items[1].startsWith(name ) ) - partial << it + def itemsRev = items[1].tokenize(':') + if( (!revision && !itemsRev[1]) || (revision && itemsRev[1] == revision) ) { + if( itemsRev[0] == name ) + exact << it.tokenize(':')[0] + else if( itemsRev[0].startsWith(name ) ) + partial << it.tokenize(':')[0] + } } def list = exact ?: partial From 463b6f169cfa140de49126a1edbf1b824855df51 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 17 Jan 2024 17:48:10 +0800 Subject: [PATCH 10/91] Multiple revisions: added for Cmds Drop, View, Config, Info Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/cli/CmdConfig.groovy | 5 ++++- .../nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy | 9 ++++++--- .../nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy | 7 +++++-- .../nextflow/src/main/groovy/nextflow/cli/CmdView.groovy | 7 +++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy index 29b874198b..c47ec4cd0f 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy @@ -44,6 +44,9 @@ class CmdConfig extends CmdBase { @Parameter(description = 'project name') List args = [] + @Parameter(names=['-r','-revision'], description = 'Revision of the project (either a git branch, tag or commit SHA number)') + String revision + @Parameter(names=['-a','-show-profiles'], description = 'Show all configuration profiles') boolean showAllProfiles @@ -182,7 +185,7 @@ class CmdConfig extends CmdBase { return file.parent ?: Paths.get('/') } - final manager = new AssetManager(path) + final manager = new AssetManager(path, revision) manager.isLocal() ? manager.localPath.toPath() : manager.configFile?.parent } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index dd36368854..c611d41326 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -39,6 +39,9 @@ class CmdDrop extends CmdBase { @Parameter(required=true, description = 'name of the project to drop') List args + @Parameter(names=['-r','-revision'], description = 'Revision of the project to drop (either a git branch, tag or commit SHA number)') + String revision + @Parameter(names='-f', description = 'Delete the repository without taking care of local changes') boolean force @@ -48,15 +51,15 @@ class CmdDrop extends CmdBase { @Override void run() { Plugins.init() - def manager = new AssetManager(args[0]) + def manager = new AssetManager(args[0], revision) if( !manager.localPath.exists() ) { - throw new AbortOperationException("No match found for: ${args[0]}") + throw new AbortOperationException("No match found for: ${args[0]}${revision ? ':'+revision : ''}") } if( this.force || manager.isClean() ) { manager.close() if( !manager.localPath.deleteDir() ) - throw new AbortOperationException("Unable to delete project `${manager.project}` -- Check access permissions for path: ${manager.localPath}") + throw new AbortOperationException("Unable to delete project `${manager.project}${revision ? ':'+revision : ''}` -- Check access permissions for path: ${manager.localPath}") return } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index e679d1fcd5..96995f58d5 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -50,6 +50,9 @@ class CmdInfo extends CmdBase { @Parameter(description = 'project name') List args + @Parameter(names=['-r','-revision'], description = 'Revision of the project (either a git branch, tag or commit SHA number)') + String revision + @Parameter(names='-d',description = 'Show detailed information', arity = 0) boolean detailed @@ -75,9 +78,9 @@ class CmdInfo extends CmdBase { } Plugins.init() - final manager = new AssetManager(args[0]) + final manager = new AssetManager(args[0], revision) if( !manager.isLocal() ) - throw new AbortOperationException("Unknown project `${args[0]}`") + throw new AbortOperationException("Unknown project `${args[0]}${revision ? ':'+revision : ''}`") if( !format || format == 'text' ) { printText(manager,level) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy index d38befaf07..14d2addc5b 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy @@ -42,6 +42,9 @@ class CmdView extends CmdBase { @Parameter(description = 'project name', required = true) List args = [] + @Parameter(names=['-r','-revision'], description = 'Revision of the project (either a git branch, tag or commit SHA number)') + String revision + @Parameter(names = '-q', description = 'Hide header line', arity = 0) boolean quiet @@ -51,9 +54,9 @@ class CmdView extends CmdBase { @Override void run() { Plugins.init() - def manager = new AssetManager(args[0]) + def manager = new AssetManager(args[0], revision) if( !manager.isLocal() ) - throw new AbortOperationException("Unknown project name `${args[0]}`") + throw new AbortOperationException("Unknown project `${args[0]}${revision ? ':'+revision : ''}`") if( all ) { if( !quiet ) From 2d3273e63ae074093837e7c1f83e1842861b1b43 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 17 Jan 2024 17:53:01 +0800 Subject: [PATCH 11/91] minor fixes to log outputs in CmdRun Signed-off-by: Dr Marco Claudio De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index b19946b593..c3667ad52e 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -524,7 +524,7 @@ class CmdRun extends CmdBase implements HubOptions { boolean checkForUpdate = true if( !manager.isRunnable() || latest ) { if( offline ) - throw new AbortOperationException("Unknown project `$repo` -- NOTE: automatic download from remote repositories is disabled") + throw new AbortOperationException("Unknown project `$repo${revision ? ':'+revision : ''}` -- NOTE: automatic download from remote repositories is disabled") log.info "Pulling $repo${revision ? ':'+revision : ''} ..." def result = manager.download(deep) if( result ) @@ -544,7 +544,7 @@ class CmdRun extends CmdBase implements HubOptions { throw e } catch( Exception e ) { - throw new AbortOperationException("Unknown error accessing project `$repo` -- Repository may be corrupted: ${manager.localPath}", e) + throw new AbortOperationException("Unknown error accessing project `$repo${revision ? ':'+revision : ''}` -- Repository may be corrupted: ${manager.localPath}", e) } } From d2e5ffeee69f2b684f3554ac88abebe4fc8ee73c Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 18 Jan 2024 12:09:07 +0800 Subject: [PATCH 12/91] AssetManager: documented new localPath schema Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 55ac8aa622..afd9498e83 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -77,6 +77,7 @@ class AssetManager { /** * Directory where the pipeline is cloned (i.e. downloaded) + * New schema: root//: */ private File localPath @@ -550,6 +551,7 @@ class AssetManager { return result } + // updated for new localPath schema (see localPath declaration at top of this class file) static protected def find( String name, String revision = null ) { def exact = [] def partial = [] From 60c3c5ea7a3e597df3c25ef9cc009e28af308fd0 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 18 Jan 2024 12:56:10 +0800 Subject: [PATCH 13/91] K8sDriverLauncher : added revision support Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy b/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy index 2debcfc83d..c3c1483673 100644 --- a/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy @@ -270,7 +270,7 @@ class K8sDriverLauncher { if( !interactive && !pipelineName.startsWith('/') && !cmd.remoteProfile && !cmd.runRemoteConfig ) { // -- check and parse project remote config Plugins.init() - final pipelineConfig = new AssetManager(pipelineName, cmd) .getConfigFile() + final pipelineConfig = new AssetManager(pipelineName, cmd.revision, cmd) .getConfigFile() builder.setUserConfigFiles(pipelineConfig) } From 4bf1e371846ac90247daeb61a9b0950284387e79 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 18 Jan 2024 14:26:19 +0800 Subject: [PATCH 14/91] updates to AssetManagerTest Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index a1f796bd56..9a2773a40b 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -110,6 +110,7 @@ class AssetManagerTest extends Specification { def folder = tempDir.getRoot() folder.resolve('cbcrg/pipe1').mkdirs() folder.resolve('cbcrg/pipe2').mkdirs() + folder.resolve('cbcrg/pipe2:v2').mkdirs() folder.resolve('ncbi/blast').mkdirs() def manager = new AssetManager() @@ -119,6 +120,11 @@ class AssetManagerTest extends Specification { then: result == 'x/y' + when: + result = manager.resolveName('x/y', 'v2') + then: + result == 'x/y' + when: result = manager.resolveName('blast') then: @@ -144,6 +150,11 @@ class AssetManagerTest extends Specification { then: thrown(AbortOperationException) + when: + result = manager.resolveName('pipe2', 'v2') + then: + result == 'cbcrg/pipe2' + when: result = manager.resolveName('../blast/script.nf') then: @@ -172,10 +183,10 @@ class AssetManagerTest extends Specification { folder.resolve('nextflow-io/hello/.git').isDirectory() when: - manager.download() + def result = manager.download() then: noExceptionThrown() - + result == "Already-up-to-date" } @@ -193,9 +204,10 @@ class AssetManagerTest extends Specification { folder.resolve('nextflow-io/hello:v1.2/.git').isDirectory() when: - manager.download() + def result = manager.download() then: noExceptionThrown() + result == "Already-up-to-date" } // The hashes used here are NOT associated with tags. @@ -236,9 +248,10 @@ class AssetManagerTest extends Specification { folder.resolve('nextflow-io/hello:mybranch/.git').isDirectory() when: - manager.download() + def result = manager.download() then: noExceptionThrown() + result == "Already-up-to-date" } From 7e3211119601da69bd86891048d3112105221fa8 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 18 Jan 2024 15:19:49 +0800 Subject: [PATCH 15/91] edit to AssetManagerTest, git.pull for TAGS does not output result of operation Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/test/groovy/nextflow/scm/AssetManagerTest.groovy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 9a2773a40b..d53da2b52a 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -204,10 +204,9 @@ class AssetManagerTest extends Specification { folder.resolve('nextflow-io/hello:v1.2/.git').isDirectory() when: - def result = manager.download() + manager.download() then: noExceptionThrown() - result == "Already-up-to-date" } // The hashes used here are NOT associated with tags. From 3b2d461a7688d00fa30fa76b4b5272620f482e88 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 18 Jan 2024 15:53:16 +0800 Subject: [PATCH 16/91] minor fix in GitlabRepositoryProvider: using DEFAULT_BRANCH instead of "master" Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/scm/GitlabRepositoryProvider.groovy | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/GitlabRepositoryProvider.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/GitlabRepositoryProvider.groovy index d03123333a..a8b35d429c 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/GitlabRepositoryProvider.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/GitlabRepositoryProvider.groovy @@ -18,6 +18,7 @@ package nextflow.scm import groovy.util.logging.Slf4j +import static nextflow.Const.DEFAULT_BRANCH /** * Implements a repository provider for GitHub service * @@ -59,8 +60,8 @@ class GitlabRepositoryProvider extends RepositoryProvider { String getDefaultBranch() { def result = invokeAndParseResponse(getEndpointUrl()) ?. default_branch if( !result ) { - log.debug "Unable to fetch repo default branch. Using `master` branch -- See https://gitlab.com/gitlab-com/support-forum/issues/1655#note_26132691" - return 'master' + log.debug "Unable to fetch repo default branch. Using `${DEFAULT_BRANCH}` branch -- See https://gitlab.com/gitlab-com/support-forum/issues/1655#note_26132691" + return DEFAULT_BRANCH } return result } From 2e6461e76af6d1087095edad020a74f1b2a71816 Mon Sep 17 00:00:00 2001 From: Ben Sherman Date: Tue, 23 Jan 2024 11:48:08 -0600 Subject: [PATCH 17/91] Minor edits Signed-off-by: Ben Sherman --- docs/developer/diagrams/nextflow.scm.mmd | 2 +- .../main/groovy/nextflow/cli/CmdDrop.groovy | 2 +- .../groovy/nextflow/scm/AssetManager.groovy | 22 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/developer/diagrams/nextflow.scm.mmd b/docs/developer/diagrams/nextflow.scm.mmd index dff37b2cda..a512e36a75 100644 --- a/docs/developer/diagrams/nextflow.scm.mmd +++ b/docs/developer/diagrams/nextflow.scm.mmd @@ -8,7 +8,7 @@ classDiagram class AssetManager { project : String - revision: String + revision : String localPath : File mainScript : String repositoryProvider : RepositoryProvider diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index c611d41326..61451a2b67 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -53,7 +53,7 @@ class CmdDrop extends CmdBase { Plugins.init() def manager = new AssetManager(args[0], revision) if( !manager.localPath.exists() ) { - throw new AbortOperationException("No match found for: ${args[0]}${revision ? ':'+revision : ''}") + throw new AbortOperationException("No match found for: ${manager.project}${revision ? ':'+revision : ''}") } if( this.force || manager.isClean() ) { diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index afd9498e83..6c88386171 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -77,7 +77,8 @@ class AssetManager { /** * Directory where the pipeline is cloned (i.e. downloaded) - * New schema: root//: + * + * Schema: $NXF_ASSETS//[:] */ private File localPath @@ -104,36 +105,36 @@ class AssetManager { * @param pipelineName The pipeline to be managed by this manager e.g. {@code nextflow-io/hello} * @param revision Revision ID for the selected pipeline (git branch, tag or commit SHA number) */ - AssetManager( String pipelineName, String revisionName = null, HubOptions cliOpts = null) { + AssetManager( String pipelineName, String revision = null, HubOptions cliOpts = null) { assert pipelineName // read the default config file (if available) def config = ProviderConfig.getDefault() // build the object - build(pipelineName, revisionName, config, cliOpts) + build(pipelineName, revision, config, cliOpts) } - AssetManager( String pipelineName, String revisionName, Map config) { + AssetManager( String pipelineName, String revision, Map config) { assert pipelineName // build the object - build(pipelineName, revisionName, config) + build(pipelineName, revision, config) } /** * Build the asset manager internal data structure * * @param pipelineName A project name or a project repository Git URL - * @param revisionName Revision ID for the selected pipeline (git branch, tag or commit SHA number) + * @param revision Revision ID for the selected pipeline (git branch, tag or commit SHA number) * @param config A {@link Map} holding the configuration properties defined in the {@link ProviderConfig#DEFAULT_SCM_FILE} file * @param cliOpts User credentials provided on the command line. See {@link HubOptions} trait * @return The {@link AssetManager} object itself */ @PackageScope - AssetManager build( String pipelineName, String revisionName = null, Map config = null, HubOptions cliOpts = null ) { + AssetManager build( String pipelineName, String revision = null, Map config = null, HubOptions cliOpts = null ) { this.providerConfigs = ProviderConfig.createFromMap(config) - this.project = resolveName(pipelineName, revisionName) - this.revision = revisionName + this.project = resolveName(pipelineName, revision) + this.revision = revision this.localPath = checkProjectDir(project, revision) this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) @@ -683,7 +684,7 @@ class AssetManager { def clone = Git.cloneRepository() def uri = getGitRepositoryUrl() - log.debug "Cloning `$project` -- Using remote URI: ${uri} into: $directory" + log.debug "Cloning `${project}` from ${uri} into ${directory}" if( !uri ) throw new AbortOperationException("Cannot find the specified project: $project") @@ -914,7 +915,6 @@ class AssetManager { return result } - protected Ref checkoutRemoteBranch() { try { From b3f141dd27a0afd303c636b2da27368558f49458 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Wed, 28 Feb 2024 06:13:44 +0000 Subject: [PATCH 18/91] parametrised revision delimiter Signed-off-by: Dr Marco De La Pierre --- .../src/main/groovy/nextflow/cli/CmdClone.groovy | 5 ++++- .../src/main/groovy/nextflow/cli/CmdDrop.groovy | 6 ++++-- .../src/main/groovy/nextflow/cli/CmdInfo.groovy | 4 +++- .../src/main/groovy/nextflow/cli/CmdPull.groovy | 5 ++++- .../src/main/groovy/nextflow/cli/CmdRun.groovy | 7 ++++--- .../src/main/groovy/nextflow/cli/CmdView.groovy | 4 +++- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 10 ++++++---- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index a1cc15188f..3901f76e40 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -15,6 +15,9 @@ */ package nextflow.cli + +import static nextflow.scm.AssetManager.revisionDelim + import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -52,7 +55,7 @@ class CmdClone extends CmdBase implements HubOptions { Plugins.init() // the pipeline name String pipeline = args[0] - String revisionSuffix = revision ? ':'+revision : '' + String revisionSuffix = revision ? revisionDelim + revision : '' final manager = new AssetManager(pipeline, revision, this) // the target directory is the second parameter diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index 553a8ea723..54b7683e8f 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -16,6 +16,8 @@ package nextflow.cli +import static nextflow.scm.AssetManager.revisionDelim + import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -53,13 +55,13 @@ class CmdDrop extends CmdBase { Plugins.init() def manager = new AssetManager(args[0], revision) if( !manager.localPath.exists() ) { - throw new AbortOperationException("No match found for: ${manager.project}${revision ? ':'+revision : ''}") + throw new AbortOperationException("No match found for: ${manager.project}${revision ? revisionDelim + revision : ''}") } if( this.force || manager.isClean() ) { manager.close() if( !manager.localPath.deleteDir() ) - throw new AbortOperationException("Unable to delete project `${manager.project}${revision ? ':'+revision : ''}` -- Check access permissions for path: ${manager.localPath}") + throw new AbortOperationException("Unable to delete project `${manager.project}${revision ? revisionDelim + revision : ''}` -- Check access permissions for path: ${manager.localPath}") return } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 5c6110adb5..89985c3af8 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -16,6 +16,8 @@ package nextflow.cli +import static nextflow.scm.AssetManager.revisionDelim + import java.lang.management.ManagementFactory import java.nio.file.spi.FileSystemProvider @@ -80,7 +82,7 @@ class CmdInfo extends CmdBase { Plugins.init() final manager = new AssetManager(args[0], revision) if( !manager.isLocal() ) - throw new AbortOperationException("Unknown project `${args[0]}${revision ? ':'+revision : ''}`") + throw new AbortOperationException("Unknown project `${args[0]}${revision ? revisionDelim + revision : ''}`") if( !format || format == 'text' ) { printText(manager,level) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 80cba9d588..988d4ea085 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -15,6 +15,9 @@ */ package nextflow.cli + +import static nextflow.scm.AssetManager.revisionDelim + import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -73,7 +76,7 @@ class CmdPull extends CmdBase implements HubOptions { Plugins.init() list.each { - log.info "Checking $it${revision ? ':'+revision : ''} ..." + log.info "Checking $it${revision ? revisionDelim + revision : ''} ..." def manager = new AssetManager(it, revision, this) def result = manager.download(deep) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index f0736c29a5..2424f1d75e 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -18,6 +18,7 @@ package nextflow.cli import static org.fusesource.jansi.Ansi.* +import static nextflow.scm.AssetManager.revisionDelim import java.nio.file.NoSuchFileException import java.nio.file.Path @@ -579,8 +580,8 @@ class CmdRun extends CmdBase implements HubOptions { boolean checkForUpdate = true if( !manager.isRunnable() || latest ) { if( offline ) - throw new AbortOperationException("Unknown project `$repo${revision ? ':'+revision : ''}` -- NOTE: automatic download from remote repositories is disabled") - log.info "Pulling $repo${revision ? ':'+revision : ''} ..." + throw new AbortOperationException("Unknown project `$repo${revision ? revisionDelim + revision : ''}` -- NOTE: automatic download from remote repositories is disabled") + log.info "Pulling $repo${revision ? revisionDelim + revision : ''} ..." def result = manager.download(deep) if( result ) log.info " $result" @@ -599,7 +600,7 @@ class CmdRun extends CmdBase implements HubOptions { throw e } catch( Exception e ) { - throw new AbortOperationException("Unknown error accessing project `$repo${revision ? ':'+revision : ''}` -- Repository may be corrupted: ${manager.localPath}", e) + throw new AbortOperationException("Unknown error accessing project `$repo${revision ? revisionDelim + revision : ''}` -- Repository may be corrupted: ${manager.localPath}", e) } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy index 8ef0dc9cff..42901f5f70 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy @@ -16,6 +16,8 @@ package nextflow.cli +import static nextflow.scm.AssetManager.revisionDelim + import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -56,7 +58,7 @@ class CmdView extends CmdBase { Plugins.init() def manager = new AssetManager(args[0], revision) if( !manager.isLocal() ) - throw new AbortOperationException("Unknown project `${args[0]}${revision ? ':'+revision : ''}`") + throw new AbortOperationException("Unknown project `${args[0]}${revision ? revisionDelim + revision : ''}`") if( all ) { if( !quiet ) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 80fec899eb..c9b0ee32d1 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -62,6 +62,8 @@ class AssetManager { @PackageScope static File root = DEFAULT_ROOT + static public final String revisionDelim = ':' + /** * The pipeline name. It must be in the form {@code username/repo} where 'username' * is a valid user name or organisation account, while 'repo' is the repository name @@ -133,12 +135,12 @@ class AssetManager { this.providerConfigs = ProviderConfig.createFromMap(config) - this.project = resolveName(pipelineName, revision) this.revision = revision - this.localPath = checkProjectDir(project, revision) + this.project = resolveName(pipelineName, this.revision) + this.localPath = checkProjectDir(project, this.revision) this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) - this.provider.setRevision(revision) + this.provider.setRevision(this.revision) setupCredentials(cliOpts) validateProjectDir() @@ -195,7 +197,7 @@ class AssetManager { throw new IllegalArgumentException("Not a valid project name: $projectName") } - new File(root, project + (revision ? ':'+revision : '')) + new File(root, project + (revision ? revisionDelim + revision : '')) } /** From 6706bd9a99a75dc169ad06774da16d0dca8ffa5c Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Wed, 28 Feb 2024 07:39:06 +0000 Subject: [PATCH 19/91] nf pull: option to list or not revs for each project Signed-off-by: Dr Marco De La Pierre --- .../src/main/groovy/nextflow/cli/CmdList.groovy | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 5b08be249a..068706af37 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -16,6 +16,9 @@ package nextflow.cli +import static nextflow.scm.AssetManager.revisionDelim + +import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic import groovy.util.logging.Slf4j @@ -33,6 +36,9 @@ class CmdList extends CmdBase { static final public NAME = 'list' + @Parameter(names=['-r','-revisions'], description = 'For each project, also list revisions') + Boolean revisions + @Override final String getName() { NAME } @@ -45,7 +51,11 @@ class CmdList extends CmdBase { return } + if (revisions) { all.each { println it } + } else { + all.collect{ it.replaceAll( /$revisionDelim.*/, '' ) }.unique().each{println it} + } } } From e62f543cf75557f6f79805c7d5c1c0b40e4a92bb Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Wed, 28 Feb 2024 14:46:34 +0000 Subject: [PATCH 20/91] nicer output for nf list -r Signed-off-by: Dr Marco De La Pierre --- .../nextflow/src/main/groovy/nextflow/cli/CmdList.groovy | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 068706af37..7ce21dd96a 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -52,9 +52,13 @@ class CmdList extends CmdBase { } if (revisions) { - all.each { println it } + all.collect{ it.tokenize(revisionDelim) } + .groupBy{ it[0] } + .each{ println it.value[0][0] ; it.value.each{ y -> println ( y.size()==1 ? ' (default)' : ' ' + y[1] ) } } } else { - all.collect{ it.replaceAll( /$revisionDelim.*/, '' ) }.unique().each{println it} + all.collect{ it.replaceAll( /$revisionDelim.*/, '' ) } + .unique() + .each{println it} } } From bd198778907f0f808b47387c2095f432c40a6740 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 29 Feb 2024 02:37:21 +0000 Subject: [PATCH 21/91] minor edit to CmdList Signed-off-by: Dr Marco De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 7ce21dd96a..54d175fb74 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -36,7 +36,7 @@ class CmdList extends CmdBase { static final public NAME = 'list' - @Parameter(names=['-r','-revisions'], description = 'For each project, also list revisions') + @Parameter(names=['-a','-all-revisions'], description = 'For each project, also list revisions') Boolean revisions @Override @@ -58,7 +58,7 @@ class CmdList extends CmdBase { } else { all.collect{ it.replaceAll( /$revisionDelim.*/, '' ) } .unique() - .each{println it} + .each{ println it } } } From c0268af0f94f2ff9824609b7660f7b3dcc415c02 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 29 Feb 2024 03:12:54 +0000 Subject: [PATCH 22/91] AssetManager: adding listRevisions method (work in progress) Signed-off-by: Dr Marco De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index c9b0ee32d1..a91d5516ec 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -554,6 +554,30 @@ class AssetManager { return result } + /** + * @return The list of available revisions for a given AssetManager project + */ + static List listRevisions( String project ) { + log.debug "Listing revisions for project: $project" + + def result = new LinkedList() + + if( !root.exists() ) + return result + + def proj = project.tokenize('/').toList() + root.eachDir { File org -> + org.eachDir { File it -> + String itOrg = org.getName().toString() ; + String itName = it.getName().toString().tokenize(revisionDelim)[0] ; + Boolean matches = ( itOrg == proj[0] && itName == proj[1] ) + result << ( matches ? "${org.getName()}/${it.getName()}".toString() : null ) + } + } + + return result + } + // updated for new localPath schema (see localPath declaration at top of this class file) static protected def find( String name, String revision = null ) { def exact = [] From aae2afc17eb2fa616596ce4e54bac749edc99990 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 29 Feb 2024 11:26:08 +0800 Subject: [PATCH 23/91] small tune to CmdList Signed-off-by: Dr Marco Claudio De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 54d175fb74..1c2926070a 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -54,7 +54,7 @@ class CmdList extends CmdBase { if (revisions) { all.collect{ it.tokenize(revisionDelim) } .groupBy{ it[0] } - .each{ println it.value[0][0] ; it.value.each{ y -> println ( y.size()==1 ? ' (default)' : ' ' + y[1] ) } } + .each{ println ' ' + it.value[0][0] ; it.value.each{ y -> println ( y.size()==1 ? ' (default)' : ' ' + y[1] ) } } } else { all.collect{ it.replaceAll( /$revisionDelim.*/, '' ) } .unique() From 268ec7978013bfbceaaabc4d56f1ebc699d8c29a Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 29 Feb 2024 18:02:39 +0800 Subject: [PATCH 24/91] minor tweak to CmdList Signed-off-by: Dr Marco Claudio De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 1c2926070a..4f80670dd3 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -58,7 +58,7 @@ class CmdList extends CmdBase { } else { all.collect{ it.replaceAll( /$revisionDelim.*/, '' ) } .unique() - .each{ println it } + .each{ println ' ' + it } } } From ac8d75521bf62818143f63f56bb9e4338106aa54 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 29 Feb 2024 18:03:34 +0800 Subject: [PATCH 25/91] AssetManager: listRevisions method now working Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index a91d5516ec..f8c6b54855 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -555,7 +555,7 @@ class AssetManager { } /** - * @return The list of available revisions for a given AssetManager project + * @return The list of available revisions for a given project name */ static List listRevisions( String project ) { log.debug "Listing revisions for project: $project" @@ -565,13 +565,9 @@ class AssetManager { if( !root.exists() ) return result - def proj = project.tokenize('/').toList() - root.eachDir { File org -> - org.eachDir { File it -> - String itOrg = org.getName().toString() ; - String itName = it.getName().toString().tokenize(revisionDelim)[0] ; - Boolean matches = ( itOrg == proj[0] && itName == proj[1] ) - result << ( matches ? "${org.getName()}/${it.getName()}".toString() : null ) + list().each { + if( it.tokenize(revisionDelim)[0] == project ) { + result << it } } From 70c8bcccfce9fe30299b3993080b769cd85a33ad Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 29 Feb 2024 18:06:03 +0800 Subject: [PATCH 26/91] CmdDrop option to drop all revisions of given project Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/cli/CmdDrop.groovy | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index 54b7683e8f..9a4ab616fb 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -44,6 +44,9 @@ class CmdDrop extends CmdBase { @Parameter(names=['-r','-revision'], description = 'Revision of the project to drop (either a git branch, tag or commit SHA number)') String revision + @Parameter(names=['-a','-all-revisions'], description = 'For specified project, drop all revisions') + Boolean allrevisions + @Parameter(names='-f', description = 'Delete the repository without taking care of local changes') boolean force @@ -53,18 +56,33 @@ class CmdDrop extends CmdBase { @Override void run() { Plugins.init() - def manager = new AssetManager(args[0], revision) - if( !manager.localPath.exists() ) { - throw new AbortOperationException("No match found for: ${manager.project}${revision ? revisionDelim + revision : ''}") + + List dropList = [] + if ( allrevisions ) { + AssetManager.listRevisions(args[0]).each { + dropList << new AssetManager(it.tokenize(revisionDelim)[0], it.tokenize(revisionDelim)[1]) + } + } else { + dropList << new AssetManager(args[0], revision) } - if( this.force || manager.isClean() ) { - manager.close() - if( !manager.localPath.deleteDir() ) - throw new AbortOperationException("Unable to delete project `${manager.project}${revision ? revisionDelim + revision : ''}` -- Check access permissions for path: ${manager.localPath}") - return + if ( !dropList ) { + throw new AbortOperationException("No revisions found for specified project: ${args[0]}") } - throw new AbortOperationException("Local project repository contains uncommitted changes -- won't drop it") + dropList.each { manager -> + if( !manager.localPath.exists() ) { + throw new AbortOperationException("No match found for: ${manager.project}${manager.revision ? revisionDelim + manager.revision : ''}") + } + + if( this.force || manager.isClean() ) { + manager.close() + if( !manager.localPath.deleteDir() ) + throw new AbortOperationException("Unable to delete project `${manager.project}${manager.revision ? revisionDelim + manager.revision : ''}` -- Check access permissions for path: ${manager.localPath}") + return + } + + throw new AbortOperationException("Local project repository contains uncommitted changes -- won't drop it") + } } } From 8bcd717e8f0253a1288adbda8f621f80014f40f7 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 11:55:52 +0100 Subject: [PATCH 27/91] AssetManagerTest: added test for method listRevisions Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 068c20dc9c..6531f84c21 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -103,6 +103,32 @@ class AssetManagerTest extends Specification { } + def testListRevisions() { + given: + def folder = tempDir.getRoot() + folder.resolve('cbcrg/pipe1').mkdirs() + folder.resolve('cbcrg/pipe2').mkdirs() + folder.resolve('cbcrg/pipe2:v2').mkdirs() + folder.resolve('cbcrg/pipe3:v3').mkdirs() + + def manager = new AssetManager() + + when: + def list = manager.listRevisions('cbcrg/pipe1') + then: + list == ['cbcrg/pipe1'] + + when: + list = manager.listRevisions('cbcrg/pipe3') + then: + list == ['cbcrg/pipe3:v3'] + + when: + list = manager.listRevisions('cbcrg/pipe2') + then: + list == ['cbcrg/pipe2', 'cbcrg/pipe2:v2'] + } + def testResolveName() { From 4616e7f6577f14fd1969c3e8f298c79788e3a419 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 12:00:35 +0100 Subject: [PATCH 28/91] docs - cli: add -a options for list and drop Signed-off-by: Dr Marco Claudio De La Pierre --- docs/cli.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/cli.md b/docs/cli.md index 119c23ea75..f566e59c62 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -535,6 +535,9 @@ The `drop` command is used to remove the projects which have been downloaded int **Options** +`-a, -all-revisions` +: For specified project, drop all revisions. + `-f` : Delete the repository without taking care of local changes. @@ -878,6 +881,9 @@ The `list` commands prints a list of the projects which are already downloaded i **Options** +`-a, -all-revisions` +: For each project, also list revisions. + `-h, -help` : Print the command usage. From e4b9d78b278775648b650ddf3a2d29d41204344b Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 12:08:08 +0100 Subject: [PATCH 29/91] docs - cli: add/update -r option for relevant commands Signed-off-by: Dr Marco Claudio De La Pierre --- docs/cli.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index f566e59c62..14a8f460b2 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -366,7 +366,7 @@ The `clone` command downloads a pipeline from a Git-hosting platform into the *c : Service hub where the project is hosted. Options: `gitlab` or `bitbucket`. `-r` (`master`) -: Revision to clone - It can be a git branch, tag, or revision number. +: Revision of the project to clone (either a git branch, tag or commit SHA number). `-user` : Private repository user name. @@ -415,6 +415,9 @@ The `config` command is used for printing the project's configuration i.e. the ` `-properties` : Print config using Java properties notation. +`-r, -revision` +: Revision of the project (either a git branch, tag or commit SHA number). + `-a, -show-profiles` : Show all configuration profiles. @@ -544,6 +547,9 @@ The `drop` command is used to remove the projects which have been downloaded int `-h, -help` : Print the command usage. +`-r, -revision` +: Revision of the project to drop (either a git branch, tag or commit SHA number). + **Examples** Drop the `nextflow-io/hello` project. @@ -1078,7 +1084,7 @@ The `pull` command downloads a pipeline from a Git-hosting platform into the glo : Service hub where the project is hosted. Options: `gitlab` or `bitbucket` `-r, -revision` -: Revision of the project to run (either a git branch, tag or commit hash). +: Revision of the project to pull (either a git branch, tag or commit SHA number). : When passing a git tag or branch, the `workflow.revision` and `workflow.commitId` fields are populated. When passing only the commit hash, `workflow.revision` is not defined. `-user` @@ -1221,7 +1227,7 @@ The `run` command is used to execute a local pipeline script or remote pipeline : Execute the script using the cached results, useful to continue executions that was stopped by an error. `-r, -revision` -: Revision of the project to run (either a git branch, tag or commit hash). +: Revision of the project to run (either a git branch, tag or commit SHA number). : When passing a git tag or branch, the `workflow.revision` and `workflow.commitId` fields are populated. When passing only the commit hash, `workflow.revision` is not defined. `-stub-run, -stub` @@ -1430,6 +1436,9 @@ The `view` command is used to inspect the pipelines that are already stored in t `-q` : Hide header line. +`-r, -revision` +: Revision of the project (either a git branch, tag or commit SHA number). + **Examples** Viewing the contents of a downloaded pipeline. From 958955a6fa78db3e3fa6b68f901053c944659292 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 13:50:36 +0100 Subject: [PATCH 30/91] CmdInfo: now also prints info on pulled revisions Signed-off-by: Dr Marco Claudio De La Pierre --- docs/cli.md | 3 ++ .../main/groovy/nextflow/cli/CmdDrop.groovy | 3 +- .../main/groovy/nextflow/cli/CmdInfo.groovy | 3 ++ .../groovy/nextflow/scm/AssetManager.groovy | 44 +++++++++++++------ 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index 14a8f460b2..ca7caf2a6e 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -691,6 +691,9 @@ If no run name or session id is provided, it will clean the latest run. `-o` (`text`) : Output format, either `text`, `json` or `yaml`. +`-r, -revision` +: Revision of the project (either a git branch, tag or commit SHA number). + **Examples** Display Nextflow runtime and system info: diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index 9a4ab616fb..f30811d0ab 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -59,7 +59,8 @@ class CmdDrop extends CmdBase { List dropList = [] if ( allrevisions ) { - AssetManager.listRevisions(args[0]).each { + def referenceManager = new AssetManager(args[0]) + referenceManager.listRevisions().each { dropList << new AssetManager(it.tokenize(revisionDelim)[0], it.tokenize(revisionDelim)[1]) } } else { diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 89985c3af8..2b3dea1ebe 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -104,7 +104,9 @@ class CmdInfo extends CmdBase { protected printText(AssetManager manager, int level) { final manifest = manager.getManifest() + def printedRevision = manager.revision ?: manager.getDefaultBranch() out.println " project name: ${manager.project}" + out.println " revision : ${printedRevision}" out.println " repository : ${manager.repositoryUrl}" out.println " local path : ${manager.localPath}" out.println " main script : ${manager.mainScriptName}" @@ -142,6 +144,7 @@ class CmdInfo extends CmdBase { protected Map createMap(AssetManager manager) { def result = [:] result.projectName = manager.project + result.revision = manager.revision ?: manager.getDefaultBranch() result.repository = manager.repositoryUrl result.localPath = manager.localPath?.toString() result.manifest = manager.manifest.toMap() diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index f8c6b54855..26ee50124c 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -314,6 +314,8 @@ class AssetManager { String getProject() { project } + String getRevision() { revision } + String getHub() { hub } @PackageScope @@ -557,8 +559,8 @@ class AssetManager { /** * @return The list of available revisions for a given project name */ - static List listRevisions( String project ) { - log.debug "Listing revisions for project: $project" + List listRevisions( String projectName = project ) { + log.debug "Listing revisions for project: $projectName" def result = new LinkedList() @@ -566,7 +568,7 @@ class AssetManager { return result list().each { - if( it.tokenize(revisionDelim)[0] == project ) { + if( it.tokenize(revisionDelim)[0] == projectName ) { result << it } } @@ -744,6 +746,18 @@ class AssetManager { names.get( head.objectId ) ?: head.objectId.name() } + /** + * @return The name of all currently pulled revisions for a given project, i.e. locally available + * + * If revision is null, default is assumed + */ + List getPulledRevisions() { + return listRevisions().collect{ + it -> String y = it.tokenize(revisionDelim)[1] + it = ( y != null ? y : getDefaultBranch() ) + } + } + RevisionInfo getCurrentRevisionAndName() { Ref head = git.getRepository().findRef(Constants.HEAD); if( !head ) @@ -771,30 +785,32 @@ class AssetManager { /** * @return A list of existing branches and tags names. For example *
-     *     * master (default)
-     *       patch-x
-     *       v1.0 (t)
-     *       v1.1 (t)
+     *     * P master (default)
+     *         patch-x
+     *         v1.0 (t)
+     *         v1.1 (t)
      * 
* - * The star character on the left highlight the current revision, the string {@code (default)} - * ticks that it is the default working branch (usually the master branch), while the string {@code (t)} - * shows that the revision is a git tag (instead of a branch) + * The star character on the left highlights the selected revision, + * the character {@code P} on the left indicates the revision is pulled locally, + * the string {@code (default)} ticks that it is the default working branch, + * while the string {@code (t)} shows that the revision is a git tag (instead of a branch) */ @Deprecated List getRevisions(int level) { def current = getCurrentRevision() def master = getDefaultBranch() + def pulled = getPulledRevisions() List branches = getBranchList() .findAll { it.name.startsWith('refs/heads/') || it.name.startsWith('refs/remotes/origin/') } .unique { shortenRefName(it.name) } - .collect { Ref it -> refToString(it,current,master,false,level) } + .collect { Ref it -> refToString(it,current,master,pulled,false,level) } List tags = getTagList() .findAll { it.name.startsWith('refs/tags/') } - .collect { refToString(it,current,master,true,level) } + .collect { refToString(it,current,master,pulled,true,level) } def result = new ArrayList(branches.size() + tags.size()) result.addAll(branches) @@ -834,6 +850,7 @@ class AssetManager { result.current = current // current branch name result.master = master // master branch name + result.pulled = getPulledRevisions() // list of pulled revisions result.branches = branches // collection of branches result.tags = tags // collect of tags return result @@ -868,11 +885,12 @@ class AssetManager { return human ? obj.name.substring(0,10) : obj.name } - protected String refToString(Ref ref, String current, String master, boolean tag, int level ) { + protected String refToString(Ref ref, String current, String master, List pulled, boolean tag, int level ) { def result = new StringBuilder() def name = shortenRefName(ref.name) result << (name == current ? '*' : ' ') + result << (name in pulled ? ' P' : ' ') if( level ) { def peel = git.getRepository().peel(ref) From f220e98cfb3a97e7d31e0cc856ac8c338c7d5cba Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 14:07:03 +0100 Subject: [PATCH 31/91] CmdInfo made smarter when non only non default revisions pulled Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/cli/CmdInfo.groovy | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 2b3dea1ebe..a1476ecc20 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -80,9 +80,15 @@ class CmdInfo extends CmdBase { } Plugins.init() - final manager = new AssetManager(args[0], revision) - if( !manager.isLocal() ) - throw new AbortOperationException("Unknown project `${args[0]}${revision ? revisionDelim + revision : ''}`") + def manager = new AssetManager(args[0], revision) + if( !manager.isLocal() ) { + if ( manager.listRevisions() && !revision ) { + manager = new AssetManager(args[0], manager.getPulledRevisions()[0]) + } + else { + throw new AbortOperationException("Unknown project `${args[0]}${revision ? revisionDelim + revision : ''}`") + } + } if( !format || format == 'text' ) { printText(manager,level) From 2ad9a24e5ab0286d55c076263b3719269364287b Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 20:28:32 +0100 Subject: [PATCH 32/91] CmdInfoTest updated Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/test/groovy/nextflow/cli/CmdInfoTest.groovy | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy index e9217bf4c9..e885519525 100644 --- a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy @@ -67,11 +67,12 @@ class CmdInfoTest extends Specification { then: screen.contains(" project name: nextflow-io/hello") + screen.contains(" revision : master") screen.contains(" repository : https://github.com/nextflow-io/hello") screen.contains(" local path : $tempDir/nextflow-io/hello" ) screen.contains(" main script : main.nf") screen.contains(" revisions : ") - screen.contains(" * master (default)") + screen.contains(" * P master (default)") } def 'should print json info' () { @@ -87,12 +88,15 @@ class CmdInfoTest extends Specification { then: json.projectName == "nextflow-io/hello" + json.revision == "master" json.repository == "https://github.com/nextflow-io/hello" json.localPath == "$tempDir/nextflow-io/hello" json.manifest.mainScript == 'main.nf' json.manifest.defaultBranch == 'master' json.revisions.current == 'master' json.revisions.master == 'master' + json.revisions.pulled.size()>1 + json.revisions.pulled.any { it == 'master' } json.revisions.branches.size()>1 json.revisions.branches.any { it.name == 'master' } json.revisions.tags.size()>1 @@ -113,12 +117,15 @@ class CmdInfoTest extends Specification { then: json.projectName == "nextflow-io/hello" + json.revision == "master" json.repository == "https://github.com/nextflow-io/hello" json.localPath == "$tempDir/nextflow-io/hello" json.manifest.mainScript == 'main.nf' json.manifest.defaultBranch == 'master' json.revisions.current == 'master' json.revisions.master == 'master' + json.revisions.pulled.size()>1 + json.revisions.pulled.any { it == 'master' } json.revisions.branches.size()>1 json.revisions.branches.any { it.name == 'master' } json.revisions.tags.size()>1 From 35ea81249b3b8291cbb578d3fb139250c3d19094 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 20:32:21 +0100 Subject: [PATCH 33/91] CmdInfoTest fix Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy index e885519525..1a39f2a556 100644 --- a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy @@ -95,7 +95,7 @@ class CmdInfoTest extends Specification { json.manifest.defaultBranch == 'master' json.revisions.current == 'master' json.revisions.master == 'master' - json.revisions.pulled.size()>1 + json.revisions.pulled.size() == 1 json.revisions.pulled.any { it == 'master' } json.revisions.branches.size()>1 json.revisions.branches.any { it.name == 'master' } @@ -124,7 +124,7 @@ class CmdInfoTest extends Specification { json.manifest.defaultBranch == 'master' json.revisions.current == 'master' json.revisions.master == 'master' - json.revisions.pulled.size()>1 + json.revisions.pulled.size() == 1 json.revisions.pulled.any { it == 'master' } json.revisions.branches.size()>1 json.revisions.branches.any { it.name == 'master' } From 80ecacd181a81d0da46d9103dadab160eb52d98d Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 20:36:35 +0100 Subject: [PATCH 34/91] CmdInfo: added code comment Signed-off-by: Dr Marco Claudio De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index a1476ecc20..8680ce0164 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -82,6 +82,7 @@ class CmdInfo extends CmdBase { Plugins.init() def manager = new AssetManager(args[0], revision) if( !manager.isLocal() ) { + // if no revision specified and default branch not found locally, use first one from list of local pulls if ( manager.listRevisions() && !revision ) { manager = new AssetManager(args[0], manager.getPulledRevisions()[0]) } From 5e4b45fdb9355d32f83e5633c8dae1849cc3981a Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 21:52:24 +0100 Subject: [PATCH 35/91] AssetManager: default revision recognised correctly if specified in manifest Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 26ee50124c..049de2b5d9 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -133,6 +133,13 @@ class AssetManager { @PackageScope AssetManager build( String pipelineName, String revision = null, Map config = null, HubOptions cliOpts = null ) { + if ( revision ) { + def referenceManager = new AssetManager(pipelineName, null, cliOpts) + if ( revision == referenceManager.getDefaultBranch() ) { + revision = null + } + } + this.providerConfigs = ProviderConfig.createFromMap(config) this.revision = revision From aa94d7b68ab099f41cf2ad717579d8c0cfb7991f Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 4 Mar 2024 22:03:20 +0100 Subject: [PATCH 36/91] small CLI Docs update Signed-off-by: Dr Marco Claudio De La Pierre --- docs/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli.md b/docs/cli.md index ca7caf2a6e..9a71652ae4 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -673,7 +673,7 @@ $ nextflow info [options] [project] **Description** -The `info` command prints out the nextflow runtime information about the hardware as well as the software versions of the Nextflow version and build, operating system, and Groovy and Java runtime. It can also be used to display information about a specific project. +The `info` command prints out the nextflow runtime information about the hardware as well as the software versions of the Nextflow version and build, operating system, and Groovy and Java runtime. It can also be used to display information about a specific project; in this case, note how revisions marked as `P` are pulled locally. If no run name or session id is provided, it will clean the latest run. From d965ee5dcd36ea6b7fc9712610e87d56c9bfe28f Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 6 Mar 2024 10:55:43 +0100 Subject: [PATCH 37/91] added a couple of comments Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 049de2b5d9..f9eb0465f6 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -133,6 +133,8 @@ class AssetManager { @PackageScope AssetManager build( String pipelineName, String revision = null, Map config = null, HubOptions cliOpts = null ) { + // if requested revision corresponds to the default branch, then unset it + // this avoids duplication of the default branch if ( revision ) { def referenceManager = new AssetManager(pipelineName, null, cliOpts) if ( revision == referenceManager.getDefaultBranch() ) { @@ -570,7 +572,6 @@ class AssetManager { log.debug "Listing revisions for project: $projectName" def result = new LinkedList() - if( !root.exists() ) return result @@ -754,7 +755,7 @@ class AssetManager { } /** - * @return The name of all currently pulled revisions for a given project, i.e. locally available + * @return The names of all locally pulled revisions for a given project * * If revision is null, default is assumed */ From 9aacb2bed52f63cb911036ff6ebcb005898eb910 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 21 Mar 2024 03:12:44 +0000 Subject: [PATCH 38/91] Review: REVISION_DELIM and added comments Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/cli/CmdClone.groovy | 4 +-- .../main/groovy/nextflow/cli/CmdDrop.groovy | 8 +++--- .../main/groovy/nextflow/cli/CmdInfo.groovy | 4 +-- .../main/groovy/nextflow/cli/CmdList.groovy | 6 ++--- .../main/groovy/nextflow/cli/CmdPull.groovy | 4 +-- .../main/groovy/nextflow/cli/CmdRun.groovy | 8 +++--- .../main/groovy/nextflow/cli/CmdView.groovy | 4 +-- .../groovy/nextflow/scm/AssetManager.groovy | 25 +++++++++++++------ 8 files changed, 36 insertions(+), 27 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index 3901f76e40..6977a7ea88 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -16,7 +16,7 @@ package nextflow.cli -import static nextflow.scm.AssetManager.revisionDelim +import static nextflow.scm.AssetManager.REVISION_DELIM import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters @@ -55,7 +55,7 @@ class CmdClone extends CmdBase implements HubOptions { Plugins.init() // the pipeline name String pipeline = args[0] - String revisionSuffix = revision ? revisionDelim + revision : '' + String revisionSuffix = revision ? REVISION_DELIM + revision : '' final manager = new AssetManager(pipeline, revision, this) // the target directory is the second parameter diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index f30811d0ab..875de92200 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -16,7 +16,7 @@ package nextflow.cli -import static nextflow.scm.AssetManager.revisionDelim +import static nextflow.scm.AssetManager.REVISION_DELIM import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters @@ -61,7 +61,7 @@ class CmdDrop extends CmdBase { if ( allrevisions ) { def referenceManager = new AssetManager(args[0]) referenceManager.listRevisions().each { - dropList << new AssetManager(it.tokenize(revisionDelim)[0], it.tokenize(revisionDelim)[1]) + dropList << new AssetManager(it.tokenize(REVISION_DELIM)[0], it.tokenize(REVISION_DELIM)[1]) } } else { dropList << new AssetManager(args[0], revision) @@ -73,13 +73,13 @@ class CmdDrop extends CmdBase { dropList.each { manager -> if( !manager.localPath.exists() ) { - throw new AbortOperationException("No match found for: ${manager.project}${manager.revision ? revisionDelim + manager.revision : ''}") + throw new AbortOperationException("No match found for: ${manager.project}${manager.revision ? REVISION_DELIM + manager.revision : ''}") } if( this.force || manager.isClean() ) { manager.close() if( !manager.localPath.deleteDir() ) - throw new AbortOperationException("Unable to delete project `${manager.project}${manager.revision ? revisionDelim + manager.revision : ''}` -- Check access permissions for path: ${manager.localPath}") + throw new AbortOperationException("Unable to delete project `${manager.project}${manager.revision ? REVISION_DELIM + manager.revision : ''}` -- Check access permissions for path: ${manager.localPath}") return } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 8680ce0164..8df05f5eb9 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -16,7 +16,7 @@ package nextflow.cli -import static nextflow.scm.AssetManager.revisionDelim +import static nextflow.scm.AssetManager.REVISION_DELIM import java.lang.management.ManagementFactory import java.nio.file.spi.FileSystemProvider @@ -87,7 +87,7 @@ class CmdInfo extends CmdBase { manager = new AssetManager(args[0], manager.getPulledRevisions()[0]) } else { - throw new AbortOperationException("Unknown project `${args[0]}${revision ? revisionDelim + revision : ''}`") + throw new AbortOperationException("Unknown project `${args[0]}${revision ? REVISION_DELIM + revision : ''}`") } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 4f80670dd3..f6c851931a 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -16,7 +16,7 @@ package nextflow.cli -import static nextflow.scm.AssetManager.revisionDelim +import static nextflow.scm.AssetManager.REVISION_DELIM import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters @@ -52,11 +52,11 @@ class CmdList extends CmdBase { } if (revisions) { - all.collect{ it.tokenize(revisionDelim) } + all.collect{ it.tokenize(REVISION_DELIM) } .groupBy{ it[0] } .each{ println ' ' + it.value[0][0] ; it.value.each{ y -> println ( y.size()==1 ? ' (default)' : ' ' + y[1] ) } } } else { - all.collect{ it.replaceAll( /$revisionDelim.*/, '' ) } + all.collect{ it.replaceAll( /$REVISION_DELIM.*/, '' ) } .unique() .each{ println ' ' + it } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 988d4ea085..2e41e5f5f4 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -16,7 +16,7 @@ package nextflow.cli -import static nextflow.scm.AssetManager.revisionDelim +import static nextflow.scm.AssetManager.REVISION_DELIM import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters @@ -76,7 +76,7 @@ class CmdPull extends CmdBase implements HubOptions { Plugins.init() list.each { - log.info "Checking $it${revision ? revisionDelim + revision : ''} ..." + log.info "Checking $it${revision ? REVISION_DELIM + revision : ''} ..." def manager = new AssetManager(it, revision, this) def result = manager.download(deep) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index 2424f1d75e..03b5cfecae 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -18,7 +18,7 @@ package nextflow.cli import static org.fusesource.jansi.Ansi.* -import static nextflow.scm.AssetManager.revisionDelim +import static nextflow.scm.AssetManager.REVISION_DELIM import java.nio.file.NoSuchFileException import java.nio.file.Path @@ -580,8 +580,8 @@ class CmdRun extends CmdBase implements HubOptions { boolean checkForUpdate = true if( !manager.isRunnable() || latest ) { if( offline ) - throw new AbortOperationException("Unknown project `$repo${revision ? revisionDelim + revision : ''}` -- NOTE: automatic download from remote repositories is disabled") - log.info "Pulling $repo${revision ? revisionDelim + revision : ''} ..." + throw new AbortOperationException("Unknown project `$repo${revision ? REVISION_DELIM + revision : ''}` -- NOTE: automatic download from remote repositories is disabled") + log.info "Pulling $repo${revision ? REVISION_DELIM + revision : ''} ..." def result = manager.download(deep) if( result ) log.info " $result" @@ -600,7 +600,7 @@ class CmdRun extends CmdBase implements HubOptions { throw e } catch( Exception e ) { - throw new AbortOperationException("Unknown error accessing project `$repo${revision ? revisionDelim + revision : ''}` -- Repository may be corrupted: ${manager.localPath}", e) + throw new AbortOperationException("Unknown error accessing project `$repo${revision ? REVISION_DELIM + revision : ''}` -- Repository may be corrupted: ${manager.localPath}", e) } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy index 42901f5f70..165be1f9b3 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy @@ -16,7 +16,7 @@ package nextflow.cli -import static nextflow.scm.AssetManager.revisionDelim +import static nextflow.scm.AssetManager.REVISION_DELIM import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters @@ -58,7 +58,7 @@ class CmdView extends CmdBase { Plugins.init() def manager = new AssetManager(args[0], revision) if( !manager.isLocal() ) - throw new AbortOperationException("Unknown project `${args[0]}${revision ? revisionDelim + revision : ''}`") + throw new AbortOperationException("Unknown project `${args[0]}${revision ? REVISION_DELIM + revision : ''}`") if( all ) { if( !quiet ) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 4b8c387cf2..fa4c66054c 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -62,7 +62,7 @@ class AssetManager { @PackageScope static File root = DEFAULT_ROOT - static public final String revisionDelim = ':' + static public final String REVISION_DELIM = ':' /** * The pipeline name. It must be in the form {@code username/repo} where 'username' @@ -206,7 +206,7 @@ class AssetManager { throw new IllegalArgumentException("Not a valid project name: $projectName") } - new File(root, project + (revision ? revisionDelim + revision : '')) + new File(root, project + (revision ? REVISION_DELIM + revision : '')) } /** @@ -572,7 +572,7 @@ class AssetManager { return result list().each { - if( it.tokenize(revisionDelim)[0] == projectName ) { + if( it.tokenize(REVISION_DELIM)[0] == projectName ) { result << it } } @@ -580,19 +580,28 @@ class AssetManager { return result } - // updated for new localPath schema (see localPath declaration at top of this class file) + // Updated for new localPath schema (see localPath declaration at top of this class file) static protected def find( String name, String revision = null ) { def exact = [] def partial = [] list().each { def items = it.split('/') - def itemsRev = items[1].tokenize(':') + /** + * itemsRev[0] is the name of each list'ed project + * itemsRev[1] is the revision + */ + def itemsRev = items[1].tokenize(REVISION_DELIM) + // Check on matching revision: either null or same revision string if( (!revision && !itemsRev[1]) || (revision && itemsRev[1] == revision) ) { + // Exact name match if( itemsRev[0] == name ) - exact << it.tokenize(':')[0] + // Return item without revision + exact << it.tokenize(REVISION_DELIM)[0] + // Partial name match else if( itemsRev[0].startsWith(name ) ) - partial << it.tokenize(':')[0] + // Return item without revision + partial << it.tokenize(REVISION_DELIM)[0] } } @@ -757,7 +766,7 @@ class AssetManager { */ List getPulledRevisions() { return listRevisions().collect{ - it -> String y = it.tokenize(revisionDelim)[1] + it -> String y = it.tokenize(REVISION_DELIM)[1] it = ( y != null ? y : getDefaultBranch() ) } } From 12718c79e0fe5763f8c90874b76f2baf2986ed23 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 21 Mar 2024 03:45:15 +0000 Subject: [PATCH 39/91] review: added method getProjectWithRevision Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy | 7 ++----- .../nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy | 4 ++-- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 2 ++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index 6977a7ea88..0c0e369317 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -16,8 +16,6 @@ package nextflow.cli -import static nextflow.scm.AssetManager.REVISION_DELIM - import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -55,7 +53,6 @@ class CmdClone extends CmdBase implements HubOptions { Plugins.init() // the pipeline name String pipeline = args[0] - String revisionSuffix = revision ? REVISION_DELIM + revision : '' final manager = new AssetManager(pipeline, revision, this) // the target directory is the second parameter @@ -72,9 +69,9 @@ class CmdClone extends CmdBase implements HubOptions { } manager.checkValidRemoteRepo() - print "Cloning ${manager.project}${revisionSuffix} ..." + print "Cloning ${manager.getProjectWithRevision()} ..." manager.clone(target, deep) print "\r" - println "${manager.project}${revisionSuffix} cloned to: $target" + println "${manager.getProjectWithRevision()} cloned to: $target" } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index 875de92200..fdad006d55 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -73,13 +73,13 @@ class CmdDrop extends CmdBase { dropList.each { manager -> if( !manager.localPath.exists() ) { - throw new AbortOperationException("No match found for: ${manager.project}${manager.revision ? REVISION_DELIM + manager.revision : ''}") + throw new AbortOperationException("No match found for: ${manager.getProjectWithRevision()}") } if( this.force || manager.isClean() ) { manager.close() if( !manager.localPath.deleteDir() ) - throw new AbortOperationException("Unable to delete project `${manager.project}${manager.revision ? REVISION_DELIM + manager.revision : ''}` -- Check access permissions for path: ${manager.localPath}") + throw new AbortOperationException("Unable to delete project `${manager.getProjectWithRevision()}` -- Check access permissions for path: ${manager.localPath}") return } diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index fa4c66054c..9f5b8ed762 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -326,6 +326,8 @@ class AssetManager { String getRevision() { revision } + String getProjectWithRevision() { project + ( revision ? REVISION_DELIM + revision : '' ) } + String getHub() { hub } @PackageScope From 0b572626c9e4773da9f59ba1bc5a464bc3dd32f4 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 21 Mar 2024 03:51:41 +0000 Subject: [PATCH 40/91] updated method getBaseNameWithRevision Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy | 2 +- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index 0c0e369317..b7be19d0b6 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -57,7 +57,7 @@ class CmdClone extends CmdBase implements HubOptions { // the target directory is the second parameter // otherwise default the current pipeline name - def target = new File(args.size()> 1 ? args[1] : manager.getBaseName()) + def target = new File(args.size()> 1 ? args[1] : manager.getBaseNameWithRevision()) if( target.exists() ) { if( target.isFile() ) throw new AbortOperationException("A file with the same name already exists: $target") diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 9f5b8ed762..266e483c70 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -503,10 +503,11 @@ class AssetManager { } - String getBaseName() { + String getBaseNameWithRevision() { def result = project.tokenize('/') if( result.size() > 2 ) throw new IllegalArgumentException("Not a valid project name: $project") - return result.size()==1 ? result[0] : result[1] + result = ( result.size()==1 ? result[0] : result[1] ) + return result + ( revision ? REVISION_DELIM + revision : '' ) } boolean isLocal() { From 17067eadcc691bc24a7021eb4322985b54249580 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 21 Mar 2024 06:38:20 +0000 Subject: [PATCH 41/91] docs/sharing: added paragraph on multiple revisions, with caveat on reproducibility Signed-off-by: Dr Marco De La Pierre Signed-off-by: Dr Marco Claudio De La Pierre --- docs/sharing.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/sharing.md b/docs/sharing.md index 2db5b9b527..d218597de1 100644 --- a/docs/sharing.md +++ b/docs/sharing.md @@ -58,6 +58,15 @@ nextflow run nextflow-io/hello -r v1.1 It will execute two different project revisions corresponding to the Git tag/branch having that names. +:::{versionadded} 24.03.0-edge +::: + +Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. + +:::{warning} +If you really care about reproducibility of your pipelines, you should explicitly refer to them by tag or commit ID, rather than my branch. This is because the same branch will point to different underlying commits over time, as pipeline development goes on. This caveat is particularly relevant in a scenario where multiple people manage and share the same local collection of pipelines. +::: + ## Commands to manage projects The following commands allows you to perform some basic operations that can be used to manage your projects. From 67dc5d5a4b7f836e656ec3a198698f70e312f424 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 21 Mar 2024 08:35:36 +0000 Subject: [PATCH 42/91] cmd info: removed sticky current revision, updated docs Signed-off-by: Dr Marco De La Pierre Signed-off-by: Dr Marco Claudio De La Pierre --- docs/cli.md | 3 --- docs/sharing.md | 8 ++++---- .../main/groovy/nextflow/cli/CmdInfo.groovy | 18 ++++++------------ .../groovy/nextflow/scm/AssetManager.groovy | 8 ++------ 4 files changed, 12 insertions(+), 25 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index c0c7ce5c1c..be95ff9f32 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -691,9 +691,6 @@ If no run name or session id is provided, it will clean the latest run. `-o` (`text`) : Output format, either `text`, `json` or `yaml`. -`-r, -revision` -: Revision of the project (either a git branch, tag or commit SHA number). - **Examples** Display Nextflow runtime and system info: diff --git a/docs/sharing.md b/docs/sharing.md index d218597de1..64dc771641 100644 --- a/docs/sharing.md +++ b/docs/sharing.md @@ -61,7 +61,7 @@ It will execute two different project revisions corresponding to the Git tag/bra :::{versionadded} 24.03.0-edge ::: -Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. +Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. Each downloaded revision is stored in a sister path to the default revision one, featuring an extra suffix string `:`. :::{warning} If you really care about reproducibility of your pipelines, you should explicitly refer to them by tag or commit ID, rather than my branch. This is because the same branch will point to different underlying commits over time, as pipeline development goes on. This caveat is particularly relevant in a scenario where multiple people manage and share the same local collection of pipelines. @@ -103,13 +103,13 @@ repository : http://github.com/nextflow-io/hello local path : $HOME/.nextflow/assets/nextflow-io/hello main script : main.nf revisions : -* master (default) +P master (default) mybranch - v1.1 [t] +P v1.1 [t] v1.2 [t] ``` -Starting from the top it shows: 1) the project name; 2) the Git repository URL; 3) the local folder where the project has been downloaded; 4) the script that is executed when launched; 5) the list of available revisions i.e. branches and tags. Tags are marked with a `[t]` on the right, the current checked-out revision is marked with a `*` on the left. +Starting from the top it shows: 1) the project name; 2) the Git repository URL; 3) the local path where the default project can be found (alternate revisions are in sister paths with an extra suffix `:`); 4) the script that is executed when launched; 5) the list of available revisions i.e. branches and tags. Tags are marked with a `[t]` on the right, the locally pulled revisions are marked with a `P` on the left. ### Pulling or updating a project diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 8df05f5eb9..428c914f9a 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -52,9 +52,6 @@ class CmdInfo extends CmdBase { @Parameter(description = 'project name') List args - @Parameter(names=['-r','-revision'], description = 'Revision of the project (either a git branch, tag or commit SHA number)') - String revision - @Parameter(names='-d',description = 'Show detailed information', arity = 0) boolean detailed @@ -80,14 +77,14 @@ class CmdInfo extends CmdBase { } Plugins.init() - def manager = new AssetManager(args[0], revision) + def manager = new AssetManager(args[0], null) if( !manager.isLocal() ) { - // if no revision specified and default branch not found locally, use first one from list of local pulls - if ( manager.listRevisions() && !revision ) { + // if default branch not found locally, use first one from list of local pulls + if ( manager.listRevisions() ) { manager = new AssetManager(args[0], manager.getPulledRevisions()[0]) } else { - throw new AbortOperationException("Unknown project `${args[0]}${revision ? REVISION_DELIM + revision : ''}`") + throw new AbortOperationException("Unknown project `${args[0]}`") } } @@ -111,11 +108,9 @@ class CmdInfo extends CmdBase { protected printText(AssetManager manager, int level) { final manifest = manager.getManifest() - def printedRevision = manager.revision ?: manager.getDefaultBranch() out.println " project name: ${manager.project}" - out.println " revision : ${printedRevision}" out.println " repository : ${manager.repositoryUrl}" - out.println " local path : ${manager.localPath}" + out.println " local path : ${manager.localPath.toString().tokenize(REVISION_DELIM)[0]}" out.println " main script : ${manager.mainScriptName}" if( manager.homePage && manager.homePage != manager.repositoryUrl ) out.println " home page : ${manager.homePage}" @@ -151,9 +146,8 @@ class CmdInfo extends CmdBase { protected Map createMap(AssetManager manager) { def result = [:] result.projectName = manager.project - result.revision = manager.revision ?: manager.getDefaultBranch() result.repository = manager.repositoryUrl - result.localPath = manager.localPath?.toString() + result.localPath = manager.localPath?.toString().tokenize(REVISION_DELIM)[0] result.manifest = manager.manifest.toMap() result.revisions = manager.getBranchesAndTags(checkForUpdates) return result diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 266e483c70..b586351db3 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -807,8 +807,7 @@ class AssetManager { * v1.1 (t) * * - * The star character on the left highlights the selected revision, - * the character {@code P} on the left indicates the revision is pulled locally, + * The character {@code P} on the left indicates the revision is pulled locally, * the string {@code (default)} ticks that it is the default working branch, * while the string {@code (t)} shows that the revision is a git tag (instead of a branch) */ @@ -847,7 +846,6 @@ class AssetManager { Map getBranchesAndTags(boolean checkForUpdates) { final result = [:] - final current = getCurrentRevision() final master = getDefaultBranch() final branches = [] @@ -864,7 +862,6 @@ class AssetManager { .findAll { it.name.startsWith('refs/tags/') } .each { Ref it -> tags << refToMap(it,remote) } - result.current = current // current branch name result.master = master // master branch name result.pulled = getPulledRevisions() // list of pulled revisions result.branches = branches // collection of branches @@ -905,8 +902,7 @@ class AssetManager { def result = new StringBuilder() def name = shortenRefName(ref.name) - result << (name == current ? '*' : ' ') - result << (name in pulled ? ' P' : ' ') + result << (name in pulled ? 'P' : ' ') if( level ) { def peel = git.getRepository().peel(ref) From 7716416cfa2671713c8df497ac21791852636954 Mon Sep 17 00:00:00 2001 From: Dr Marco De La Pierre Date: Thu, 21 Mar 2024 10:42:03 +0000 Subject: [PATCH 43/91] fixed unit tests in CmdInfoTest Signed-off-by: Dr Marco De La Pierre Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/test/groovy/nextflow/cli/CmdInfoTest.groovy | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy index 1a39f2a556..59a12a847f 100644 --- a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy @@ -67,12 +67,11 @@ class CmdInfoTest extends Specification { then: screen.contains(" project name: nextflow-io/hello") - screen.contains(" revision : master") screen.contains(" repository : https://github.com/nextflow-io/hello") screen.contains(" local path : $tempDir/nextflow-io/hello" ) screen.contains(" main script : main.nf") screen.contains(" revisions : ") - screen.contains(" * P master (default)") + screen.contains(" P master (default)") } def 'should print json info' () { @@ -88,12 +87,10 @@ class CmdInfoTest extends Specification { then: json.projectName == "nextflow-io/hello" - json.revision == "master" json.repository == "https://github.com/nextflow-io/hello" json.localPath == "$tempDir/nextflow-io/hello" json.manifest.mainScript == 'main.nf' json.manifest.defaultBranch == 'master' - json.revisions.current == 'master' json.revisions.master == 'master' json.revisions.pulled.size() == 1 json.revisions.pulled.any { it == 'master' } @@ -117,12 +114,10 @@ class CmdInfoTest extends Specification { then: json.projectName == "nextflow-io/hello" - json.revision == "master" json.repository == "https://github.com/nextflow-io/hello" json.localPath == "$tempDir/nextflow-io/hello" json.manifest.mainScript == 'main.nf' json.manifest.defaultBranch == 'master' - json.revisions.current == 'master' json.revisions.master == 'master' json.revisions.pulled.size() == 1 json.revisions.pulled.any { it == 'master' } From 561a59fe8328af0601a13f1399b332883ef35266 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 17 Jun 2024 11:34:55 +0200 Subject: [PATCH 44/91] docs update/fix Signed-off-by: Dr Marco Claudio De La Pierre --- docs/developer/diagrams/nextflow.scm.mmd | 2 +- docs/sharing.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/developer/diagrams/nextflow.scm.mmd b/docs/developer/diagrams/nextflow.scm.mmd index a512e36a75..5d015138b4 100644 --- a/docs/developer/diagrams/nextflow.scm.mmd +++ b/docs/developer/diagrams/nextflow.scm.mmd @@ -11,7 +11,7 @@ classDiagram revision : String localPath : File mainScript : String - repositoryProvider : RepositoryProvider + provider : RepositoryProvider hub : String providerConfigs : List~ProviderConfig~ } diff --git a/docs/sharing.md b/docs/sharing.md index 64dc771641..a4d597ab27 100644 --- a/docs/sharing.md +++ b/docs/sharing.md @@ -58,13 +58,13 @@ nextflow run nextflow-io/hello -r v1.1 It will execute two different project revisions corresponding to the Git tag/branch having that names. -:::{versionadded} 24.03.0-edge +:::{versionadded} 24.XX.0-edge ::: Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. Each downloaded revision is stored in a sister path to the default revision one, featuring an extra suffix string `:`. :::{warning} -If you really care about reproducibility of your pipelines, you should explicitly refer to them by tag or commit ID, rather than my branch. This is because the same branch will point to different underlying commits over time, as pipeline development goes on. This caveat is particularly relevant in a scenario where multiple people manage and share the same local collection of pipelines. +If you really care about reproducibility of your pipelines, consider explicitly referring to them by tag or commit ID, rather than my branch. This is because the same branch will point to different underlying commits over time, as pipeline development goes on. ::: ## Commands to manage projects From 48cf800cfd2407c631899b5c5932f3ede9fe6b63 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 17 Jun 2024 11:56:33 +0200 Subject: [PATCH 45/91] multi revs: consistent usage of manager.getProjectWithRevision() in Cmds Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy | 4 +--- .../nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy | 9 ++++----- .../nextflow/src/main/groovy/nextflow/cli/CmdView.groovy | 4 +--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 2e41e5f5f4..5928b08a9b 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -16,8 +16,6 @@ package nextflow.cli -import static nextflow.scm.AssetManager.REVISION_DELIM - import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -76,8 +74,8 @@ class CmdPull extends CmdBase implements HubOptions { Plugins.init() list.each { - log.info "Checking $it${revision ? REVISION_DELIM + revision : ''} ..." def manager = new AssetManager(it, revision, this) + log.info "Checking ${manager.getProjectWithRevision()} ..." def result = manager.download(deep) manager.updateModules() diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index 7f94169f53..c54ec91982 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -17,7 +17,6 @@ package nextflow.cli import static org.fusesource.jansi.Ansi.* -import static nextflow.scm.AssetManager.REVISION_DELIM import java.nio.file.NoSuchFileException import java.nio.file.Path @@ -571,13 +570,13 @@ class CmdRun extends CmdBase implements HubOptions { * try to look for a pipeline in the repository */ def manager = new AssetManager(pipelineName, revision, this) - def repo = manager.getProject() + def repo = manager.getProjectWithRevision() boolean checkForUpdate = true if( !manager.isRunnable() || latest ) { if( offline ) - throw new AbortOperationException("Unknown project `$repo${revision ? REVISION_DELIM + revision : ''}` -- NOTE: automatic download from remote repositories is disabled") - log.info "Pulling $repo${revision ? REVISION_DELIM + revision : ''} ..." + throw new AbortOperationException("Unknown project `$repo` -- NOTE: automatic download from remote repositories is disabled") + log.info "Pulling $repo ..." def result = manager.download(deep) if( result ) log.info " $result" @@ -596,7 +595,7 @@ class CmdRun extends CmdBase implements HubOptions { throw e } catch( Exception e ) { - throw new AbortOperationException("Unknown error accessing project `$repo${revision ? REVISION_DELIM + revision : ''}` -- Repository may be corrupted: ${manager.localPath}", e) + throw new AbortOperationException("Unknown error accessing project `$repo` -- Repository may be corrupted: ${manager.localPath}", e) } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy index 165be1f9b3..54899d1f92 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy @@ -16,8 +16,6 @@ package nextflow.cli -import static nextflow.scm.AssetManager.REVISION_DELIM - import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -58,7 +56,7 @@ class CmdView extends CmdBase { Plugins.init() def manager = new AssetManager(args[0], revision) if( !manager.isLocal() ) - throw new AbortOperationException("Unknown project `${args[0]}${revision ? REVISION_DELIM + revision : ''}`") + throw new AbortOperationException("Unknown project `${manager.getProjectWithRevision()}`") if( all ) { if( !quiet ) From 6070273d1b831e0ba544207c2963fb353c9a2567 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 17 Jun 2024 14:53:46 +0200 Subject: [PATCH 46/91] AssetManager: undo redirect of default revision to null (circular manager instantiation) Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 440ca64d2f..67093dbcc2 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -133,15 +133,6 @@ class AssetManager { @PackageScope AssetManager build( String pipelineName, String revision = null, Map config = null, HubOptions cliOpts = null ) { - // if requested revision corresponds to the default branch, then unset it - // this avoids duplication of the default branch - if ( revision ) { - def referenceManager = new AssetManager(pipelineName, null, cliOpts) - if ( revision == referenceManager.getDefaultBranch() ) { - revision = null - } - } - this.providerConfigs = ProviderConfig.createFromMap(config) this.revision = revision From da159d91075d769f60fed38ff0b236438648e161 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 17 Jun 2024 14:56:23 +0200 Subject: [PATCH 47/91] AssetManager: removed chicken n egg between hubprovider and localpath Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 67093dbcc2..1530e127aa 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -137,11 +137,13 @@ class AssetManager { this.revision = revision this.project = resolveName(pipelineName, this.revision) - this.localPath = checkProjectDir(project, this.revision) + this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) this.provider.setRevision(this.revision) setupCredentials(cliOpts) + + this.localPath = checkProjectDir(this.project, this.revision) validateProjectDir() return this @@ -206,6 +208,7 @@ class AssetManager { */ @PackageScope void validateProjectDir() { + assert localPath if( !localPath.exists() ) { return @@ -392,7 +395,7 @@ class AssetManager { @Memoized String getGitRepositoryUrl() { - if( localPath.exists() ) { + if( localPathDefinedAndExists() ) { return localPath.toURI().toString() } @@ -450,7 +453,7 @@ class AssetManager { String text = null ConfigObject result = null try { - text = localPath.exists() ? new File(localPath, MANIFEST_FILE_NAME).text : provider.readText(MANIFEST_FILE_NAME) + text = localPathDefinedAndExists() ? new File(localPath, MANIFEST_FILE_NAME).text : provider.readText(MANIFEST_FILE_NAME) } catch( FileNotFoundException e ) { log.debug "Project manifest does not exist: ${e.message}" @@ -475,7 +478,7 @@ class AssetManager { } Path getConfigFile() { - if( localPath.exists() ) { + if( localPathDefinedAndExists() ) { return new File(localPath, MANIFEST_FILE_NAME).toPath() } else { @@ -513,6 +516,10 @@ class AssetManager { localPath.exists() && ( new File(localPath,DEFAULT_MAIN_FILE_NAME).exists() || new File(localPath,MANIFEST_FILE_NAME).exists() ) } + boolean localPathDefinedAndExists() { + localPath != null ? localPath.exists() : false + } + /** * @return true if no differences exist between the working-tree, the index, * and the current HEAD, false if differences do exist @@ -1069,7 +1076,7 @@ class AssetManager { } protected String getGitConfigRemoteUrl() { - if( !localPath ) { + if( !localPathDefinedAndExists() ) { return null } @@ -1108,11 +1115,11 @@ class AssetManager { protected String guessHubProviderFromGitConfig(boolean failFast=false) { - assert localPath // find the repository remote URL from the git project config file final domain = getGitConfigRemoteDomain() if( !domain && failFast ) { + assert localPath def message = (localGitConfig.exists() ? "Can't find git repository remote host -- Check config file at path: $localGitConfig" : "Can't find git repository config file -- Repository may be corrupted: $localPath" ) From 18249529aabec7f35c3953282b0695c20b39a6b8 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 17 Jun 2024 16:56:49 +0200 Subject: [PATCH 48/91] AssetManager: new location for revisions --- .../groovy/nextflow/scm/AssetManager.groovy | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 1530e127aa..04da023623 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -62,6 +62,10 @@ class AssetManager { @PackageScope static File root = DEFAULT_ROOT + static final String REVISION_MAP = '.nextflow/revisionMapFile' + + static public final String REVISION_SUBDIR = '.nextflow/commits' + static public final String REVISION_DELIM = ':' /** @@ -80,7 +84,7 @@ class AssetManager { /** * Directory where the pipeline is cloned (i.e. downloaded) * - * Schema: $NXF_ASSETS//[:] + * Schema: $NXF_ASSETS///.nextflow/commits/ */ private File localPath @@ -154,6 +158,27 @@ class AssetManager { localPath ? new File(localPath,'.git/config') : null } + /** + * Path of the revision -> commit map for the project + * + * Schema: $NXF_ASSETS///.nextflow/revisionMapFile + */ + @PackageScope + File getRevisionMap() { + File revisionMap = new File(root, project + '/' + REVISION_MAP) + return revisionMap.exists() ? revisionMap : null + } + + @PackageScope + File getRevisionSubdir() { + File revisionSubdir = new File(root, project + '/' + REVISION_SUBDIR) + return revisionSubdir.exists() ? revisionSubdir : null + } + + File getLocalRootPath() { + File localRootPath = new File(root, project) + return localRootPath.exists() ? localRootPath : null + } @PackageScope AssetManager setProject(String name) { this.project = name return this @@ -199,7 +224,7 @@ class AssetManager { throw new IllegalArgumentException("Not a valid project name: $projectName") } - new File(root, project + (revision ? REVISION_DELIM + revision : '')) + new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : 'DEFAULT_REVISION') ) } /** @@ -565,18 +590,16 @@ class AssetManager { /** * @return The list of available revisions for a given project name */ - List listRevisions( String projectName = project ) { + List listRevisions( String projectName = this.project ) { log.debug "Listing revisions for project: $projectName" def result = new LinkedList() if( !root.exists() ) return result + if( !revisionSubdir ) + return result - list().each { - if( it.tokenize(REVISION_DELIM)[0] == projectName ) { - result << it - } - } + revisionSubdir.eachDir { File it -> result << it.getName().toString() } return result } From c2db13284b115df1ae0ea30cb43f677964d5513b Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 17 Jun 2024 16:57:03 +0200 Subject: [PATCH 49/91] Using new Asset location for CmdDrop and CmdList --- .../main/groovy/nextflow/cli/CmdDrop.groovy | 11 +++++++--- .../main/groovy/nextflow/cli/CmdList.groovy | 20 +++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index fdad006d55..ff7f7d48b5 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -45,7 +45,7 @@ class CmdDrop extends CmdBase { String revision @Parameter(names=['-a','-all-revisions'], description = 'For specified project, drop all revisions') - Boolean allrevisions + Boolean allRevisions @Parameter(names='-f', description = 'Delete the repository without taking care of local changes') boolean force @@ -58,10 +58,10 @@ class CmdDrop extends CmdBase { Plugins.init() List dropList = [] - if ( allrevisions ) { + if ( allRevisions ) { def referenceManager = new AssetManager(args[0]) referenceManager.listRevisions().each { - dropList << new AssetManager(it.tokenize(REVISION_DELIM)[0], it.tokenize(REVISION_DELIM)[1]) + dropList << new AssetManager(args[0], it) } } else { dropList << new AssetManager(args[0], revision) @@ -85,5 +85,10 @@ class CmdDrop extends CmdBase { throw new AbortOperationException("Local project repository contains uncommitted changes -- won't drop it") } + + if ( allRevisions ) { + def referenceManager = new AssetManager(args[0]) + referenceManager.localRootPath.deleteDir() + } } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index f6c851931a..260a1359b5 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -37,7 +37,7 @@ class CmdList extends CmdBase { static final public NAME = 'list' @Parameter(names=['-a','-all-revisions'], description = 'For each project, also list revisions') - Boolean revisions + Boolean allRevisions @Override final String getName() { NAME } @@ -51,14 +51,18 @@ class CmdList extends CmdBase { return } - if (revisions) { - all.collect{ it.tokenize(REVISION_DELIM) } - .groupBy{ it[0] } - .each{ println ' ' + it.value[0][0] ; it.value.each{ y -> println ( y.size()==1 ? ' (default)' : ' ' + y[1] ) } } + if (allRevisions) { + all.each{ + println(" $it") + def revManager = new AssetManager(it) + revManager.listRevisions().each{ println(" $it") } + revManager.close() + } +// .collect{ it.tokenize(REVISION_DELIM) } +// .groupBy{ it[0] } +// .each{ println ' ' + it.value[0][0] ; it.value.each{ y -> println ( y.size()==1 ? ' (default)' : ' ' + y[1] ) } } } else { - all.collect{ it.replaceAll( /$REVISION_DELIM.*/, '' ) } - .unique() - .each{ println ' ' + it } + all.each{ println(" $it") } } } From 32fe34857d5d968dc02ec313f4db2eed51eb3e78 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 11:23:01 +0200 Subject: [PATCH 50/91] Using new Asset location for CmdPull --- .../main/groovy/nextflow/cli/CmdPull.groovy | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 5928b08a9b..51ee299f46 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -59,11 +59,11 @@ class CmdPull extends CmdBase implements HubOptions { if( !all && !args ) throw new AbortOperationException('Missing argument') - def list = all ? AssetManager.list() : args.toList() - if( !list ) { - log.info "(nothing to do)" - return - } + if( all && args ) + throw new AbortOperationException('Option `all` requires no arguments') + + if( all && revision ) + throw new AbortOperationException('Option `all` is not compatible with `revision`') /* only for testing purpose */ if( root ) { @@ -72,9 +72,31 @@ class CmdPull extends CmdBase implements HubOptions { // init plugin system Plugins.init() - - list.each { - def manager = new AssetManager(it, revision, this) + + List list = [] + if ( all ) { + def all = AssetManager.list() + all.each{ proj -> + def revManager = new AssetManager(proj) + revManager.listRevisions().each{ rev -> + if( rev == "DEFAULT_REVISION" ) + rev = null + list << new AssetManager(proj, rev, this) + } + revManager.close() + } + } else { + args.toList().each { + list << new AssetManager(it, revision, this) + } + } + + if( !list ) { + log.info "(nothing to do)" + return + } + + list.each { manager -> log.info "Checking ${manager.getProjectWithRevision()} ..." def result = manager.download(deep) From 8411c2ea455aee66bab01f49c99a04ccf96e065a Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 11:29:45 +0200 Subject: [PATCH 51/91] CmdDrop and CmdList: got rid of REVISION_DELIM Signed-off-by: Dr Marco Claudio De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy | 2 -- modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy | 5 ----- 2 files changed, 7 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index ff7f7d48b5..cac7ba78ae 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -16,8 +16,6 @@ package nextflow.cli -import static nextflow.scm.AssetManager.REVISION_DELIM - import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 260a1359b5..953491356c 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -16,8 +16,6 @@ package nextflow.cli -import static nextflow.scm.AssetManager.REVISION_DELIM - import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -58,9 +56,6 @@ class CmdList extends CmdBase { revManager.listRevisions().each{ println(" $it") } revManager.close() } -// .collect{ it.tokenize(REVISION_DELIM) } -// .groupBy{ it[0] } -// .each{ println ' ' + it.value[0][0] ; it.value.each{ y -> println ( y.size()==1 ? ' (default)' : ' ' + y[1] ) } } } else { all.each{ println(" $it") } } From c190daccc54d6de4c76407a32f1e3fd02738c5b1 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 11:55:44 +0200 Subject: [PATCH 52/91] Using new Asset location for CmdInfo Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy | 6 ++---- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 5 +---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 428c914f9a..7c52a6a414 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -16,8 +16,6 @@ package nextflow.cli -import static nextflow.scm.AssetManager.REVISION_DELIM - import java.lang.management.ManagementFactory import java.nio.file.spi.FileSystemProvider @@ -110,7 +108,7 @@ class CmdInfo extends CmdBase { out.println " project name: ${manager.project}" out.println " repository : ${manager.repositoryUrl}" - out.println " local path : ${manager.localPath.toString().tokenize(REVISION_DELIM)[0]}" + out.println " local path : ${manager.localRootPath?.toString()}" out.println " main script : ${manager.mainScriptName}" if( manager.homePage && manager.homePage != manager.repositoryUrl ) out.println " home page : ${manager.homePage}" @@ -147,7 +145,7 @@ class CmdInfo extends CmdBase { def result = [:] result.projectName = manager.project result.repository = manager.repositoryUrl - result.localPath = manager.localPath?.toString().tokenize(REVISION_DELIM)[0] + result.localPath = manager.localRootPath?.toString() result.manifest = manager.manifest.toMap() result.revisions = manager.getBranchesAndTags(checkForUpdates) return result diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 04da023623..cb5c7c8162 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -789,10 +789,7 @@ class AssetManager { * If revision is null, default is assumed */ List getPulledRevisions() { - return listRevisions().collect{ - it -> String y = it.tokenize(REVISION_DELIM)[1] - it = ( y != null ? y : getDefaultBranch() ) - } + listRevisions().collect{ it = ( it != "DEFAULT_REVISION" ? it : getDefaultBranch() ) } } RevisionInfo getCurrentRevisionAndName() { From 55868c7e1ee016038a986c99dafe531517545137 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 13:37:30 +0200 Subject: [PATCH 53/91] updated CmdClone Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy | 2 +- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index b7be19d0b6..0c0e369317 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -57,7 +57,7 @@ class CmdClone extends CmdBase implements HubOptions { // the target directory is the second parameter // otherwise default the current pipeline name - def target = new File(args.size()> 1 ? args[1] : manager.getBaseNameWithRevision()) + def target = new File(args.size()> 1 ? args[1] : manager.getBaseName()) if( target.exists() ) { if( target.isFile() ) throw new AbortOperationException("A file with the same name already exists: $target") diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index cb5c7c8162..fffd22a7d1 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -522,11 +522,10 @@ class AssetManager { } - String getBaseNameWithRevision() { + String getBaseName() { def result = project.tokenize('/') if( result.size() > 2 ) throw new IllegalArgumentException("Not a valid project name: $project") - result = ( result.size()==1 ? result[0] : result[1] ) - return result + ( revision ? REVISION_DELIM + revision : '' ) + return result.size()==1 ? result[0] : result[1] } boolean isLocal() { From 05ac8c91ebbbb35f35f89d71f2527e4f5ca4d9a6 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 14:03:44 +0200 Subject: [PATCH 54/91] AssetManager: reverted to original find() method Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 29 +++++-------------- .../nextflow/scm/AssetManagerTest.groovy | 10 ------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index fffd22a7d1..f7aa3288d0 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -140,7 +140,7 @@ class AssetManager { this.providerConfigs = ProviderConfig.createFromMap(config) this.revision = revision - this.project = resolveName(pipelineName, this.revision) + this.project = resolveName(pipelineName) this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) @@ -286,7 +286,7 @@ class AssetManager { * @return The fully qualified project name e.g. {@code cbcrg/foo} */ @PackageScope - String resolveName( String name, String revision = null ) { + String resolveName( String name ) { assert name // @@ -328,7 +328,7 @@ class AssetManager { name = parts[0] } - def qualifiedName = find(name, revision) + def qualifiedName = find(name) if( !qualifiedName ) { return "$DEFAULT_ORGANIZATION/$name".toString() } @@ -603,29 +603,16 @@ class AssetManager { return result } - // Updated for new localPath schema (see localPath declaration at top of this class file) - static protected def find( String name, String revision = null ) { + static protected def find( String name ) { def exact = [] def partial = [] list().each { def items = it.split('/') - /** - * itemsRev[0] is the name of each list'ed project - * itemsRev[1] is the revision - */ - def itemsRev = items[1].tokenize(REVISION_DELIM) - // Check on matching revision: either null or same revision string - if( (!revision && !itemsRev[1]) || (revision && itemsRev[1] == revision) ) { - // Exact name match - if( itemsRev[0] == name ) - // Return item without revision - exact << it.tokenize(REVISION_DELIM)[0] - // Partial name match - else if( itemsRev[0].startsWith(name ) ) - // Return item without revision - partial << it.tokenize(REVISION_DELIM)[0] - } + if( items[1] == name ) + exact << it + else if( items[1].startsWith(name ) ) + partial << it } def list = exact ?: partial diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 6531f84c21..c53cb7f054 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -146,11 +146,6 @@ class AssetManagerTest extends Specification { then: result == 'x/y' - when: - result = manager.resolveName('x/y', 'v2') - then: - result == 'x/y' - when: result = manager.resolveName('blast') then: @@ -176,11 +171,6 @@ class AssetManagerTest extends Specification { then: thrown(AbortOperationException) - when: - result = manager.resolveName('pipe2', 'v2') - then: - result == 'cbcrg/pipe2' - when: result = manager.resolveName('../blast/script.nf') then: From 0dbc77da95e2c3344f7e9c041da67ecc4d75df45 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 14:26:01 +0200 Subject: [PATCH 55/91] fixed revisionSubdir and unit tests Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 8 ++-- .../nextflow/scm/AssetManagerTest.groovy | 22 +++++------ .../nextflow/scm/UpdateModuleTest.groovy | 38 +++++++++---------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index f7aa3288d0..91daf50ac4 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -170,8 +170,8 @@ class AssetManager { } @PackageScope - File getRevisionSubdir() { - File revisionSubdir = new File(root, project + '/' + REVISION_SUBDIR) + File getRevisionSubdir( String projectName = project ) { + File revisionSubdir = new File(root, projectName + '/' + REVISION_SUBDIR) return revisionSubdir.exists() ? revisionSubdir : null } @@ -595,10 +595,10 @@ class AssetManager { def result = new LinkedList() if( !root.exists() ) return result - if( !revisionSubdir ) + if( !getRevisionSubdir(projectName) ) return result - revisionSubdir.eachDir { File it -> result << it.getName().toString() } + getRevisionSubdir(projectName).eachDir { File it -> result << it.getName().toString() } return result } diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index c53cb7f054..837e5b6863 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -106,27 +106,27 @@ class AssetManagerTest extends Specification { def testListRevisions() { given: def folder = tempDir.getRoot() - folder.resolve('cbcrg/pipe1').mkdirs() - folder.resolve('cbcrg/pipe2').mkdirs() - folder.resolve('cbcrg/pipe2:v2').mkdirs() - folder.resolve('cbcrg/pipe3:v3').mkdirs() + folder.resolve('cbcrg/pipe1/.nextflow/commits/DEFAULT_REVISION').mkdirs() + folder.resolve('cbcrg/pipe2/.nextflow/commits/DEFAULT_REVISION').mkdirs() + folder.resolve('cbcrg/pipe2/.nextflow/commits/v2').mkdirs() + folder.resolve('cbcrg/pipe3/.nextflow/commits/v3').mkdirs() def manager = new AssetManager() when: def list = manager.listRevisions('cbcrg/pipe1') then: - list == ['cbcrg/pipe1'] + list == ['DEFAULT_REVISION'] when: list = manager.listRevisions('cbcrg/pipe3') then: - list == ['cbcrg/pipe3:v3'] + list == ['v3'] when: list = manager.listRevisions('cbcrg/pipe2') then: - list == ['cbcrg/pipe2', 'cbcrg/pipe2:v2'] + list == ['DEFAULT_REVISION', 'v2'] } @@ -388,10 +388,10 @@ class AssetManagerTest extends Specification { } ''' def dir = tempDir.getRoot() - dir.resolve('foo/bar').mkdirs() - dir.resolve('foo/bar/nextflow.config').text = config - dir.resolve('foo/bar/.git').mkdir() - dir.resolve('foo/bar/.git/config').text = GIT_CONFIG_TEXT + dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION').mkdirs() + dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION/nextflow.config').text = config + dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION/.git').mkdir() + dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION/.git/config').text = GIT_CONFIG_TEXT when: def holder = new AssetManager() diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy index d3e82abf72..b7ab75b978 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy @@ -108,16 +108,16 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_x').exists() - target.resolve('local/pipe_x/.git').exists() - target.resolve('local/pipe_x/main.nf').exists() + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/.git').exists() + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/main.nf').exists() - target.resolve('local/pipe_x/prj_aaa').exists() - target.resolve('local/pipe_x/prj_aaa/file1.txt').text == 'Hello' - target.resolve('local/pipe_x/prj_aaa/file2.log').text == 'World' + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_aaa').exists() + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_aaa/file1.txt').text == 'Hello' + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_aaa/file2.log').text == 'World' - target.resolve('local/pipe_x/prj_bbb').exists() - target.resolve('local/pipe_x/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_x/prj_bbb/file2.log').text == 'Mondo' + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_bbb').exists() + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_bbb/file2.log').text == 'Mondo' } @@ -146,11 +146,11 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_2').exists() - target.resolve('local/pipe_2/.git').exists() - target.resolve('local/pipe_2/main.nf').exists() + target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/.git').exists() + target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/main.nf').exists() - target.resolve('local/pipe_2/prj_aaa').list().size()==0 - target.resolve('local/pipe_2/prj_bbb').list().size()==0 + target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/prj_aaa').list().size()==0 + target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/prj_bbb').list().size()==0 } def 'should clone selected submodules' () { @@ -179,16 +179,16 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_3').exists() - target.resolve('local/pipe_3/.git').exists() - target.resolve('local/pipe_3/main.nf').exists() + target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/.git').exists() + target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/main.nf').exists() - target.resolve('local/pipe_3/prj_aaa').list().size()==0 + target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_aaa').list().size()==0 - target.resolve('local/pipe_3/prj_bbb').exists() - target.resolve('local/pipe_3/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_bbb').exists() + target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_3/prj_ccc').exists() - target.resolve('local/pipe_3/prj_ccc/file-x.txt').text == 'x' + target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_ccc').exists() + target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_ccc/file-x.txt').text == 'x' } From e3cfec4709261cbc3aaeddb7939d2321c1696502 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 14:35:09 +0200 Subject: [PATCH 56/91] docs updates Signed-off-by: Dr Marco Claudio De La Pierre --- docs/cli.md | 4 ++-- docs/sharing.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index e06f15c3f8..195b631692 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -715,10 +715,10 @@ $ nextflow info nextflow-io/hello local path : /Users/evanfloden/.nextflow/assets/nextflow-io/hello main script : main.nf revisions : - * master (default) + P master (default) mybranch testing - v1.1 [t] + P v1.1 [t] v1.2 [t] ``` diff --git a/docs/sharing.md b/docs/sharing.md index a4d597ab27..82fc40e664 100644 --- a/docs/sharing.md +++ b/docs/sharing.md @@ -61,7 +61,7 @@ It will execute two different project revisions corresponding to the Git tag/bra :::{versionadded} 24.XX.0-edge ::: -Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. Each downloaded revision is stored in a sister path to the default revision one, featuring an extra suffix string `:`. +Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. Each downloaded revision is stored in a subdirecrory path of the local project path: `$NXF_ASSETS///.nextflow/commits/` (for the default branch, `` is set to `DEFAULT_REVISION`). :::{warning} If you really care about reproducibility of your pipelines, consider explicitly referring to them by tag or commit ID, rather than my branch. This is because the same branch will point to different underlying commits over time, as pipeline development goes on. @@ -100,7 +100,7 @@ By using the `info` command you can show information from a downloaded project. $ nextflow info hello project name: nextflow-io/hello repository : http://github.com/nextflow-io/hello -local path : $HOME/.nextflow/assets/nextflow-io/hello +local path : /Users/evanfloden/.nextflow/assets/nextflow-io/hello main script : main.nf revisions : P master (default) @@ -109,7 +109,7 @@ P v1.1 [t] v1.2 [t] ``` -Starting from the top it shows: 1) the project name; 2) the Git repository URL; 3) the local path where the default project can be found (alternate revisions are in sister paths with an extra suffix `:`); 4) the script that is executed when launched; 5) the list of available revisions i.e. branches and tags. Tags are marked with a `[t]` on the right, the locally pulled revisions are marked with a `P` on the left. +Starting from the top it shows: 1) the project name; 2) the Git repository URL; 3) the local path where the project can be found; 4) the script that is executed when launched; 5) the list of available revisions i.e. branches and tags. Tags are marked with a `[t]` on the right, the locally pulled revisions are marked with a `P` on the left. ### Pulling or updating a project From b6352c449942333d3b7dab9f3f9046ed629e941e Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 14:37:26 +0200 Subject: [PATCH 57/91] AssetManager: REVISION_DELIM not needed any more Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 91daf50ac4..aeae97ecd3 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -66,8 +66,6 @@ class AssetManager { static public final String REVISION_SUBDIR = '.nextflow/commits' - static public final String REVISION_DELIM = ':' - /** * The pipeline name. It must be in the form {@code username/repo} where 'username' * is a valid user name or organisation account, while 'repo' is the repository name @@ -345,7 +343,7 @@ class AssetManager { String getRevision() { revision } - String getProjectWithRevision() { project + ( revision ? REVISION_DELIM + revision : '' ) } + String getProjectWithRevision() { project + ( revision ? ':' + revision : '' ) } String getHub() { hub } From db4903a3084dea4ae98ba8fc0cba9bd9a584a25d Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 14:53:15 +0200 Subject: [PATCH 58/91] AssetManagerTest: further fixes Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManagerTest.groovy | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 837e5b6863..d991084f40 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -136,7 +136,6 @@ class AssetManagerTest extends Specification { def folder = tempDir.getRoot() folder.resolve('cbcrg/pipe1').mkdirs() folder.resolve('cbcrg/pipe2').mkdirs() - folder.resolve('cbcrg/pipe2:v2').mkdirs() folder.resolve('ncbi/blast').mkdirs() def manager = new AssetManager() @@ -217,7 +216,7 @@ class AssetManagerTest extends Specification { when: manager.download() then: - folder.resolve('nextflow-io/hello:v1.2/.git').isDirectory() + folder.resolve('nextflow-io/hello/.nextflow/commits/v1.2/.git').isDirectory() when: manager.download() @@ -237,7 +236,7 @@ class AssetManagerTest extends Specification { when: manager.download() then: - folder.resolve('nextflow-io/hello:6b9515aba6c7efc6a9b3f273ce116fc0c224bf68/.git').isDirectory() + folder.resolve('nextflow-io/hello/.nextflow/commits/6b9515aba6c7efc6a9b3f273ce116fc0c224bf68/.git').isDirectory() when: def result = manager.download() @@ -260,7 +259,7 @@ class AssetManagerTest extends Specification { when: manager.download() then: - folder.resolve('nextflow-io/hello:mybranch/.git').isDirectory() + folder.resolve('nextflow-io/hello/.nextflow/commits/mybranch/.git').isDirectory() when: def result = manager.download() @@ -563,9 +562,9 @@ class AssetManagerTest extends Specification { when: manager.download() then: - folder.resolve('nextflow-io/nf-test-branch:dev/.git').isDirectory() + folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/dev/.git').isDirectory() and: - folder.resolve('nextflow-io/nf-test-branch:dev/workflow.nf').text == "println 'Hello'\n" + folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/dev/workflow.nf').text == "println 'Hello'\n" } @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) @@ -592,9 +591,9 @@ class AssetManagerTest extends Specification { when: manager.download() then: - folder.resolve('nextflow-io/nf-test-branch:v0.1/.git').isDirectory() + folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/v0.1/.git').isDirectory() and: - folder.resolve('nextflow-io/nf-test-branch:v0.1/workflow.nf').text == "println 'Hello'\n" + folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/v0.1/workflow.nf').text == "println 'Hello'\n" } } From 90f8f1d41d171a3aa09a95afb33d9fd6e8603f36 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 18 Jun 2024 15:41:29 +0200 Subject: [PATCH 59/91] AssetManager: revert back to set revision in checkValidRemoteRepo() Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index aeae97ecd3..0825009273 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -142,7 +142,6 @@ class AssetManager { this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) - this.provider.setRevision(this.revision) setupCredentials(cliOpts) this.localPath = checkProjectDir(this.project, this.revision) @@ -409,7 +408,10 @@ class AssetManager { } AssetManager checkValidRemoteRepo() { - // Check that the remote git provider contains the main script file (main.nf by default) + // Configure the git provider to use the required revision as source for all needed remote resources: + // - config if present in repo (nextflow.config by default) + // - main script (main.nf by default) + provider.revision = revision final scriptName = getMainScriptName() provider.validateFor(scriptName) return this From a3d5557181e37dbbf0bd1d7f0d220f7023eb3dcf Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 19 Jun 2024 12:13:21 +0200 Subject: [PATCH 60/91] AssetManager: using existing revision map Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/cli/CmdInfo.groovy | 2 + .../groovy/nextflow/scm/AssetManager.groovy | 51 +++++++++++++++---- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 7c52a6a414..124b8a7096 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -80,6 +80,8 @@ class CmdInfo extends CmdBase { // if default branch not found locally, use first one from list of local pulls if ( manager.listRevisions() ) { manager = new AssetManager(args[0], manager.getPulledRevisions()[0]) + if( !manager.isLocal() ) + throw new AbortOperationException("Unknown project `${args[0]}`") } else { throw new AbortOperationException("Unknown project `${args[0]}`") diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 0825009273..7e443db1f0 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -62,7 +62,9 @@ class AssetManager { @PackageScope static File root = DEFAULT_ROOT - static final String REVISION_MAP = '.nextflow/revisionMapFile' + static final String BARE_REPO = '.nextflow/bare_repo' + + static final String REVISION_MAP = '.nextflow/revision_map_file' static public final String REVISION_SUBDIR = '.nextflow/commits' @@ -144,8 +146,7 @@ class AssetManager { this.provider = createHubProvider(hub) setupCredentials(cliOpts) - this.localPath = checkProjectDir(this.project, this.revision) - validateProjectDir() + defineProjectDir(this.project, this.revision) return this } @@ -155,8 +156,15 @@ class AssetManager { localPath ? new File(localPath,'.git/config') : null } + @PackageScope + File getBareRepo() { + new File(root, project + '/' + BARE_REPO) + } + /** - * Path of the revision -> commit map for the project + * Path of the "revision -> commit" map file for the project + * + * CSV format: , * * Schema: $NXF_ASSETS///.nextflow/revisionMapFile */ @@ -207,21 +215,42 @@ class AssetManager { } /** - * Verify the project name matcher the expected pattern. - * and return the directory where the project is stored locally + * Verify the project name matcher the expected pattern, + * map revision to commit ID, + * define the directory where the project is stored locally, + * and validate it. * * @param projectName A project name matching the pattern {@code owner/project} * @param revision Revision ID for the selected pipeline (git branch, tag or commit SHA number) * @return The project dir {@link File} */ @PackageScope - File checkProjectDir(String projectName, String revision) { - + void defineProjectDir(String projectName, String revision) { if( !isValidProjectName(projectName)) { throw new IllegalArgumentException("Not a valid project name: $projectName") } - new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : 'DEFAULT_REVISION') ) + String commitId = revisionToCommit(revision) + + if( commitId ) { + this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : 'DEFAULT_REVISION') ) + validateProjectDir() + } else { + this.localPath = null + } + } + + @PackageScope + String revisionToCommit(String revision) { + String commitId + + if( revisionMap ) { + String revisionTmp = revision ?: 'DEFAULT_REVISION' + commitId = revisionMap.readLines().find{ it.split(',')[0] == revisionTmp } + commitId = commitId ? commitId.split(',')[1] : commitId + } + + return commitId } /** @@ -529,7 +558,7 @@ class AssetManager { } boolean isLocal() { - localPath.exists() + localPathDefinedAndExists() } /** @@ -537,7 +566,7 @@ class AssetManager { * file (i.e. main.nf) or the nextflow manifest file (i.e. nextflow.config) */ boolean isRunnable() { - localPath.exists() && ( new File(localPath,DEFAULT_MAIN_FILE_NAME).exists() || new File(localPath,MANIFEST_FILE_NAME).exists() ) + localPathDefinedAndExists() && ( new File(localPath,DEFAULT_MAIN_FILE_NAME).exists() || new File(localPath,MANIFEST_FILE_NAME).exists() ) } boolean localPathDefinedAndExists() { From 0f29320e823116e0a28186689bd1436a295323fc Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 19 Jun 2024 13:38:17 +0200 Subject: [PATCH 61/91] using DEFAULT_REVISION_DIRNAME --- .../main/groovy/nextflow/cli/CmdPull.groovy | 4 +- .../groovy/nextflow/scm/AssetManager.groovy | 8 ++-- .../nextflow/scm/AssetManagerTest.groovy | 18 +++++---- .../nextflow/scm/UpdateModuleTest.groovy | 40 ++++++++++--------- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 51ee299f46..9321eb2339 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -16,6 +16,8 @@ package nextflow.cli +import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME + import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -79,7 +81,7 @@ class CmdPull extends CmdBase implements HubOptions { all.each{ proj -> def revManager = new AssetManager(proj) revManager.listRevisions().each{ rev -> - if( rev == "DEFAULT_REVISION" ) + if( rev == DEFAULT_REVISION_DIRNAME ) rev = null list << new AssetManager(proj, rev, this) } diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 7e443db1f0..aa879c3f2f 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -68,6 +68,8 @@ class AssetManager { static public final String REVISION_SUBDIR = '.nextflow/commits' + static public final String DEFAULT_REVISION_DIRNAME = 'DEFAULT_REVISION' + /** * The pipeline name. It must be in the form {@code username/repo} where 'username' * is a valid user name or organisation account, while 'repo' is the repository name @@ -233,7 +235,7 @@ class AssetManager { String commitId = revisionToCommit(revision) if( commitId ) { - this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : 'DEFAULT_REVISION') ) + this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : DEFAULT_REVISION_DIRNAME) ) validateProjectDir() } else { this.localPath = null @@ -245,7 +247,7 @@ class AssetManager { String commitId if( revisionMap ) { - String revisionTmp = revision ?: 'DEFAULT_REVISION' + String revisionTmp = revision ?: DEFAULT_REVISION_DIRNAME commitId = revisionMap.readLines().find{ it.split(',')[0] == revisionTmp } commitId = commitId ? commitId.split(',')[1] : commitId } @@ -804,7 +806,7 @@ class AssetManager { * If revision is null, default is assumed */ List getPulledRevisions() { - listRevisions().collect{ it = ( it != "DEFAULT_REVISION" ? it : getDefaultBranch() ) } + listRevisions().collect{ it = ( it != DEFAULT_REVISION_DIRNAME ? it : getDefaultBranch() ) } } RevisionInfo getCurrentRevisionAndName() { diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index d991084f40..462b75a881 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -16,6 +16,8 @@ package nextflow.scm +import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME + import spock.lang.IgnoreIf import nextflow.exception.AbortOperationException @@ -106,8 +108,8 @@ class AssetManagerTest extends Specification { def testListRevisions() { given: def folder = tempDir.getRoot() - folder.resolve('cbcrg/pipe1/.nextflow/commits/DEFAULT_REVISION').mkdirs() - folder.resolve('cbcrg/pipe2/.nextflow/commits/DEFAULT_REVISION').mkdirs() + folder.resolve('cbcrg/pipe1/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME).mkdirs() + folder.resolve('cbcrg/pipe2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME).mkdirs() folder.resolve('cbcrg/pipe2/.nextflow/commits/v2').mkdirs() folder.resolve('cbcrg/pipe3/.nextflow/commits/v3').mkdirs() @@ -116,7 +118,7 @@ class AssetManagerTest extends Specification { when: def list = manager.listRevisions('cbcrg/pipe1') then: - list == ['DEFAULT_REVISION'] + list == [DEFAULT_REVISION_DIRNAME] when: list = manager.listRevisions('cbcrg/pipe3') @@ -126,7 +128,7 @@ class AssetManagerTest extends Specification { when: list = manager.listRevisions('cbcrg/pipe2') then: - list == ['DEFAULT_REVISION', 'v2'] + list == [DEFAULT_REVISION_DIRNAME, 'v2'] } @@ -387,10 +389,10 @@ class AssetManagerTest extends Specification { } ''' def dir = tempDir.getRoot() - dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION').mkdirs() - dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION/nextflow.config').text = config - dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION/.git').mkdir() - dir.resolve('foo/bar/.nextflow/commits/DEFAULT_REVISION/.git/config').text = GIT_CONFIG_TEXT + dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME).mkdirs() + dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/nextflow.config').text = config + dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').mkdir() + dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git/config').text = GIT_CONFIG_TEXT when: def holder = new AssetManager() diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy index b7ab75b978..2e7f56839f 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy @@ -16,6 +16,8 @@ package nextflow.scm +import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME + import java.nio.file.Files import java.nio.file.Path @@ -108,16 +110,16 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_x').exists() - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/.git').exists() - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/main.nf').exists() + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_aaa').exists() - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_aaa/file1.txt').text == 'Hello' - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_aaa/file2.log').text == 'World' + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').exists() + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file1.txt').text == 'Hello' + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file2.log').text == 'World' - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_bbb').exists() - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_x/.nextflow/commits/DEFAULT_REVISION/prj_bbb/file2.log').text == 'Mondo' + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file2.log').text == 'Mondo' } @@ -146,11 +148,11 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_2').exists() - target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/.git').exists() - target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/main.nf').exists() + target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() + target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() - target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/prj_aaa').list().size()==0 - target.resolve('local/pipe_2/.nextflow/commits/DEFAULT_REVISION/prj_bbb').list().size()==0 + target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 + target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').list().size()==0 } def 'should clone selected submodules' () { @@ -179,16 +181,16 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_3').exists() - target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/.git').exists() - target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/main.nf').exists() + target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() + target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() - target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_aaa').list().size()==0 + target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 - target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_bbb').exists() - target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() + target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_ccc').exists() - target.resolve('local/pipe_3/.nextflow/commits/DEFAULT_REVISION/prj_ccc/file-x.txt').text == 'x' + target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc').exists() + target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc/file-x.txt').text == 'x' } From 93db4ee8cb189e3f9b12cc67278a36cbd5df3de4 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 19 Jun 2024 14:22:20 +0200 Subject: [PATCH 62/91] AssetManager: add checkLocalBarePath Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index aa879c3f2f..4c8e2c1004 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -186,6 +186,7 @@ class AssetManager { File localRootPath = new File(root, project) return localRootPath.exists() ? localRootPath : null } + @PackageScope AssetManager setProject(String name) { this.project = name return this @@ -234,7 +235,9 @@ class AssetManager { String commitId = revisionToCommit(revision) - if( commitId ) { + // MARCO TEST ONLY + if( true ) { + //if( commitId ) { this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : DEFAULT_REVISION_DIRNAME) ) validateProjectDir() } else { @@ -279,6 +282,35 @@ class AssetManager { } + @PackageScope + void checkLocalBarePath() { + /* + * if the bare repository of the pipeline does not exists locally pull it from the remote repo + */ + if( !bareRepo.exists() ) { + bareRepo.parentFile.mkdirs() + + final cloneURL = getGitRepositoryUrl() + log.debug "Pulling bare repo for $project -- Using remote clone url: ${cloneURL}" + + def bare = Git.cloneRepository() + if( provider.hasCredentials() ) + bare.setCredentialsProvider( provider.getGitCredentials() ) + + bare + .setBare( true ) + .setURI(cloneURL) + .setGitDir(bareRepo) + .call() + } else { + log.debug "Fetching (updating) bare repo for $project" + + Git.open(bareRepo) + .fetch() + .call() + } + } + /** * Find out the "hub provider" (i.e. the platform on which the remote repository is stored * for example: github, bitbucket, etc) and verifies that it is a known provider. @@ -666,13 +698,19 @@ class AssetManager { String download(Integer deep=null) { assert project + // make sure it contains a valid repository + checkValidRemoteRepo() + + // get local copy of bare repository + checkLocalBarePath() + // update mapping of revision to commit, and update localPath + //updateRevisionMap() + /* * if the pipeline does not exists locally pull it from the remote repo */ if( !localPath.exists() ) { localPath.parentFile.mkdirs() - // make sure it contains a valid repository - checkValidRemoteRepo() final cloneURL = getGitRepositoryUrl() log.debug "Pulling $project -- Using remote clone url: ${cloneURL}" From 71a5b2fefafd5da983f7e293c0527b8d9cdd1ae5 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 19 Jun 2024 14:23:27 +0200 Subject: [PATCH 63/91] rename checkLocalBarePath to checkBareRepo Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 4c8e2c1004..c4452e203f 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -283,7 +283,7 @@ class AssetManager { } @PackageScope - void checkLocalBarePath() { + void checkBareRepo() { /* * if the bare repository of the pipeline does not exists locally pull it from the remote repo */ @@ -702,7 +702,7 @@ class AssetManager { checkValidRemoteRepo() // get local copy of bare repository - checkLocalBarePath() + checkBareRepo() // update mapping of revision to commit, and update localPath //updateRevisionMap() From 70847e734a724e16ae09a3e3855e03c04082b8ef Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 19 Jun 2024 15:19:37 +0200 Subject: [PATCH 64/91] AssetManager: added revisionToCommitWithBareRepo, work in progress Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 82 +++++++++++++------ 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index c4452e203f..6c676fb42e 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -143,12 +143,13 @@ class AssetManager { this.revision = revision this.project = resolveName(pipelineName) + validateProjectName(this.project) this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) setupCredentials(cliOpts) - defineProjectDir(this.project, this.revision) + updateProjectDir(this.project, this.revision, revisionToCommitWithMap(this.revision)) return this } @@ -218,8 +219,17 @@ class AssetManager { } /** - * Verify the project name matcher the expected pattern, - * map revision to commit ID, + * Verify the project name matches the expected pattern + */ + @PackageScope + void validateProjectName(String projectName) { + if( !isValidProjectName(projectName)) { + throw new IllegalArgumentException("Not a valid project name: $projectName") + } + } + + /** + * Map revision to commit ID, * define the directory where the project is stored locally, * and validate it. * @@ -228,34 +238,13 @@ class AssetManager { * @return The project dir {@link File} */ @PackageScope - void defineProjectDir(String projectName, String revision) { - if( !isValidProjectName(projectName)) { - throw new IllegalArgumentException("Not a valid project name: $projectName") - } - - String commitId = revisionToCommit(revision) - + void updateProjectDir(String projectName, String revision, String commitId) { // MARCO TEST ONLY if( true ) { //if( commitId ) { this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : DEFAULT_REVISION_DIRNAME) ) validateProjectDir() - } else { - this.localPath = null - } - } - - @PackageScope - String revisionToCommit(String revision) { - String commitId - - if( revisionMap ) { - String revisionTmp = revision ?: DEFAULT_REVISION_DIRNAME - commitId = revisionMap.readLines().find{ it.split(',')[0] == revisionTmp } - commitId = commitId ? commitId.split(',')[1] : commitId } - - return commitId } /** @@ -311,6 +300,47 @@ class AssetManager { } } + @PackageScope + String revisionToCommitWithBareRepo(String revision) { + String commitId + + def rev = Git.open(bareRepo) + .getRepository() + .resolve(revision ?: Constants.HEAD) + if ( rev ) + commitId = rev.getName() + + return commitId + } + + @PackageScope + String revisionToCommitWithMap(String revision) { + String commitId + + if( revisionMap ) { + String revisionTmp = revision ?: DEFAULT_REVISION_DIRNAME + commitId = revisionMap.readLines().find{ it.split(',')[0] == revisionTmp } + commitId = commitId ? commitId.split(',')[1] : commitId + } + + return commitId + } + + @PackageScope + void updateRevisionMap() { + def a='a' + } + + @PackageScope + void updateRevisionMapAndLocalPath(String revision) { + updateRevisionMap() + + // MARCO TEST ONLY + String commitId = revisionToCommitWithMap(revision) + //String commitId = revisionToCommitWithBareRepo(revision) + updateProjectDir(this.project, revision, commitId) + } + /** * Find out the "hub provider" (i.e. the platform on which the remote repository is stored * for example: github, bitbucket, etc) and verifies that it is a known provider. @@ -704,7 +734,7 @@ class AssetManager { // get local copy of bare repository checkBareRepo() // update mapping of revision to commit, and update localPath - //updateRevisionMap() + updateRevisionMapAndLocalPath(revision) /* * if the pipeline does not exists locally pull it from the remote repo From 9c6816649615dff9b762829976f92c762314360a Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Wed, 19 Jun 2024 15:23:25 +0200 Subject: [PATCH 65/91] minor update Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 6c676fb42e..0f5514ba32 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -327,17 +327,17 @@ class AssetManager { } @PackageScope - void updateRevisionMap() { + void updateRevisionMap(String revision, String commitId) { def a='a' } @PackageScope void updateRevisionMapAndLocalPath(String revision) { - updateRevisionMap() - // MARCO TEST ONLY String commitId = revisionToCommitWithMap(revision) //String commitId = revisionToCommitWithBareRepo(revision) + + updateRevisionMap(revision, commitId) updateProjectDir(this.project, revision, commitId) } From 0a3d4a6d3619c88372ae94f488038fe1bdb8758c Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 11:44:41 +0200 Subject: [PATCH 66/91] AssetManager: updateRevisionMap ok, overall work in progress Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/cli/CmdDrop.groovy | 1 + .../main/groovy/nextflow/cli/CmdInfo.groovy | 4 +- .../groovy/nextflow/scm/AssetManager.groovy | 47 ++++++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index cac7ba78ae..1e5247bbd1 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -78,6 +78,7 @@ class CmdDrop extends CmdBase { manager.close() if( !manager.localPath.deleteDir() ) throw new AbortOperationException("Unable to delete project `${manager.getProjectWithRevision()}` -- Check access permissions for path: ${manager.localPath}") + manager.pruneRevisionMap() return } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index 124b8a7096..f0fcc6ee49 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -110,7 +110,7 @@ class CmdInfo extends CmdBase { out.println " project name: ${manager.project}" out.println " repository : ${manager.repositoryUrl}" - out.println " local path : ${manager.localRootPath?.toString()}" + out.println " local path : ${manager.localRootPath.toString()}" out.println " main script : ${manager.mainScriptName}" if( manager.homePage && manager.homePage != manager.repositoryUrl ) out.println " home page : ${manager.homePage}" @@ -147,7 +147,7 @@ class CmdInfo extends CmdBase { def result = [:] result.projectName = manager.project result.repository = manager.repositoryUrl - result.localPath = manager.localRootPath?.toString() + result.localPath = manager.localRootPath.toString() result.manifest = manager.manifest.toMap() result.revisions = manager.getBranchesAndTags(checkForUpdates) return result diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 0f5514ba32..9b73ec09dd 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -173,19 +173,16 @@ class AssetManager { */ @PackageScope File getRevisionMap() { - File revisionMap = new File(root, project + '/' + REVISION_MAP) - return revisionMap.exists() ? revisionMap : null + new File(root, project + '/' + REVISION_MAP) } @PackageScope File getRevisionSubdir( String projectName = project ) { - File revisionSubdir = new File(root, projectName + '/' + REVISION_SUBDIR) - return revisionSubdir.exists() ? revisionSubdir : null + new File(root, projectName + '/' + REVISION_SUBDIR) } File getLocalRootPath() { - File localRootPath = new File(root, project) - return localRootPath.exists() ? localRootPath : null + new File(root, project) } @PackageScope AssetManager setProject(String name) { @@ -239,7 +236,7 @@ class AssetManager { */ @PackageScope void updateProjectDir(String projectName, String revision, String commitId) { - // MARCO TEST ONLY + // PIPPO MARCO TEST ONLY if( true ) { //if( commitId ) { this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : DEFAULT_REVISION_DIRNAME) ) @@ -279,7 +276,7 @@ class AssetManager { if( !bareRepo.exists() ) { bareRepo.parentFile.mkdirs() - final cloneURL = getGitRepositoryUrl() + final cloneURL = provider.getCloneUrl() log.debug "Pulling bare repo for $project -- Using remote clone url: ${cloneURL}" def bare = Git.cloneRepository() @@ -307,7 +304,7 @@ class AssetManager { def rev = Git.open(bareRepo) .getRepository() .resolve(revision ?: Constants.HEAD) - if ( rev ) + if( rev ) commitId = rev.getName() return commitId @@ -317,7 +314,7 @@ class AssetManager { String revisionToCommitWithMap(String revision) { String commitId - if( revisionMap ) { + if( revisionMap.exists() ) { String revisionTmp = revision ?: DEFAULT_REVISION_DIRNAME commitId = revisionMap.readLines().find{ it.split(',')[0] == revisionTmp } commitId = commitId ? commitId.split(',')[1] : commitId @@ -326,16 +323,34 @@ class AssetManager { return commitId } + void pruneRevisionMap() { + updateRevisionMap(this.revision, null) + } + @PackageScope void updateRevisionMap(String revision, String commitId) { - def a='a' + String revisionTmp = revision ?: DEFAULT_REVISION_DIRNAME + if( !revisionMap.exists() && commitId != null ) { + revisionMap.parentFile.mkdirs() + revisionMap << revisionTmp + ',' + commitId + '\n' + } else { + List oldRevisionMap = revisionMap.readLines() + revisionMap.text = '' + oldRevisionMap.each{ + if( it.split(',')[0] != revisionTmp ) + revisionMap << it + '\n' + } + if( commitId != null ) + revisionMap << revisionTmp + ',' + commitId + '\n' + } } @PackageScope void updateRevisionMapAndLocalPath(String revision) { - // MARCO TEST ONLY - String commitId = revisionToCommitWithMap(revision) - //String commitId = revisionToCommitWithBareRepo(revision) + // get local copy of bare repository + checkBareRepo() + + String commitId = revisionToCommitWithBareRepo(revision) updateRevisionMap(revision, commitId) updateProjectDir(this.project, revision, commitId) @@ -688,7 +703,7 @@ class AssetManager { def result = new LinkedList() if( !root.exists() ) return result - if( !getRevisionSubdir(projectName) ) + if( !getRevisionSubdir(projectName).exists() ) return result getRevisionSubdir(projectName).eachDir { File it -> result << it.getName().toString() } @@ -731,8 +746,6 @@ class AssetManager { // make sure it contains a valid repository checkValidRemoteRepo() - // get local copy of bare repository - checkBareRepo() // update mapping of revision to commit, and update localPath updateRevisionMapAndLocalPath(revision) From 920f8aadc60df313ff80ff54c86f4ae0693a3334 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 13:54:29 +0200 Subject: [PATCH 67/91] final updateProjectDir ; fixed cmddrop Signed-off-by: Dr Marco Claudio De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy | 2 +- .../nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index 1e5247bbd1..aba75c44b6 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -70,7 +70,7 @@ class CmdDrop extends CmdBase { } dropList.each { manager -> - if( !manager.localPath.exists() ) { + if( !manager.localPathDefinedAndExists() ) { throw new AbortOperationException("No match found for: ${manager.getProjectWithRevision()}") } diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 9b73ec09dd..17bf6361ef 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -236,9 +236,7 @@ class AssetManager { */ @PackageScope void updateProjectDir(String projectName, String revision, String commitId) { - // PIPPO MARCO TEST ONLY - if( true ) { - //if( commitId ) { + if( commitId ) { this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : DEFAULT_REVISION_DIRNAME) ) validateProjectDir() } From be2b84f734bea6aff12b55cda09cb8a557ec06c2 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 15:35:28 +0200 Subject: [PATCH 68/91] in localPath, use commitId, plus related fixes in listRevisions Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/cli/CmdList.groovy | 10 +++++ .../groovy/nextflow/scm/AssetManager.groovy | 37 ++++++++++++++++--- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 953491356c..2caeb6507d 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -37,6 +37,9 @@ class CmdList extends CmdBase { @Parameter(names=['-a','-all-revisions'], description = 'For each project, also list revisions') Boolean allRevisions + @Parameter(names=['-all-commits'], description = 'For each project, also list all downloaded commits') + Boolean allCommits + @Override final String getName() { NAME } @@ -56,6 +59,13 @@ class CmdList extends CmdBase { revManager.listRevisions().each{ println(" $it") } revManager.close() } + } else if(allCommits) { + all.each{ + println(" $it") + def revManager = new AssetManager(it) + revManager.listCommits().each{ println(" $it") } + revManager.close() + } } else { all.each{ println(" $it") } } diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 17bf6361ef..6dc956910c 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -237,7 +237,7 @@ class AssetManager { @PackageScope void updateProjectDir(String projectName, String revision, String commitId) { if( commitId ) { - this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + (revision ? revision : DEFAULT_REVISION_DIRNAME) ) + this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + commitId ) validateProjectDir() } } @@ -322,13 +322,21 @@ class AssetManager { } void pruneRevisionMap() { - updateRevisionMap(this.revision, null) + if( revisionMap.exists() ) { + String commitId = revisionToCommitWithMap(this.revision) + List oldRevisionMap = revisionMap.readLines() + revisionMap.text = '' + oldRevisionMap.each{ + if( it.split(',')[1] != commitId ) + revisionMap << it + '\n' + } + } } @PackageScope void updateRevisionMap(String revision, String commitId) { String revisionTmp = revision ?: DEFAULT_REVISION_DIRNAME - if( !revisionMap.exists() && commitId != null ) { + if( !revisionMap.exists() ) { revisionMap.parentFile.mkdirs() revisionMap << revisionTmp + ',' + commitId + '\n' } else { @@ -338,8 +346,7 @@ class AssetManager { if( it.split(',')[0] != revisionTmp ) revisionMap << it + '\n' } - if( commitId != null ) - revisionMap << revisionTmp + ',' + commitId + '\n' + revisionMap << revisionTmp + ',' + commitId + '\n' } } @@ -698,6 +705,23 @@ class AssetManager { List listRevisions( String projectName = this.project ) { log.debug "Listing revisions for project: $projectName" + def result = new LinkedList() + if( !root.exists() ) + return result + if( !revisionMap.exists() ) + return result + + revisionMap.eachLine{ it -> result << it.split(',')[0] } + + return result + } + + /** + * @return The list of downloaded bare commits for a given project name + */ + List listCommits( String projectName = this.project ) { + log.debug "Listing all commits for project: $projectName" + def result = new LinkedList() if( !root.exists() ) return result @@ -753,6 +777,7 @@ class AssetManager { if( !localPath.exists() ) { localPath.parentFile.mkdirs() + //final cloneURL = bareRepo.toString() final cloneURL = getGitRepositoryUrl() log.debug "Pulling $project -- Using remote clone url: ${cloneURL}" @@ -883,6 +908,8 @@ class AssetManager { * @return The names of all locally pulled revisions for a given project * * If revision is null, default is assumed + * Should only be used for the purpose of printing project information + * */ List getPulledRevisions() { listRevisions().collect{ it = ( it != DEFAULT_REVISION_DIRNAME ? it : getDefaultBranch() ) } From 8da7bea707c99a07dfd835c8af51fb0901501aff Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 15:57:46 +0200 Subject: [PATCH 69/91] list command can also show commits Signed-off-by: Dr Marco Claudio De La Pierre --- docs/cli.md | 3 +++ .../main/groovy/nextflow/cli/CmdList.groovy | 24 +++++++++++++++++-- .../groovy/nextflow/scm/AssetManager.groovy | 17 +++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index 195b631692..ddfe83439d 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -890,6 +890,9 @@ The `list` commands prints a list of the projects which are already downloaded i `-a, -all-revisions` : For each project, also list revisions. +`-d` +: Show commit information for revisions (in conjunction with `-a`)). + `-h, -help` : Print the command usage. diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 2caeb6507d..cd62fd8b4c 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -40,6 +40,12 @@ class CmdList extends CmdBase { @Parameter(names=['-all-commits'], description = 'For each project, also list all downloaded commits') Boolean allCommits + @Parameter(names='-d',description = 'Show commit information for revisions', arity = 0) + boolean detailed + + @Parameter(names='-dd', hidden = true, arity = 0) + boolean moreDetailed + @Override final String getName() { NAME } @@ -52,14 +58,28 @@ class CmdList extends CmdBase { return } - if (allRevisions) { + if( moreDetailed ) + detailed = true + if( detailed && allRevisions ) { + all.each{ + println(" $it") + def revManager = new AssetManager(it) + revManager.listRevisionsAndCommits().each{ k,v -> + def value = v + if( !moreDetailed ) + value = v.substring(0,10) + println(" $value $k") } + revManager.close() + } + } + else if( allRevisions ) { all.each{ println(" $it") def revManager = new AssetManager(it) revManager.listRevisions().each{ println(" $it") } revManager.close() } - } else if(allCommits) { + } else if( allCommits ) { all.each{ println(" $it") def revManager = new AssetManager(it) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 6dc956910c..fe7ccc5cd1 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -716,6 +716,23 @@ class AssetManager { return result } + /** + * @return The map of available revisions and corresponding commits for a given project name + */ + Map listRevisionsAndCommits( String projectName = this.project ) { + log.debug "Listing revisions for project: $projectName" + + def result = new LinkedHashMap() + if( !root.exists() ) + return result + if( !revisionMap.exists() ) + return result + + revisionMap.eachLine{ it -> result[ it.split(',')[0] ] = it.split(',')[1] } + + return result + } + /** * @return The list of downloaded bare commits for a given project name */ From d7c2f30a527dc41043f1516f325ca2ac6bd986f6 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 15:59:56 +0200 Subject: [PATCH 70/91] updated docs/sharing.md commit in localpath Signed-off-by: Dr Marco Claudio De La Pierre --- docs/sharing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sharing.md b/docs/sharing.md index 82fc40e664..91308229af 100644 --- a/docs/sharing.md +++ b/docs/sharing.md @@ -61,7 +61,7 @@ It will execute two different project revisions corresponding to the Git tag/bra :::{versionadded} 24.XX.0-edge ::: -Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. Each downloaded revision is stored in a subdirecrory path of the local project path: `$NXF_ASSETS///.nextflow/commits/` (for the default branch, `` is set to `DEFAULT_REVISION`). +Nextflow downloads and locally maintains each explicitly requested Git branch, tag or commit ID in a separate directory path, thus enabling to run multiple revisions of the same pipeline at the same time. Each downloaded revision is stored in a subdirecrory path of the local project path: `$NXF_ASSETS///.nextflow/commits/`. :::{warning} If you really care about reproducibility of your pipelines, consider explicitly referring to them by tag or commit ID, rather than my branch. This is because the same branch will point to different underlying commits over time, as pipeline development goes on. From f27b1155ea2570a98184cee570bf12985baf23d1 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 16:29:59 +0200 Subject: [PATCH 71/91] remove use of getPulledRevisions Signed-off-by: Dr Marco Claudio De La Pierre --- .../main/groovy/nextflow/cli/CmdInfo.groovy | 2 +- .../groovy/nextflow/scm/AssetManager.groovy | 24 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index f0fcc6ee49..dddeb72bed 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -79,7 +79,7 @@ class CmdInfo extends CmdBase { if( !manager.isLocal() ) { // if default branch not found locally, use first one from list of local pulls if ( manager.listRevisions() ) { - manager = new AssetManager(args[0], manager.getPulledRevisions()[0]) + manager = new AssetManager(args[0], manager.listRevisions()[0]) if( !manager.isLocal() ) throw new AbortOperationException("Unknown project `${args[0]}`") } diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index fe7ccc5cd1..d21b36ac7b 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -716,6 +716,15 @@ class AssetManager { return result } + /** + * uses getDefaultBranch() + * only for usage within service methods getRevisions() and getBranchesAndTags() + */ + @PackageScope + List listRevisionsToCompareInfo() { + listRevisions().collect{ it = ( it != DEFAULT_REVISION_DIRNAME ? it : getDefaultBranch() ) } + } + /** * @return The map of available revisions and corresponding commits for a given project name */ @@ -921,17 +930,6 @@ class AssetManager { names.get( head.objectId ) ?: head.objectId.name() } - /** - * @return The names of all locally pulled revisions for a given project - * - * If revision is null, default is assumed - * Should only be used for the purpose of printing project information - * - */ - List getPulledRevisions() { - listRevisions().collect{ it = ( it != DEFAULT_REVISION_DIRNAME ? it : getDefaultBranch() ) } - } - RevisionInfo getCurrentRevisionAndName() { Ref head = git.getRepository().findRef(Constants.HEAD); if( !head ) @@ -974,7 +972,7 @@ class AssetManager { def current = getCurrentRevision() def master = getDefaultBranch() - def pulled = getPulledRevisions() + def pulled = listRevisionsToCompareInfo() List branches = getBranchList() .findAll { it.name.startsWith('refs/heads/') || it.name.startsWith('refs/remotes/origin/') } @@ -1021,7 +1019,7 @@ class AssetManager { .each { Ref it -> tags << refToMap(it,remote) } result.master = master // master branch name - result.pulled = getPulledRevisions() // list of pulled revisions + result.pulled = listRevisionsToCompareInfo() // list of pulled revisions result.branches = branches // collection of branches result.tags = tags // collect of tags return result From 3d45ef3c60fe4e5a5408fc4dbffc31c0f39b6860 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 16:30:32 +0200 Subject: [PATCH 72/91] fix for CmdDrop: use of DEFAULT_REVISION_DIRNAME --- .../src/main/groovy/nextflow/cli/CmdDrop.groovy | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index aba75c44b6..e765800ae1 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -16,6 +16,8 @@ package nextflow.cli +import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME + import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -57,9 +59,11 @@ class CmdDrop extends CmdBase { List dropList = [] if ( allRevisions ) { - def referenceManager = new AssetManager(args[0]) - referenceManager.listRevisions().each { - dropList << new AssetManager(args[0], it) + def revManager = new AssetManager(args[0]) + revManager.listRevisions().each { rev -> + if( rev == DEFAULT_REVISION_DIRNAME ) + rev = null + dropList << new AssetManager(args[0], rev) } } else { dropList << new AssetManager(args[0], revision) @@ -86,8 +90,8 @@ class CmdDrop extends CmdBase { } if ( allRevisions ) { - def referenceManager = new AssetManager(args[0]) - referenceManager.localRootPath.deleteDir() + def revManager = new AssetManager(args[0]) + revManager.localRootPath.deleteDir() } } } From 06a22299e4ae00338909c79c70fd5179955ccb4d Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 16:30:53 +0200 Subject: [PATCH 73/91] CmdList: better output for default revision --- .../src/main/groovy/nextflow/cli/CmdList.groovy | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index cd62fd8b4c..3a9e7caf8e 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -16,6 +16,8 @@ package nextflow.cli +import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME + import com.beust.jcommander.Parameter import com.beust.jcommander.Parameters import groovy.transform.CompileStatic @@ -65,10 +67,11 @@ class CmdList extends CmdBase { println(" $it") def revManager = new AssetManager(it) revManager.listRevisionsAndCommits().each{ k,v -> - def value = v + if( k == DEFAULT_REVISION_DIRNAME ) + k = '(default)' if( !moreDetailed ) - value = v.substring(0,10) - println(" $value $k") } + v = v.substring(0,10) + println(" $v $k") } revManager.close() } } @@ -76,7 +79,11 @@ class CmdList extends CmdBase { all.each{ println(" $it") def revManager = new AssetManager(it) - revManager.listRevisions().each{ println(" $it") } + revManager.listRevisions().each{ + if( it == DEFAULT_REVISION_DIRNAME ) + it = '(default)' + println(" $it") + } revManager.close() } } else if( allCommits ) { From a77bd5972fdee064d09a55eba98cf52a168ca414 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Thu, 20 Jun 2024 17:05:44 +0200 Subject: [PATCH 74/91] AssetManager, CmdDrop : some method signature updates --- .../src/main/groovy/nextflow/cli/CmdDrop.groovy | 2 +- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index e765800ae1..5cbe23663e 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -82,7 +82,7 @@ class CmdDrop extends CmdBase { manager.close() if( !manager.localPath.deleteDir() ) throw new AbortOperationException("Unable to delete project `${manager.getProjectWithRevision()}` -- Check access permissions for path: ${manager.localPath}") - manager.pruneRevisionMap() + manager.pruneRevisionMap(manager.revision) return } diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index d21b36ac7b..c016fb9f4a 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -149,7 +149,7 @@ class AssetManager { this.provider = createHubProvider(hub) setupCredentials(cliOpts) - updateProjectDir(this.project, this.revision, revisionToCommitWithMap(this.revision)) + updateProjectDir(this.project, revisionToCommitWithMap(this.revision)) return this } @@ -235,7 +235,7 @@ class AssetManager { * @return The project dir {@link File} */ @PackageScope - void updateProjectDir(String projectName, String revision, String commitId) { + void updateProjectDir(String projectName, String commitId) { if( commitId ) { this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + commitId ) validateProjectDir() @@ -321,9 +321,9 @@ class AssetManager { return commitId } - void pruneRevisionMap() { + void pruneRevisionMap(String revision) { if( revisionMap.exists() ) { - String commitId = revisionToCommitWithMap(this.revision) + String commitId = revisionToCommitWithMap(revision) List oldRevisionMap = revisionMap.readLines() revisionMap.text = '' oldRevisionMap.each{ @@ -358,7 +358,7 @@ class AssetManager { String commitId = revisionToCommitWithBareRepo(revision) updateRevisionMap(revision, commitId) - updateProjectDir(this.project, revision, commitId) + updateProjectDir(this.project, commitId) } /** From 3b9978b5b59b4cf7370e66e24a137e4a2119f132 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 12:15:49 +0200 Subject: [PATCH 75/91] AssetManager.download(): using bareRepo for pulling, plus related changes Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManager.groovy | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index c016fb9f4a..45adf948a3 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -92,6 +92,8 @@ class AssetManager { private Git _git + private Git _bareGit + private String mainScript private RepositoryProvider provider @@ -148,6 +150,7 @@ class AssetManager { this.hub = checkHubProvider(cliOpts) this.provider = createHubProvider(hub) setupCredentials(cliOpts) + validateProjectBareDir() updateProjectDir(this.project, revisionToCommitWithMap(this.revision)) @@ -156,7 +159,7 @@ class AssetManager { @PackageScope File getLocalGitConfig() { - localPath ? new File(localPath,'.git/config') : null + bareRepo.exists() ? new File(bareRepo,'config') : null } @PackageScope @@ -238,7 +241,6 @@ class AssetManager { void updateProjectDir(String projectName, String commitId) { if( commitId ) { this.localPath = new File( root, projectName + '/' + REVISION_SUBDIR + '/' + commitId ) - validateProjectDir() } } @@ -247,21 +249,19 @@ class AssetManager { * line option or implicitly by entering a repository URL, matches with clone URL of a project already cloned (downloaded). */ @PackageScope - void validateProjectDir() { - assert localPath - - if( !localPath.exists() ) { + void validateProjectBareDir() { + if( !bareRepo.exists() ) { return } // if project dir exists it must contain the Git config file final configProvider = guessHubProviderFromGitConfig(true) if( !configProvider ) - throw new IllegalStateException("Cannot find a provider config for repository at path: $localPath") + throw new IllegalStateException("Cannot find a provider config for repository at path: $bareRepo") // checks that the selected hub matches with the one defined in the git config file if( hub != configProvider ) { - throw new AbortOperationException("A project with name: `$localPath` has already been downloaded from a different provider: `$configProvider`") + throw new AbortOperationException("A project with name: `$bareRepo` has already been downloaded from a different provider: `$configProvider`") } } @@ -274,7 +274,7 @@ class AssetManager { if( !bareRepo.exists() ) { bareRepo.parentFile.mkdirs() - final cloneURL = provider.getCloneUrl() + final cloneURL = getGitRepositoryUrl() log.debug "Pulling bare repo for $project -- Using remote clone url: ${cloneURL}" def bare = Git.cloneRepository() @@ -532,11 +532,6 @@ class AssetManager { @Memoized String getGitRepositoryUrl() { - - if( localPathDefinedAndExists() ) { - return localPath.toURI().toString() - } - provider.getCloneUrl() } @@ -678,6 +673,10 @@ class AssetManager { _git.close() _git = null } + if( _bareGit ) { + _bareGit.close() + _bareGit = null + } } /** @@ -783,6 +782,13 @@ class AssetManager { return _git } + protected Git getBareGit() { + if( !_bareGit ) { + _bareGit = Git.open(bareRepo) + } + return _bareGit + } + /** * Download a pipeline from a remote Github repository * @@ -803,8 +809,7 @@ class AssetManager { if( !localPath.exists() ) { localPath.parentFile.mkdirs() - //final cloneURL = bareRepo.toString() - final cloneURL = getGitRepositoryUrl() + final cloneURL = bareRepo.toString() log.debug "Pulling $project -- Using remote clone url: ${cloneURL}" // clone it @@ -828,7 +833,7 @@ class AssetManager { } // return status message - return "downloaded from ${cloneURL}" + return "downloaded from ${getGitRepositoryUrl()}" } log.debug "Pulling $project -- Using local path: $localPath" @@ -1007,13 +1012,13 @@ class AssetManager { final branches = [] final tags = [] - Map remote = checkForUpdates ? git.lsRemote().callAsMap() : null + Map remote = checkForUpdates ? bareGit.lsRemote().callAsMap() : null getBranchList() .findAll { it.name.startsWith('refs/heads/') || it.name.startsWith('refs/remotes/origin/') } .unique { shortenRefName(it.name) } .each { Ref it -> branches << refToMap(it,remote) } - remote = checkForUpdates ? git.lsRemote().setTags(true).callAsMap() : null + remote = checkForUpdates ? bareGit.lsRemote().setTags(true).callAsMap() : null getTagList() .findAll { it.name.startsWith('refs/tags/') } .each { Ref it -> tags << refToMap(it,remote) } @@ -1104,14 +1109,14 @@ class AssetManager { @Deprecated List getUpdates(int level) { - def remote = git.lsRemote().callAsMap() + def remote = bareGit.lsRemote().callAsMap() List branches = getBranchList() .findAll { it.name.startsWith('refs/heads/') || it.name.startsWith('refs/remotes/origin/') } .unique { shortenRefName(it.name) } .findAll { Ref ref -> hasRemoteChange(ref,remote) } .collect { Ref ref -> formatUpdate(remote.get(ref.name),level) } - remote = git.lsRemote().setTags(true).callAsMap() + remote = bareGit.lsRemote().setTags(true).callAsMap() List tags = getTagList() .findAll { it.name.startsWith('refs/tags/') } .findAll { Ref ref -> hasRemoteChange(ref,remote) } @@ -1194,7 +1199,7 @@ class AssetManager { protected String getRemoteCommitId(RevisionInfo rev) { final tag = rev.type == RevisionInfo.Type.TAG - final cmd = git.lsRemote().setTags(tag) + final cmd = bareGit.lsRemote().setTags(tag) if( provider.hasCredentials() ) cmd.setCredentialsProvider( provider.getGitCredentials() ) final list = cmd.call() @@ -1234,7 +1239,7 @@ class AssetManager { } protected String getGitConfigRemoteUrl() { - if( !localPathDefinedAndExists() ) { + if( !bareRepo.exists() ) { return null } @@ -1244,10 +1249,8 @@ class AssetManager { } final iniFile = new IniFile().load(gitConfig) - final branch = manifest.getDefaultBranch() - final remote = iniFile.getString("branch \"${branch}\"", "remote", "origin") - final url = iniFile.getString("remote \"${remote}\"", "url") - log.debug "Git config: $gitConfig; branch: $branch; remote: $remote; url: $url" + final url = iniFile.getString("remote \"origin\"", "url") + log.debug "Git config: $gitConfig; url: $url" return url } @@ -1277,10 +1280,9 @@ class AssetManager { // find the repository remote URL from the git project config file final domain = getGitConfigRemoteDomain() if( !domain && failFast ) { - assert localPath def message = (localGitConfig.exists() ? "Can't find git repository remote host -- Check config file at path: $localGitConfig" - : "Can't find git repository config file -- Repository may be corrupted: $localPath" ) + : "Can't find git repository config file -- Repository may be corrupted: $bareRepo" ) throw new AbortOperationException(message) } From 20e6edc4b5b47b18827ae835a07158e7d9421e69 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 12:22:20 +0200 Subject: [PATCH 76/91] CmdList and CmdPull: no need for manager.close() Signed-off-by: Dr Marco Claudio De La Pierre --- modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy | 3 --- modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy | 1 - 2 files changed, 4 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy index 3a9e7caf8e..261ff10698 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdList.groovy @@ -72,7 +72,6 @@ class CmdList extends CmdBase { if( !moreDetailed ) v = v.substring(0,10) println(" $v $k") } - revManager.close() } } else if( allRevisions ) { @@ -84,14 +83,12 @@ class CmdList extends CmdBase { it = '(default)' println(" $it") } - revManager.close() } } else if( allCommits ) { all.each{ println(" $it") def revManager = new AssetManager(it) revManager.listCommits().each{ println(" $it") } - revManager.close() } } else { all.each{ println(" $it") } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 9321eb2339..e13133f47b 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -85,7 +85,6 @@ class CmdPull extends CmdBase implements HubOptions { rev = null list << new AssetManager(proj, rev, this) } - revManager.close() } } else { args.toList().each { From 2199974b1a9fb02c4f359da31993c4d8f4da6009 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 15:22:41 +0200 Subject: [PATCH 77/91] AssetManagerTest: updated list tests Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 462b75a881..f718f4902c 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -17,6 +17,8 @@ package nextflow.scm import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME +import static nextflow.scm.AssetManager.REVISION_MAP +import static nextflow.scm.AssetManager.REVISION_SUBDIR import spock.lang.IgnoreIf @@ -107,28 +109,56 @@ class AssetManagerTest extends Specification { def testListRevisions() { given: + def revisionMap1 = + """branch1,12345 +branch2,67890""" + def revisionMap2 = + """branchA,abcde +branchB,fghij""" + def folder = tempDir.getRoot() - folder.resolve('cbcrg/pipe1/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME).mkdirs() - folder.resolve('cbcrg/pipe2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME).mkdirs() - folder.resolve('cbcrg/pipe2/.nextflow/commits/v2').mkdirs() - folder.resolve('cbcrg/pipe3/.nextflow/commits/v3').mkdirs() + folder.resolve('cbcrg/pipe1/.nextflow/').mkdirs() + folder.resolve('cbcrg/pipe2/.nextflow/').mkdirs() + folder.resolve('cbcrg/pipe1/' + REVISION_MAP).text = revisionMap1 + folder.resolve('cbcrg/pipe2/' + REVISION_MAP).text = revisionMap2 - def manager = new AssetManager() + when: + def manager = new AssetManager('cbcrg/pipe1') + def list = manager.listRevisions() + def dict = manager.listRevisionsAndCommits() + then: + list == ['branch1','branch2'] + dict == Map.of('branch1','12345','branch2','67890') + //dict == [branch1:'12345',branch2:'67890'] when: - def list = manager.listRevisions('cbcrg/pipe1') + manager = new AssetManager('cbcrg/pipe2') + list = manager.listRevisions() + dict = manager.listRevisionsAndCommits() then: - list == [DEFAULT_REVISION_DIRNAME] + list == ['branchA', 'branchB'] + dict == Map.of('branchA','abcde','branchB','fghij') + } + + def testListCommits() { + given: + def folder = tempDir.getRoot() + folder.resolve('cbcrg/pipe1/' + REVISION_SUBDIR + '/12345').mkdirs() + folder.resolve('cbcrg/pipe1/' + REVISION_SUBDIR + '/67890').mkdirs() + folder.resolve('cbcrg/pipe2/' + REVISION_SUBDIR + '/abcde').mkdirs() + folder.resolve('cbcrg/pipe2/' + REVISION_SUBDIR + '/fghij').mkdirs() when: - list = manager.listRevisions('cbcrg/pipe3') + def manager = new AssetManager('cbcrg/pipe1') + def list = manager.listCommits() then: - list == ['v3'] + list.sort() == ['12345','67890'] when: - list = manager.listRevisions('cbcrg/pipe2') + manager = new AssetManager('cbcrg/pipe2') + list = manager.listCommits() then: - list == [DEFAULT_REVISION_DIRNAME, 'v2'] + list.sort() == ['abcde','fghij'] } From 36dab4d29a5f0c36d02abd93e45cabb6ec0373a5 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 15:39:02 +0200 Subject: [PATCH 78/91] AssetManagerTest: fixed manifest test 1 Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index f718f4902c..c45e79bbee 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -16,6 +16,7 @@ package nextflow.scm +import static nextflow.scm.AssetManager.BARE_REPO import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME import static nextflow.scm.AssetManager.REVISION_MAP import static nextflow.scm.AssetManager.REVISION_SUBDIR @@ -248,7 +249,7 @@ branchB,fghij""" when: manager.download() then: - folder.resolve('nextflow-io/hello/.nextflow/commits/v1.2/.git').isDirectory() + folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/v1.2/.git').isDirectory() when: manager.download() @@ -268,7 +269,7 @@ branchB,fghij""" when: manager.download() then: - folder.resolve('nextflow-io/hello/.nextflow/commits/6b9515aba6c7efc6a9b3f273ce116fc0c224bf68/.git').isDirectory() + folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/6b9515aba6c7efc6a9b3f273ce116fc0c224bf68/.git').isDirectory() when: def result = manager.download() @@ -291,7 +292,7 @@ branchB,fghij""" when: manager.download() then: - folder.resolve('nextflow-io/hello/.nextflow/commits/mybranch/.git').isDirectory() + folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/mybranch/.git').isDirectory() when: def result = manager.download() @@ -419,14 +420,15 @@ branchB,fghij""" } ''' def dir = tempDir.getRoot() - dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME).mkdirs() - dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/nextflow.config').text = config - dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').mkdir() - dir.resolve('foo/bar/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git/config').text = GIT_CONFIG_TEXT + dir.resolve('foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME).mkdirs() + dir.resolve('foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/nextflow.config').text = config + dir.resolve('foo/bar/' + BARE_REPO).mkdirs() + dir.resolve('foo/bar/' + BARE_REPO + '/config').text = GIT_CONFIG_TEXT when: def holder = new AssetManager() holder.build('foo/bar') + holder.localPath = new File(dir.toString() + '/foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME) then: holder.getMainScriptName() == 'hello.nf' holder.manifest.getDefaultBranch() == 'super-stuff' @@ -594,9 +596,9 @@ branchB,fghij""" when: manager.download() then: - folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/dev/.git').isDirectory() + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/dev/.git').isDirectory() and: - folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/dev/workflow.nf').text == "println 'Hello'\n" + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/dev/workflow.nf').text == "println 'Hello'\n" } @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) @@ -623,9 +625,9 @@ branchB,fghij""" when: manager.download() then: - folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/v0.1/.git').isDirectory() + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/v0.1/.git').isDirectory() and: - folder.resolve('nextflow-io/nf-test-branch/.nextflow/commits/v0.1/workflow.nf').text == "println 'Hello'\n" + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/v0.1/workflow.nf').text == "println 'Hello'\n" } } From 2375bda22e293006453c14bed1745653a3ce9bc5 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 16:01:39 +0200 Subject: [PATCH 79/91] AssetManagerTest: fixed all executed tests Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index c45e79bbee..26f9dfaaeb 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -428,7 +428,7 @@ branchB,fghij""" when: def holder = new AssetManager() holder.build('foo/bar') - holder.localPath = new File(dir.toString() + '/foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME) + holder.setLocalPath(new File(dir.toString() + '/foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME)) then: holder.getMainScriptName() == 'hello.nf' holder.manifest.getDefaultBranch() == 'super-stuff' @@ -444,12 +444,10 @@ branchB,fghij""" def dir = tempDir.getRoot() dir.resolve('foo/bar').mkdirs() dir.resolve('foo/bar/nextflow.config').text = 'empty: 1' - dir.resolve('foo/bar/.git').mkdir() - dir.resolve('foo/bar/.git/config').text = GIT_CONFIG_TEXT when: def holder = new AssetManager() - holder.build('foo/bar') + holder.build('foo/bar').setLocalPath(new File(dir.toString() + '/foo/bar')) then: holder.getMainScriptName() == 'main.nf' @@ -463,11 +461,11 @@ branchB,fghij""" given: def dir = tempDir.root - dir.resolve('.git').mkdir() - dir.resolve('.git/config').text = GIT_CONFIG_LONG + dir.resolve('foo/bar/' + BARE_REPO).mkdirs() + dir.resolve('foo/bar/' + BARE_REPO + '/config').text = GIT_CONFIG_LONG when: - def manager = new AssetManager().setLocalPath(dir.toFile()) + def manager = new AssetManager().build('foo/bar') then: manager.getGitConfigRemoteUrl() == 'git@github.com:nextflow-io/nextflow.git' @@ -477,11 +475,11 @@ branchB,fghij""" given: def dir = tempDir.root - dir.resolve('.git').mkdir() - dir.resolve('.git/config').text = GIT_CONFIG_LONG + dir.resolve('foo/bar/' + BARE_REPO).mkdirs() + dir.resolve('foo/bar/' + BARE_REPO + '/config').text = GIT_CONFIG_LONG when: - def manager = new AssetManager().setLocalPath(dir.toFile()) + def manager = new AssetManager().build('foo/bar') then: manager.getGitConfigRemoteDomain() == 'github.com' @@ -502,9 +500,6 @@ branchB,fghij""" def commit = repo.commit().setSign(false).setAll(true).setMessage('First commit').call() repo.close() - // append fake remote data - dir.resolve('.git/config').text = GIT_CONFIG_TEXT - when: def p = Mock(RepositoryProvider) { getRepositoryUrl() >> 'https://github.com/nextflow-io/nextflow' } and: From ae835e8241d15cd214cef5f5a34db706189ed351 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 16:28:31 +0200 Subject: [PATCH 80/91] CmdPullTest fixed Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/test/groovy/nextflow/cli/CmdPullTest.groovy | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/cli/CmdPullTest.groovy b/modules/nextflow/src/test/groovy/nextflow/cli/CmdPullTest.groovy index de3fea6853..cca1e08a1e 100644 --- a/modules/nextflow/src/test/groovy/nextflow/cli/CmdPullTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/cli/CmdPullTest.groovy @@ -16,6 +16,8 @@ package nextflow.cli +import static nextflow.scm.AssetManager.REVISION_SUBDIR + import nextflow.plugin.Plugins import spock.lang.IgnoreIf @@ -40,13 +42,13 @@ class CmdPullTest extends Specification { given: def accessToken = System.getenv('NXF_GITHUB_ACCESS_TOKEN') def dir = Files.createTempDirectory('test') - def cmd = new CmdPull(args: ['nextflow-io/hello'], root: dir.toFile(), hubUser: accessToken) + def cmd = new CmdPull(args: ['nextflow-io/hello'], root: dir.toFile(), revision: '7588c46ffefb4e3c06d4ab32c745c4d5e56cdad8', hubUser: accessToken) when: cmd.run() then: - dir.resolve('nextflow-io/hello/.git').exists() - dir.resolve('nextflow-io/hello/README.md').exists() + dir.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/' + '7588c46ffefb4e3c06d4ab32c745c4d5e56cdad8' + '/.git').exists() + dir.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/' + '7588c46ffefb4e3c06d4ab32c745c4d5e56cdad8' + '/README.md').exists() cleanup: dir?.deleteDir() From 6769307c3f144f999d4ce108dd6c0a508bbd758e Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 16:53:35 +0200 Subject: [PATCH 81/91] AssetManagerTest: fixed tests that need github token Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 26f9dfaaeb..c824864318 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -221,14 +221,14 @@ branchB,fghij""" given: def folder = tempDir.getRoot() - String revision = null + String revision = '7588c46ffefb4e3c06d4ab32c745c4d5e56cdad8' // easier to fix commit for a generic test def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) when: manager.download() then: - folder.resolve('nextflow-io/hello/.git').isDirectory() + folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/' + '7588c46ffefb4e3c06d4ab32c745c4d5e56cdad8' + '/.git').isDirectory() when: def result = manager.download() @@ -245,11 +245,12 @@ branchB,fghij""" def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') def manager = new AssetManager().build('nextflow-io/hello', "v1.2", [providers: [github: [auth: token]]]) + // tag v1.2 -> commit 1b420d060d3fad67027154ac48e3bdea06f058da when: manager.download() then: - folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/v1.2/.git').isDirectory() + folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/' + '1b420d060d3fad67027154ac48e3bdea06f058da' + '/.git').isDirectory() when: manager.download() @@ -269,7 +270,7 @@ branchB,fghij""" when: manager.download() then: - folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/6b9515aba6c7efc6a9b3f273ce116fc0c224bf68/.git').isDirectory() + folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/' + '6b9515aba6c7efc6a9b3f273ce116fc0c224bf68' + '/.git').isDirectory() when: def result = manager.download() @@ -288,11 +289,12 @@ branchB,fghij""" def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') def manager = new AssetManager().build('nextflow-io/hello', "mybranch", [providers: [github: [auth: token]]]) + // as of Jun 2024, branch "mybranch" -> commit "1c3e9e7404127514d69369cd87f8036830f5cf64" when: manager.download() then: - folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/mybranch/.git').isDirectory() + folder.resolve('nextflow-io/hello/' + REVISION_SUBDIR + '/' + '1c3e9e7404127514d69369cd87f8036830f5cf64' + '/.git').isDirectory() when: def result = manager.download() @@ -587,13 +589,14 @@ branchB,fghij""" def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') def manager = new AssetManager().build('nextflow-io/nf-test-branch', "dev", [providers: [github: [auth: token]]]) + // as of June 2024, branch "dev" -> commit "6f882561d589365c3950d170df8445e3c0dc8028" when: manager.download() then: - folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/dev/.git').isDirectory() + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/' + '6f882561d589365c3950d170df8445e3c0dc8028' + '/.git').isDirectory() and: - folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/dev/workflow.nf').text == "println 'Hello'\n" + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/' + '6f882561d589365c3950d170df8445e3c0dc8028' + '/workflow.nf').text == "println 'Hello'\n" } @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) @@ -616,13 +619,14 @@ branchB,fghij""" def folder = tempDir.getRoot() def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') def manager = new AssetManager().build('nextflow-io/nf-test-branch', "v0.1", [providers: [github: [auth: token]]]) + // tag "v0.1" -> commit "6f882561d589365c3950d170df8445e3c0dc8028" when: manager.download() then: - folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/v0.1/.git').isDirectory() + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/' + '6f882561d589365c3950d170df8445e3c0dc8028' + '/.git').isDirectory() and: - folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/v0.1/workflow.nf').text == "println 'Hello'\n" + folder.resolve('nextflow-io/nf-test-branch/' + REVISION_SUBDIR + '/' + '6f882561d589365c3950d170df8445e3c0dc8028' + '/workflow.nf').text == "println 'Hello'\n" } } From 2cf9942bede19709bb63f011666ce6b8c88ba022 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Mon, 24 Jun 2024 17:02:31 +0200 Subject: [PATCH 82/91] AssetManagerTest: add test for checkBareRepo Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/nextflow/scm/AssetManagerTest.groovy | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index c824864318..7375b5807d 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -216,6 +216,23 @@ branchB,fghij""" } + @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) + def testCloneBareRepo() { + + given: + def folder = tempDir.getRoot() + String revision = null + def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') + def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) + + when: + manager.checkBareRepo() + then: + folder.resolve('nextflow-io/hello/' + BARE_REPO).isDirectory() + folder.resolve('nextflow-io/hello/' + BARE_REPO + '/config').exists() + } + + @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) def testPull() { From 0c140dedf5361a87b4ee803b40d71e82ca926e95 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 14:31:15 +0200 Subject: [PATCH 83/91] AssetManagerTest: added various tests for revToCommit methods Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 7375b5807d..82ee937cca 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -110,12 +110,8 @@ class AssetManagerTest extends Specification { def testListRevisions() { given: - def revisionMap1 = - """branch1,12345 -branch2,67890""" - def revisionMap2 = - """branchA,abcde -branchB,fghij""" + String revisionMap1 = '''branch1,12345\nbranch2,67890''' + String revisionMap2 = '''branchA,abcde\nbranchB,fghij''' def folder = tempDir.getRoot() folder.resolve('cbcrg/pipe1/.nextflow/').mkdirs() @@ -216,6 +212,38 @@ branchB,fghij""" } + def testUpdateRevisionMap() { + + given: + def folder = tempDir.getRoot() + String revision = null + def manager = new AssetManager().build('nextflow-io/hello', revision) + String revisionMap1 = '''v1.2,1b420d060d3fad67027154ac48e3bdea06f058da\n''' + + when: + manager.updateRevisionMap('v1.2','1b420d060d3fad67027154ac48e3bdea06f058da') + then: + folder.resolve('nextflow-io/hello/' + REVISION_MAP).exists() + folder.resolve('nextflow-io/hello/' + REVISION_MAP).text == revisionMap1 + } + + + def testRevisionToCommitWithMap() { + + given: + def folder = tempDir.getRoot() + String revision = null + def manager = new AssetManager().build('nextflow-io/hello', revision) + String revisionMap1 = '''v1.2,1b420d060d3fad67027154ac48e3bdea06f058da\n''' + + when: + folder.resolve('nextflow-io/hello/.nextflow').mkdirs() + folder.resolve('nextflow-io/hello/' + REVISION_MAP).text = revisionMap1 + then: + manager.revisionToCommitWithMap('v1.2') == '1b420d060d3fad67027154ac48e3bdea06f058da' + } + + @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) def testCloneBareRepo() { @@ -232,6 +260,21 @@ branchB,fghij""" folder.resolve('nextflow-io/hello/' + BARE_REPO + '/config').exists() } + @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) + def testRevisionToCommitWithBareRepo() { + + given: + def folder = tempDir.getRoot() + String revision = null + def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') + def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) + + when: + manager.checkBareRepo() + then: + manager.revisionToCommitWithBareRepo('v1.2') == '1b420d060d3fad67027154ac48e3bdea06f058da' + } + @Requires({System.getenv('NXF_GITHUB_ACCESS_TOKEN')}) def testPull() { From 923e200560d6e5551a00b8473a43a9a113b266f1 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 14:33:16 +0200 Subject: [PATCH 84/91] AssetManagerTest: updated listRevs tests Signed-off-by: Dr Marco Claudio De La Pierre --- .../nextflow/scm/AssetManagerTest.groovy | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 82ee937cca..957732c9a6 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -122,18 +122,37 @@ class AssetManagerTest extends Specification { when: def manager = new AssetManager('cbcrg/pipe1') def list = manager.listRevisions() - def dict = manager.listRevisionsAndCommits() then: list == ['branch1','branch2'] - dict == Map.of('branch1','12345','branch2','67890') - //dict == [branch1:'12345',branch2:'67890'] when: manager = new AssetManager('cbcrg/pipe2') list = manager.listRevisions() - dict = manager.listRevisionsAndCommits() then: list == ['branchA', 'branchB'] + } + + def testListRevisionsAndCommits() { + given: + String revisionMap1 = '''branch1,12345\nbranch2,67890''' + String revisionMap2 = '''branchA,abcde\nbranchB,fghij''' + + def folder = tempDir.getRoot() + folder.resolve('cbcrg/pipe1/.nextflow/').mkdirs() + folder.resolve('cbcrg/pipe2/.nextflow/').mkdirs() + folder.resolve('cbcrg/pipe1/' + REVISION_MAP).text = revisionMap1 + folder.resolve('cbcrg/pipe2/' + REVISION_MAP).text = revisionMap2 + + when: + def manager = new AssetManager('cbcrg/pipe1') + def dict = manager.listRevisionsAndCommits() + then: + dict == Map.of('branch1','12345','branch2','67890') + + when: + manager = new AssetManager('cbcrg/pipe2') + dict = manager.listRevisionsAndCommits() + then: dict == Map.of('branchA','abcde','branchB','fghij') } From bac8797b49253fbbac7511246c9025ff61916f2b Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 14:44:37 +0200 Subject: [PATCH 85/91] AssetManager: update to revisionToCommitWithBareRepo Signed-off-by: Dr Marco Claudio De La Pierre --- .../src/main/groovy/nextflow/scm/AssetManager.groovy | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 45adf948a3..c3734913f3 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -299,11 +299,13 @@ class AssetManager { String revisionToCommitWithBareRepo(String revision) { String commitId - def rev = Git.open(bareRepo) - .getRepository() - .resolve(revision ?: Constants.HEAD) - if( rev ) - commitId = rev.getName() + if( bareRepo.exists() ) { + def rev = Git.open(bareRepo) + .getRepository() + .resolve(revision ?: Constants.HEAD) + if( rev ) + commitId = rev.getName() + } return commitId } From 5de01cc65c3923134144dd5e454e80220af08bbd Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 14:52:46 +0200 Subject: [PATCH 86/91] AssetManagerTest: removed unneeded variable --- .../src/test/groovy/nextflow/scm/AssetManagerTest.groovy | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 957732c9a6..1f66bb5b82 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -17,7 +17,6 @@ package nextflow.scm import static nextflow.scm.AssetManager.BARE_REPO -import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME import static nextflow.scm.AssetManager.REVISION_MAP import static nextflow.scm.AssetManager.REVISION_SUBDIR @@ -501,15 +500,15 @@ class AssetManagerTest extends Specification { } ''' def dir = tempDir.getRoot() - dir.resolve('foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME).mkdirs() - dir.resolve('foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/nextflow.config').text = config + dir.resolve('foo/bar/' + REVISION_SUBDIR + '/' + 'mockup_dir').mkdirs() + dir.resolve('foo/bar/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/nextflow.config').text = config dir.resolve('foo/bar/' + BARE_REPO).mkdirs() dir.resolve('foo/bar/' + BARE_REPO + '/config').text = GIT_CONFIG_TEXT when: def holder = new AssetManager() holder.build('foo/bar') - holder.setLocalPath(new File(dir.toString() + '/foo/bar/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME)) + holder.setLocalPath(new File(dir.toString() + '/foo/bar/' + REVISION_SUBDIR + '/' + 'mockup_dir')) then: holder.getMainScriptName() == 'hello.nf' holder.manifest.getDefaultBranch() == 'super-stuff' From b061203519331f3ece7a1c441ea1eaa7d16dfa03 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 14:53:05 +0200 Subject: [PATCH 87/91] UpdateModuleTest: small makeup --- .../nextflow/scm/UpdateModuleTest.groovy | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy index 2e7f56839f..918d8d787d 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy @@ -110,16 +110,16 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_x').exists() - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').exists() - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file1.txt').text == 'Hello' - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file2.log').text == 'World' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file1.txt').text == 'Hello' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file2.log').text == 'World' - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_x/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file2.log').text == 'Mondo' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file2.log').text == 'Mondo' } @@ -148,11 +148,11 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_2').exists() - target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() - target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() - target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 - target.resolve('local/pipe_2/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').list().size()==0 + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').list().size()==0 } def 'should clone selected submodules' () { @@ -181,16 +181,16 @@ class UpdateModuleTest extends Specification { then: target.resolve('local/pipe_3').exists() - target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() - target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() - target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 - target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() - target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc').exists() - target.resolve('local/pipe_3/.nextflow/commits/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc/file-x.txt').text == 'x' + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc/file-x.txt').text == 'x' } From 5a81758a23481df73d790d505e0fd882f87f263c Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 15:02:52 +0200 Subject: [PATCH 88/91] UpdateModuleTest: fixed all unit tests --- .../groovy/nextflow/scm/AssetManager.groovy | 10 ++-- .../nextflow/scm/UpdateModuleTest.groovy | 48 ++++++++++--------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index c3734913f3..411f882058 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -354,8 +354,6 @@ class AssetManager { @PackageScope void updateRevisionMapAndLocalPath(String revision) { - // get local copy of bare repository - checkBareRepo() String commitId = revisionToCommitWithBareRepo(revision) @@ -796,14 +794,18 @@ class AssetManager { * * @result A message representing the operation result */ - String download(Integer deep=null) { + String download(Integer deep=null, boolean testDisableUpdateLocalPath = false) { assert project // make sure it contains a valid repository checkValidRemoteRepo() + // get local copy of bare repository + checkBareRepo() // update mapping of revision to commit, and update localPath - updateRevisionMapAndLocalPath(revision) + // boolean is for testing purposes only (e.g. UpdateModuleTest) + if( !testDisableUpdateLocalPath ) + updateRevisionMapAndLocalPath(revision) /* * if the pipeline does not exists locally pull it from the remote repo diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy index 918d8d787d..573a627bba 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy @@ -17,6 +17,7 @@ package nextflow.scm import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME +import static nextflow.scm.AssetManager.REVISION_SUBDIR import java.nio.file.Files import java.nio.file.Path @@ -105,21 +106,22 @@ class UpdateModuleTest extends Specification { when: def manager = new AssetManager("file:${baseFolder}/pipe_x") - manager.download() + manager.setLocalPath(new File(target.toString() + '/local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir')) + manager.download(null, true) manager.updateModules() then: target.resolve('local/pipe_x').exists() - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/.git').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/main.nf').exists() - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').exists() - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file1.txt').text == 'Hello' - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa/file2.log').text == 'World' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_aaa').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_aaa/file1.txt').text == 'Hello' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_aaa/file2.log').text == 'World' - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file2.log').text == 'Mondo' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_bbb').exists() + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_x/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_bbb/file2.log').text == 'Mondo' } @@ -143,16 +145,17 @@ class UpdateModuleTest extends Specification { when: def manager = new AssetManager( "file:${baseFolder}/pipe_2" ) - manager.download() + manager.setLocalPath(new File(target.toString() + '/local/pipe_2/' + REVISION_SUBDIR + '/' + 'mockup_dir')) + manager.download(null, true) manager.updateModules() then: target.resolve('local/pipe_2').exists() - target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() - target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/.git').exists() + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/main.nf').exists() - target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 - target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').list().size()==0 + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_aaa').list().size()==0 + target.resolve('local/pipe_2/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_bbb').list().size()==0 } def 'should clone selected submodules' () { @@ -176,21 +179,22 @@ class UpdateModuleTest extends Specification { when: def manager = new AssetManager( "file:${baseFolder}/pipe_3" ) - manager.download() + manager.setLocalPath(new File(target.toString() + '/local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir')) + manager.download(null, true) manager.updateModules() then: target.resolve('local/pipe_3').exists() - target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/.git').exists() - target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/main.nf').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/.git').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/main.nf').exists() - target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_aaa').list().size()==0 + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_aaa').list().size()==0 - target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb').exists() - target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_bbb/file1.txt').text == 'Ciao' + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_bbb').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_bbb/file1.txt').text == 'Ciao' - target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc').exists() - target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + DEFAULT_REVISION_DIRNAME + '/prj_ccc/file-x.txt').text == 'x' + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_ccc').exists() + target.resolve('local/pipe_3/' + REVISION_SUBDIR + '/' + 'mockup_dir' + '/prj_ccc/file-x.txt').text == 'x' } From 305299434874c77b136849488b970da8044e7173 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 15:57:43 +0200 Subject: [PATCH 89/91] UpdateModuleTest: minor edit --- .../src/test/groovy/nextflow/scm/UpdateModuleTest.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy index 573a627bba..4e1f7e9e49 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/UpdateModuleTest.groovy @@ -16,7 +16,6 @@ package nextflow.scm -import static nextflow.scm.AssetManager.DEFAULT_REVISION_DIRNAME import static nextflow.scm.AssetManager.REVISION_SUBDIR import java.nio.file.Files From 6d6d7ae5d786e311a8a868f57f872cc4ad03b700 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 16:51:18 +0200 Subject: [PATCH 90/91] AssetManager: set revision and localPath outside constructor as separate method ; plus related updates across codebase --- .../main/groovy/nextflow/cli/CmdClone.groovy | 3 +- .../main/groovy/nextflow/cli/CmdConfig.groovy | 3 +- .../main/groovy/nextflow/cli/CmdDrop.groovy | 4 +- .../main/groovy/nextflow/cli/CmdInfo.groovy | 6 ++- .../main/groovy/nextflow/cli/CmdPull.groovy | 4 +- .../main/groovy/nextflow/cli/CmdRun.groovy | 3 +- .../main/groovy/nextflow/cli/CmdView.groovy | 3 +- .../nextflow/k8s/K8sDriverLauncher.groovy | 3 +- .../groovy/nextflow/scm/AssetManager.groovy | 24 +++++----- .../groovy/nextflow/cli/CmdInfoTest.groovy | 3 +- .../nextflow/scm/AssetManagerTest.groovy | 45 +++++++++++++------ 11 files changed, 65 insertions(+), 36 deletions(-) diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy index 0c0e369317..9fd1b6ad37 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdClone.groovy @@ -53,7 +53,8 @@ class CmdClone extends CmdBase implements HubOptions { Plugins.init() // the pipeline name String pipeline = args[0] - final manager = new AssetManager(pipeline, revision, this) + final manager = new AssetManager(pipeline, this) + manager.setRevisionAndLocalPath(pipeline, revision) // the target directory is the second parameter // otherwise default the current pipeline name diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy index 851261c67b..30b5124edf 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdConfig.groovy @@ -186,7 +186,8 @@ class CmdConfig extends CmdBase { return file.parent ?: Paths.get('/') } - final manager = new AssetManager(path, revision) + final manager = new AssetManager(path) + manager.setRevisionAndLocalPath(path, revision) manager.isLocal() ? manager.localPath.toPath() : manager.configFile?.parent } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy index 5cbe23663e..311738ad5b 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdDrop.groovy @@ -63,10 +63,10 @@ class CmdDrop extends CmdBase { revManager.listRevisions().each { rev -> if( rev == DEFAULT_REVISION_DIRNAME ) rev = null - dropList << new AssetManager(args[0], rev) + dropList << new AssetManager(args[0]).setRevisionAndLocalPath(args[0], rev) } } else { - dropList << new AssetManager(args[0], revision) + dropList << new AssetManager(args[0]).setRevisionAndLocalPath(args[0], revision) } if ( !dropList ) { diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy index dddeb72bed..b02a367220 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdInfo.groovy @@ -75,11 +75,13 @@ class CmdInfo extends CmdBase { } Plugins.init() - def manager = new AssetManager(args[0], null) + def manager = new AssetManager(args[0]) + manager.setRevisionAndLocalPath(args[0], null) if( !manager.isLocal() ) { // if default branch not found locally, use first one from list of local pulls if ( manager.listRevisions() ) { - manager = new AssetManager(args[0], manager.listRevisions()[0]) + manager = new AssetManager(args[0]) + manager.setRevisionAndLocalPath(args[0], manager.listRevisions()[0]) if( !manager.isLocal() ) throw new AbortOperationException("Unknown project `${args[0]}`") } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index e13133f47b..29488c0a4e 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -83,12 +83,12 @@ class CmdPull extends CmdBase implements HubOptions { revManager.listRevisions().each{ rev -> if( rev == DEFAULT_REVISION_DIRNAME ) rev = null - list << new AssetManager(proj, rev, this) + list << new AssetManager(proj, this).setRevisionAndLocalPath(proj, rev) } } } else { args.toList().each { - list << new AssetManager(it, revision, this) + list << new AssetManager(it, this).setRevisionAndLocalPath(it, revision) } } diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy index c54ec91982..36e56bb21f 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy @@ -569,7 +569,8 @@ class CmdRun extends CmdBase implements HubOptions { /* * try to look for a pipeline in the repository */ - def manager = new AssetManager(pipelineName, revision, this) + def manager = new AssetManager(pipelineName, this) + manager.setRevisionAndLocalPath(pipelineName, revision) def repo = manager.getProjectWithRevision() boolean checkForUpdate = true diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy index 54899d1f92..96eaa22b39 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdView.groovy @@ -54,7 +54,8 @@ class CmdView extends CmdBase { @Override void run() { Plugins.init() - def manager = new AssetManager(args[0], revision) + def manager = new AssetManager(args[0]) + manager.setRevisionAndLocalPath(args[0], revision) if( !manager.isLocal() ) throw new AbortOperationException("Unknown project `${manager.getProjectWithRevision()}`") diff --git a/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy b/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy index 4a2e5a83a8..b1f9e83d92 100644 --- a/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/k8s/K8sDriverLauncher.groovy @@ -273,7 +273,8 @@ class K8sDriverLauncher { if( !interactive && !pipelineName.startsWith('/') && !cmd.remoteProfile && !cmd.runRemoteConfig ) { // -- check and parse project remote config Plugins.init() - final pipelineConfig = new AssetManager(pipelineName, cmd.revision, cmd) .getConfigFile() + final pipelineConfig = new AssetManager(pipelineName, cmd) .getConfigFile() + pipelineConfig.setRevisionAndLocalPath(pipelineName, cmd.revision) builder.setUserConfigFiles(pipelineConfig) } diff --git a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy index 411f882058..acd7a2d898 100644 --- a/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy @@ -86,7 +86,7 @@ class AssetManager { /** * Directory where the pipeline is cloned (i.e. downloaded) * - * Schema: $NXF_ASSETS///.nextflow/commits/ + * Schema: $NXF_ASSETS///.nextflow/commits/ */ private File localPath @@ -113,37 +113,34 @@ class AssetManager { * Create a new asset manager with the specified pipeline name * * @param pipelineName The pipeline to be managed by this manager e.g. {@code nextflow-io/hello} - * @param revision Revision ID for the selected pipeline (git branch, tag or commit SHA number) */ - AssetManager( String pipelineName, String revision = null, HubOptions cliOpts = null) { + AssetManager( String pipelineName, HubOptions cliOpts = null) { assert pipelineName // read the default config file (if available) def config = ProviderConfig.getDefault() // build the object - build(pipelineName, revision, config, cliOpts) + build(pipelineName, config, cliOpts) } - AssetManager( String pipelineName, String revision, Map config) { + AssetManager( String pipelineName, Map config) { assert pipelineName // build the object - build(pipelineName, revision, config) + build(pipelineName, config) } /** * Build the asset manager internal data structure * * @param pipelineName A project name or a project repository Git URL - * @param revision Revision ID for the selected pipeline (git branch, tag or commit SHA number) * @param config A {@link Map} holding the configuration properties defined in the {@link ProviderConfig#DEFAULT_SCM_FILE} file * @param cliOpts User credentials provided on the command line. See {@link HubOptions} trait * @return The {@link AssetManager} object itself */ @PackageScope - AssetManager build( String pipelineName, String revision = null, Map config = null, HubOptions cliOpts = null ) { + AssetManager build( String pipelineName, Map config = null, HubOptions cliOpts = null ) { this.providerConfigs = ProviderConfig.createFromMap(config) - this.revision = revision this.project = resolveName(pipelineName) validateProjectName(this.project) @@ -152,8 +149,6 @@ class AssetManager { setupCredentials(cliOpts) validateProjectBareDir() - updateProjectDir(this.project, revisionToCommitWithMap(this.revision)) - return this } @@ -352,6 +347,13 @@ class AssetManager { } } + AssetManager setRevisionAndLocalPath(String pipelineName, String revision) { + this.revision = revision + updateProjectDir(resolveName(pipelineName), revisionToCommitWithMap(revision)) + + return this + } + @PackageScope void updateRevisionMapAndLocalPath(String revision) { diff --git a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy index 59a12a847f..d4c355fc8f 100644 --- a/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/cli/CmdInfoTest.groovy @@ -47,7 +47,8 @@ class CmdInfoTest extends Specification { AssetManager.root = tempDir.toFile() String revision = null def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) // download the project manager.download() } diff --git a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy index 1f66bb5b82..bc62712b5b 100644 --- a/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy +++ b/modules/nextflow/src/test/groovy/nextflow/scm/AssetManagerTest.groovy @@ -235,7 +235,8 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() String revision = null - def manager = new AssetManager().build('nextflow-io/hello', revision) + def manager = new AssetManager().build('nextflow-io/hello') + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) String revisionMap1 = '''v1.2,1b420d060d3fad67027154ac48e3bdea06f058da\n''' when: @@ -251,7 +252,8 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() String revision = null - def manager = new AssetManager().build('nextflow-io/hello', revision) + def manager = new AssetManager().build('nextflow-io/hello') + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) String revisionMap1 = '''v1.2,1b420d060d3fad67027154ac48e3bdea06f058da\n''' when: @@ -269,7 +271,8 @@ class AssetManagerTest extends Specification { def folder = tempDir.getRoot() String revision = null def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) when: manager.checkBareRepo() @@ -285,7 +288,8 @@ class AssetManagerTest extends Specification { def folder = tempDir.getRoot() String revision = null def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) when: manager.checkBareRepo() @@ -301,7 +305,8 @@ class AssetManagerTest extends Specification { def folder = tempDir.getRoot() String revision = '7588c46ffefb4e3c06d4ab32c745c4d5e56cdad8' // easier to fix commit for a generic test def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', revision, [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) when: manager.download() @@ -321,8 +326,10 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() + String revision = 'v1.2' def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', "v1.2", [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) // tag v1.2 -> commit 1b420d060d3fad67027154ac48e3bdea06f058da when: @@ -342,8 +349,10 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() + String revision = '6b9515aba6c7efc6a9b3f273ce116fc0c224bf68' def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', "6b9515aba6c7efc6a9b3f273ce116fc0c224bf68", [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) when: manager.download() @@ -365,8 +374,10 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() + String revision = 'mybranch' def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', "mybranch", [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) // as of Jun 2024, branch "mybranch" -> commit "1c3e9e7404127514d69369cd87f8036830f5cf64" when: @@ -389,7 +400,8 @@ class AssetManagerTest extends Specification { def dir = tempDir.getRoot() String revision = null def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/hello', revision, [providers:[github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/hello', [providers:[github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) when: manager.clone(dir.toFile()) @@ -527,7 +539,8 @@ class AssetManagerTest extends Specification { when: def holder = new AssetManager() - holder.build('foo/bar').setLocalPath(new File(dir.toString() + '/foo/bar')) + holder.build('foo/bar') + holder.setLocalPath(new File(dir.toString() + '/foo/bar')) then: holder.getMainScriptName() == 'main.nf' @@ -665,8 +678,10 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() + String revision = 'dev' def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/nf-test-branch', "dev", [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/nf-test-branch', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/nf-test-branch', revision) // as of June 2024, branch "dev" -> commit "6f882561d589365c3950d170df8445e3c0dc8028" when: @@ -682,7 +697,9 @@ class AssetManagerTest extends Specification { given: def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/nf-test-branch', 'dev', [providers: [github: [auth: token]]]) + String revision = 'dev' + def manager = new AssetManager().build('nextflow-io/nf-test-branch', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) expect: manager.checkValidRemoteRepo() @@ -695,8 +712,10 @@ class AssetManagerTest extends Specification { given: def folder = tempDir.getRoot() + String revision = 'v0.1' def token = System.getenv('NXF_GITHUB_ACCESS_TOKEN') - def manager = new AssetManager().build('nextflow-io/nf-test-branch', "v0.1", [providers: [github: [auth: token]]]) + def manager = new AssetManager().build('nextflow-io/nf-test-branch', [providers: [github: [auth: token]]]) + manager.setRevisionAndLocalPath('nextflow-io/hello', revision) // tag "v0.1" -> commit "6f882561d589365c3950d170df8445e3c0dc8028" when: From 69416fc8a0c5158d83d9dc4b190adcac92c8a91c Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Tue, 25 Jun 2024 16:53:27 +0200 Subject: [PATCH 91/91] CmdPull: allow -a as equivalent to -all --- docs/cli.md | 2 +- modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index ddfe83439d..e7fc50955b 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1074,7 +1074,7 @@ The `pull` command downloads a pipeline from a Git-hosting platform into the glo **Options** -`-all` +`-a, -all` : Update all downloaded projects. `-d, -deep` diff --git a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy index 29488c0a4e..cf5c661a56 100644 --- a/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/cli/CmdPull.groovy @@ -40,7 +40,7 @@ class CmdPull extends CmdBase implements HubOptions { @Parameter(description = 'project name or repository url to pull', arity = 1) List args - @Parameter(names='-all', description = 'Update all downloaded projects', arity = 0) + @Parameter(names=['-a','-all'], description = 'Update all downloaded projects', arity = 0) boolean all @Parameter(names=['-r','-revision'], description = 'Revision of the project to pull (either a git branch, tag or commit SHA number)')