0

I want to sort version from Iterable<Component> components. Нow when i print in the console it shows me the following result:

artifact 1.0.1
artifact 1.0.10
artifact 1.0.11
artifact 1.0.12
artifcat 1.0.2
artifcat 1.0.3
artifcat 1.0.4

This is my code

import org.sonatype.nexus.repository.storage.Component
import org.sonatype.nexus.repository.storage.Query
import org.sonatype.nexus.repository.storage.StorageFacet

def repoName = "artifact"

log.info("delete components for repository: " + repoName)


def repo = repository.repositoryManager.get(repoName)
def tx = repo.facet(StorageFacet).txSupplier().get()
try {
tx.begin()
    Iterable<Component> components = tx.findComponents(Query.builder()
      .where('version < ').param('1.1.0')
      .build(), [repo])
    tx.commit()
    
    for(Component c : components) {
        log.info("Name " + c.name() + " Version" + c.version())
    }
} catch (Exception e) {
    log.warn("Transaction failed {}", e.toString())
    tx.rollback()
} finally {
    tx.close()
}
  • 1
    There are some scenarios that aren't represented in your sample output to know for sure what the requirement is. Does `components.sort {it.version()}` yield the desired order? – Jeff Scott Brown Mar 16 '21 at 18:20
  • 1
    Your title says *Numeric string sorting* but your output shows `1.0.2` coming _after_ `1.0.11` which suggests maybe your requirement is alpha sorting. – Jeff Scott Brown Mar 16 '21 at 18:22
  • components.sort {it.version()} from where does it come this "it" – Svetoslav Panteleev Mar 16 '21 at 18:46
  • 1
    "where does it come this it" - In Groovy, if a closure does not declare an argument list, the closure will accept 1 optional argument, named `it`. `{ it.version() }`, `{ it -> it.version() }` and `{ comp -> comp.version() }` are functionally equivalent. – Jeff Scott Brown Mar 16 '21 at 18:49
  • I tried it like this before components = components.sort { it.size() }, but it gave me a error, but I don't remember it at the moment. I guess it gave me the error because I'm a using size, not a version – Svetoslav Panteleev Mar 16 '21 at 19:16
  • 1
    "components = components.sort { it.size() }" - That is valid Groovy and will not throw an error at runtime if all of the elements in `components` has a method on it named `size` that accepts no arguments. – Jeff Scott Brown Mar 16 '21 at 19:20
  • 1
    I thought you wanted to sort on version so I suggested `components = components.sort { it.version() }`. – Jeff Scott Brown Mar 16 '21 at 19:20
  • Okay, I'll try it tomorrow, if there's anything I'll write, thank you very much – Svetoslav Panteleev Mar 16 '21 at 19:40
  • I know it lacks some documentation on sonatype side (and it might actually not work since I could not test) but.... did you try to sort the components beforehand right from the orientdb result ? => `.suffix('orderby version')` (to be added right before the query `.build()`). Some references [in this answer](https://stackoverflow.com/a/49820194/9401096) – Zeitounator Mar 27 '21 at 00:39

2 Answers2

1

Some simple sorting by version can be done as follows:

def components = []
'''\
artifact 1.2.1
artifact 1.0.1
artifact 1.0.10
artifact 2.0.10
artifact 1.0.11
artifact 1.0.12
artifact 1.4.12
artifcat 1.0.2
artifcat 1.0.3
artifcat 1.0.4'''.splitEachLine( ' ' ){ name, version ->
  components << [ name:name, version:version ]
}

// augment each component with numeric represenation of version
components.each{
  it.versionNumeric = it.version.split( /\./ )*.toInteger().reverse().withIndex().sum{ num, pow -> 100.power( pow ) * num }
}

components.sort{ it.versionNumeric }*.version.join '\n'

prints

1.0.1
1.0.2
1.0.3
1.0.4
1.0.10
1.0.11
1.0.12
1.2.1
1.4.12
2.0.10
injecteer
  • 20,038
  • 4
  • 45
  • 89
0

Another example:

def components = '''\
artifact 1.2.1
artifact 1.0.1
artifact 1.0.10
artifact 2.0.10
artifact 10.2
artifact 1.0.11
artifact 1.0.12
artifact 1.4.12
artifcat 1.0.2
artifcat 1.0.3
artifcat 1.0.4
artifact 1.0.4.2'''.readLines()*.tokenize(' ').collect { name, version ->
  [name: name, version: version]
}

def sorted = components.sort { a, b ->
  def f = { it.version.tokenize('.')*.toInteger() }
  [f(a), f(b)].transpose().findResult { ai, bi -> 
    ai <=> bi ?: null 
  } ?: a.version <=> b.version
}

sorted.each { c -> 
    println c.version
}

which prints:

─➤ groovy solution.groovy
1.0.1
1.0.2
1.0.3
1.0.4
1.0.4.2
1.0.10
1.0.11
1.0.12
1.2.1
1.4.12
2.0.10
10.2

Note that this solution also (at least more or less) handles versions with differing numbers of elements such as 10.2 and 1.0.4.2.

Matias Bjarland
  • 4,124
  • 1
  • 13
  • 21