Conceitos de controle de versão

Controle de versão mínimo

vcpkg usa uma abordagem de seleção mínima para versionamento, inspirada na usada por Go, mas modificada de algumas maneiras:

  • Sempre começa a partir de uma nova instalação, elimina a necessidade de operações de upgrade/downgrade.
  • Permita dependências irrestritas introduzindo linhas de base.

O princípio da seleção mínima, no entanto, permanece o mesmo. Dado um conjunto de restrições, vcpkg usará as versões "mais antigas" possíveis de pacotes que podem satisfazer todas as restrições.

O uso de uma abordagem de versão mínima tem as seguintes vantagens:

  • É previsível e fácil de entender.
  • O usuário controla quando as atualizações acontecem, como em, nenhuma atualização é executada automaticamente quando uma nova versão é lançada.
  • Evita o uso de um solucionador SAT.

Para dar um exemplo, considere o seguinte gráfico de pacote:

    (A 1.0) -> (B 1.0)

    (A 1.1) -> (B 1.0) 
            -> (C 3.0) 

    (A 1.2) -> (B 2.0)
            -> (C 3.0)

    (C 2.0)

E o seguinte manifesto:

{
    "name": "example",
    "version": "1.0.0",
    "dependencies": [ 
        { "name": "A", "version>=": "1.1" },
        { "name": "C", "version>=": "2.0" }
    ], 
    "builtin-baseline": "<some git commit with A's baseline at 1.0>"
}

Depois de contabilizar as dependências transitivas, temos o seguinte conjunto de restrições:

  • A >= 1,1
    • B >= 1,0
    • C >= 3,0
  • C >= 2,0

Uma vez que vcpkg tem que satisfazer todas as restrições, o conjunto de pacotes instalados torna-se:

  • A 1.1, mesmo quando A 1.2 existe, não há restrições maiores do que 1.1 então vcpkg seleciona a versão mínima possível.
  • B 1.0, transitivamente exigido pela A 1.1.
  • C 3.0, atualizado pela restrição transitiva adicionada por B 1.0 para satisfazer as restrições de versão.

Resolução de restrições

Dado um manifesto com um conjunto de dependências versionadas, vcpkg tentará calcular um plano de instalação de pacote que satisfaça todas as restrições.

As restrições de versão vêm nos seguintes sabores:

  • Restrições declaradas: restrições declaradas explicitamente no manifesto de nível superior usando version>=.
  • Restrições de linha de base: restrições adicionadas implicitamente pelo builtin-baseline.
  • Restrições transitivas: restrições adicionadas indiretamente por dependências de suas dependências.
  • Restrições substituídas: restrições substituídas no manifesto de nível superior usando overrides declarações.

Para calcular um plano de instalação, vcpkg segue aproximadamente estas etapas:

  • Adicione todas as restrições de nível superior ao plano.
  • Adicione recursivamente restrições transitivas ao plano.
    • Cada vez que um novo pacote é adicionado ao plano, adicione também sua restrição de linha de base ao plano.
    • Cada vez que uma restrição é adicionada:
    • Se existir uma substituição para o pacote
      • Selecione a versão na substituição.
    • Caso contrário:
      • Se não houver nenhuma versão anterior selecionada.
        • Selecione a versão mínima que satisfaz a restrição.
      • Se houver uma versão anterior selecionada:
        • Se o esquema de controle de versão da nova restrição não corresponder ao da versão selecionada anteriormente:
          • Adicione um conflito de versão.
        • Se a versão da restrição não for comparável à versão selecionada anteriormente. Por exemplo, comparando "version-string: apple" com "version-string: orange":
          • Adicione um conflito de versão.
        • Se a versão de restrições for maior do que a versão selecionada anteriormente:
          • Selecione a versão mais alta.
        • Caso contrário:
          • Mantenha a seleção anterior.
  • Reveja o plano:
    • Se não houver conflitos
      • Instalar os pacotes selecionados
    • Caso contrário:
      • Comunicar os conflitos ao usuário

Adquirindo versões de porta

Embora o conceito de versões de pacote sempre tenha estado presente no vcpkg, o conceito de restrições de versão não esteve.

Com a introdução de restrições de controle de versão, agora é possível que um pacote dependa de uma versão de porta que não corresponda à disponível localmente. Isso levanta um problema, pois vcpkg precisa saber como adquirir os arquivos de porta para a versão solicitada.

Para resolver esse problema, um novo conjunto de arquivos de metadados foi introduzido. Esses arquivos estão localizados no diretório no versions/ nível raiz do repositório vcpkg.

O versions/ diretório, conterá arquivos JSON para cada uma das portas disponíveis no registro. Cada arquivo listará todas as versões disponíveis para um pacote e conterá um objeto Git tree-ish que vcpkg pode verificar para obter os portfiles dessa versão.

Exemplo: zlib.json

{
  "versions": [
    {
      "git-tree": "2dfc991c739ab9f2605c2ad91a58a7982eb15687",
      "version-string": "1.2.11",
      "port-version": 9
    },
    ...
    {
      "git-tree": "a516e5ee220c8250f21821077d0e3dd517f02631",
      "version-string": "1.2.10",
      "port-version": 0
    },
    {
      "git-tree": "3309ec82cd96d752ff890c441cb20ef49b52bf94",
      "version-string": "1.2.8",
      "port-version": 0
    }
  ]
}

Para cada porta, seu arquivo de versões correspondente deve estar localizado em versions/{first letter of port name}-/{port name}.json. Por exemplo, o arquivo de versão do zlib estará localizado em versions/z-/zlib.json. Além dos arquivos de versão de porta, o arquivo de linha de base atual está localizado em versions/baseline.json.