Search code examples
azure-devopsazure-pipelinesrakurakudo

set PATH in azure pipelines in Windows


I am using Azure Pipelines to build a Rakudo binary for Raku (previously aka Perl 6) in Windows.

This is my azure-pipelines.yml file:

jobs:
- job: Windows
  pool:
    vmImage: 'vs2017-win2016'
  steps:
    - bash: |
        mkdir -p $(Build.SourcesDirectory)/rakudo-win
        curl -L https://github.com/rakudo/rakudo/releases/download/2019.07.1/rakudo-2019.07.1.tar.gz | tar xz
        mv rakudo-2019.07.1 rakudo
        cd rakudo
        C:/Strawberry/perl/bin/perl Configure.pl --gen-moar --gen-nqp --backends=moar --prefix=$(Build.SourcesDirectory)/rakudo-win
        make
        make install

    - bash: |
        echo "##vso[task.prependpath]$(Build.SourcesDirectory)/rakudo-win/bin"

    - bash: |
        perl6 -v

The pipeline script builds perl6 binary fine inside $(Build.SourcesDirectory)/rakudo-win/bin folder. There is indeed perl6.exe inside $(Build.SourcesDirectory)/rakudo-win/bin. To make it available, I set the path by prepending it in the bash script. But when I try to run command perl6 -v, the build fails at this step.

I searched for similar issues in SO here, here, here.

Still I could not solve my issue. Any help how to make perl6 binary available at PATH?

EDITED

Next thing I did was create another .yml script as follows:

jobs:
- job: Windows
  pool:
    vmImage: 'vs2017-win2016'
  steps:
    - script: |
        call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
    - pwsh: |
        mkdir -p C:\rakudo-win
        Invoke-WebRequest -Uri "https://github.com/rakudo/rakudo/releases/download/2019.07.1/rakudo-2019.07.1.tar.gz" -OutFile "rakudo.tar.gz"
        tar -xvf .\rakudo.tar.gz
        cd rakudo-2019.07.1
        C:\Strawberry\perl\bin\perl Configure.pl --gen-moar --gen-nqp --backends=moar --prefix=C:\rakudo-win
        make
        make install
    - pwsh: |
        $oldpath = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).path
        $newpath = "C:\rakudo-win\bin;$oldpath" 
        Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newpath
    - script: |
        SET PATH=C:\rakudo-win\bin;%PATH%

    - script: |
        perl6 -v

and tried changing PATH twice once in powershell and another in cmdline. But still it throws following error:

'perl6' is not recognized as an internal or external command,
operable program or batch file.

Any help?


Solution

  • In fact, you are very close to the correct solution. Your second powershell task has set the PATH successfully. You can add another separate task to print out the system PATH value to verify this.

    - pwsh: |
        $NewPathInRegistry = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).path
        Write-Host $NewPathInRegistry
    

    enter image description here


    To set the PATH programmatically, you can not use set command, this command can indeed set the environment variable PATH, but the disadvantage of set is the new PATH value is only available in the current command line terminal, it does not actually been added into the System Variable. That's why you were getting an unrecognized error in the next script step.

    To permanently add the directory to environment variable PATH so that it can work for next others steps, you need use setx or add them into Registry by using reg add. But the usage of setx has limitation that the PATH value max to 1024 characters. So, here the best solution is updating PATH by modifying the Registry value.

    BUT, updating Registry still has another issue, you must kill current process and run one new process to run perl6 so that it can read the new available Registry setting.

    If run stop-process in Azure devops pipeline, it will make the task failed with exit code -1. This is the expected exit code, so you can set the continueOnError: true to step so that the next steps can continue.