Increment a version number contained in a text file

陌路散爱 提交于 2020-03-21 07:03:25

问题


This self-answered question addresses the scenario originally described in Increment version number in file:

A version number embedded in a text file is to be incremented.

Sample text-file content:

nuspec{
    id = XXX;
    version: 0.0.30;
    title: XXX;

For instance, I want embedded version number 0.0.30 updated to 0.0.31.

The line of interest can be assumed to match the following regex: ^\s+version: (.+);$

Note hat the intent is not to replace the version number with a fixed new version, but to increment the existing version.

Ideally, the increment logic would handle version strings representing either [version] (System.Version) or [semver] (System.Management.Automation.SemanticVersion) instances, ranging from 2 - 4 components; e.g.:

  • 1.0
  • 1.0.2
  • 1.0.2.3 - [version] format (up to 4 numeric components)
  • 1.0.2-preview2 - [semver] format (up to 3 numeric components), optionally with a --separated preview label
  • 1.0.2-preview2+001 - ditto, additionally with a +-separated build label

回答1:


In PowerShell [Core] (v6.1+), a concise solution is possible:

$file = 'somefile.txt'
(Get-Content -Raw $file) -replace '(?m)(?<=^\s+version: ).+(?=;$)', {
    # Increment the *last numeric* component of the version number.
    # See below for how to target other components.
    $_.Value -replace '(?<=\.)\d+(?=$|-)', { 1 + $_.Value }
  } | Set-Content $file

Note:
* In PowerShell [Core] 6+, BOM-less UTF-8 is the default encoding; use -Encoding with Set-Content if you need a different encoding.
* By using -Raw, the command reads the entire file into memory first, which enables writing back to that same file in the same pipeline; however, there is a slight risk of data loss if writing back to the input file gets interrupted.
* -replace invariably replaces all substrings that match the regex.
* Inline regex option (?m) ensures that ^ and $ match the start and end of individual lines, which is necessary due to Get-Content -Raw reading the entire file as a single, multi-line string.

Note:

  • For simplicity, text-based manipulation of the version string is performed, but you could also cast $_.Value to [version] or [semver] (PowerShell [Core] v6+ only) and work with that.
    The advantage of the text-based manipulation is the concise ability to retain all other components of the input version string as-is, without adding previously unspecified ones.

  • The above relies on the -replace operator's ability to perform regex-based string substitutions fully dynamically, via a script block ({ ... }) - as explained in this answer.

  • The regexes use look-around assertions ((?<=...) and (?=...)) so as to ensure that only the part of the input to be modified is matched.

    • Only the (?<=^\s+version: ) and (?=;$) look-arounds are specific to the sample file format; adjust these parts as needed to match the version number in your file format.

The above increment's the input version's last numeric component. To target the various version-number components, use the following inner regex instead:

  • Increment the major number (e.g., 2.0.9 -> 3.0.9):

    • '2.0.9' -replace '\d+(?=\..+)', { 1 + [int] $_.Value }
  • The minor number:

    • '2.0.9' -replace '(?<=^\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
  • The patch / build number (3rd component; 2.0.9 -> 2.0.10):

    • '2.0.9' -replace '(?<=^\d+\.\d+\.)\d+(?=.*)', { 1 + [int] $_.Value }
  • The last / revision number, as above, whatever it is, even if followed by a pre-release label (e.g.,; 2.0.9.10 -> 2.0.9.11 or 7.0.0-preview2 -> 7.0.1-preview2):

    • '2.0.9.10' -replace '(?<=\.)\d+(?=$|-)', { 1 + [int] $_.Value }

Note: If the targeted component doesn't exist, the original version is returned as-is.


In Windows PowerShell, where -replace doesn't support script-block-based substitutions, you can use the switch statement with the -File and -Regex options instead:

$file = 'someFile.txt'
$updatedFileContent = 
  switch -regex -file $file { # Loop over all lines in the file.

    '^\s+version: (.+);$' { # line with version number

      # Extract the old version number...
      $oldVersion = $Matches[1]

      # ... and update it, by incrementing the last component in this
      # example.
      $components = $oldVersion -split '\.'
      $components[-1] = 1 + $components[-1]

      $newVersion = $components -join '.'

      # Replace the old version with the new version in the line
      # and output the modified line.
      $_.Replace($oldVersion, $newVersion)

    }

    default { # All other lines.
      # Pass them through.
      $_ 
    }
}

# Save back to file. Use -Encoding as needed.
$updatedFileContent | Set-Content $file


来源:https://stackoverflow.com/questions/60651450/increment-a-version-number-contained-in-a-text-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!