Linux & CVS
Um dos grandes atrativos no Linux é a disponibilidade de seu código fonte e de ferramentas para programação. Milhares e milhares de linhas de código são escritas, alteradas, removidas diariamente de programas que podem ou não ser livres. Mas, como saber o que mudou em um caso específico? Como rastrear essas mudanças?
O uso do CVS surge como uma das possíveis respostas. Usando um servidor CVS pode-se rastrear, facilmente, o autor responsável por uma mudança e o que foi mudado, além de quando foi e qual ou quais arquivos foram afetados. Também é possível configurar quem pode ou não efetuar mudanças, etc.
O funcionamento do CVS vale-se de mecanismos de reconhecimentos de padrões que pode trabalhar diretamente de acordo com localizações definidas ou com uma busca do tipo fuzzy, procurando por similaridades no texto.
A conexão pode ser feita diretamente com o servidor CVS, representando uma configuração mais simples, ou com o uso de, por exemplo, SSH, representando uma conexão mais segura. Neste artigo, por uma questão de simplicidade e possibilidade de explicação dos recursos disponibilizados, farei a configuração simplificada. Outras possibilidades que permitem maior grau de segurança (SSH, SSH + chroot, etc.) são possíveis e encorajadas.
O que é o CVS
- Um sistema de controle de versões
- Permite desenvolvimento colaborativo
- Encarregando-se de juntar automaticamente as mudanças feitas por todos os autores do documento / programa
O que o CVS não é
- Um sistema de geração de documentos
- Um substituto para o gerenciamento de documentos
- Um substituto para a comunicação entre os autores
- Um sistema automatizado de testes
- Um sistema de processamento embutido
- A solução para todos os teus problemas
Algumas destas atividades podem ser realizadas com uma integração de programas ou scripts juntamente com o CVS. Mas, por si próprio, o CVS não realiza nenhuma das ``mágicas'' acima.
Mas qual é a grande vantagem de um servidor CVS? Por quê não é simplesmente guardada uma cópia do arquivo em cada um de seus estágios?
O CVS, para otimizar o uso de disco, guarda apenas a última versão de um arquivo qualquer e guarda modificações para as versões anteriores ou ramificações. Essa abordagem torna o sistema mais eficiente tanto em termos de espaço ocupado quanto de velocidade para obtenção de versões anteriores ou comparações entre versões.
Configuração do Servidor
O primeiro passo é identificar qual o tipo de superservidor de conexões você possui instalado: inetd ou xinetd. Para o inetd, deve-se adicionar a seguinte linha no arquivo /etc/inetd.conf e reiniciar o servidor (com, por exemplo um killall -HUP inet):
cvspserver stream tcp nowait cvs /usr/sbin/tcpd cvs -f
-T /tmp --allow-root=/home/cvs pserver
Nota:. A linha acima deve ser digitada em apenas uma linha.
O primeiro parâmetro, cvspserver, indica a porta na qual o inetd ficará escutando por conexões. O comum é a porta 2401, indicada da seguinte maneira no arquivo /etc/services:
cvspserver 2401/tcp cvspserver 2401/udp
O segundo e terceiro parâmetros informam o tipo de conexão. O quarto parâmetro informa o que o inetd deve fazer com as conexões. O quinto parâmetro indica qual o usuário que deve ser utilizado para executar os programas e, por motivos de segurança, optamos por um usuário exclusivo para o CVS, ao invés de utilizar o root. O próximo parâmetro informa que usaremos o tcpd, do tcp_wrappers, ao invés do CVS diretamene. Isso nos permitirá um melhor controle de acesso baseado em máquinas, usuários, etc. Por último temos o CVS e seus parâmetros. Ali informamos qual o diretório que poderá ser acessado (no caso /home/cvs), qual o tipo de autenticação que será utilizada (pserver), qual o diretório para arquivos temporários (/tmp) e diz que não deve ser lido o arquivo ~/.cvsrc.
Explicada a linha para o inetd, temos a seguinte configuração para o xinetd (sugiro um arquivo com o nome cvs no /etc/xinet.d/):
service cvspserver
{
disable = no
socket_type = stream
protocol = tcp
wait = no
user = root
env = TMP=/tmp TMPDIR=/tmp HOME=/tmp
server = /usr/bin/cvs
server_args = -f --allow-root=/home/cvs pserver
}
As explicações para os parâmetros são idênticas às apresentadas para o inetd. Uma reinicialização do servidor xinetd também é necessária (killall -HUP xinetd) para que as novas configurações sejam lidas e passem a ser aceitas pelo servidor.
Pronto! Tarefa concluída. Temos um servidor CVS funcionando. Não se esqueça de liberar a conexão para todas as máquinas que deverão conectar-se ao servidor editando o arquivo /etc/hosts.allow. Teste o funcionamento com um telnet seu.servidor.aqui 2401.
O passo seguinte é a criação do repositório. Seguindo com nosso exemplo, devem existir um usuário cvs e um diretório /home/cvs pertencente a este usuário.
Repare que em nenhum momento preocupei-me com o dimensionamento da máquina a ser utilizada. Este dimensionamento exige que algumas variáveis sejam consideradas e faz-se necessário em uma análise caso a caso. Pode-se assumir, entretanto, que a maioria das máquinas modernas está num patamar suficiente de processamento e possui uma quantidade adequada de memória para funcionar como servidor CVS. Leve a questão do dimensionamento a sério se estiveres realizando alguma instalação maior ou comercialmente.
Repositórios
Criação de um repositório
Temos um servidor funcionando, mas onde armazenaremos as informações? Em repositórios! Mas, o que são eles?
Repositórios são como representamos no CVS os projetos. Um repositório pode dar origem a mais de um produto, ter mais de um arquivo ou diretório mas, recomenda-se que tenha apenas um projeto.
Usa-se o próprio CVS para criar repositórios. O comando a ser utilizado, no servidor, é:
cvs -d /home/cvs init
Caso executes este comando para um repositório que já existe, arquivos não não serão destruídos.
Este comando criará um novo repositório com os arquivos de administração necessários, preenchidos (ou não preenchidos, dependendo do ponto de vista) de acordo com o padrão do CVS.
Estes arquivos de configuração merecem uma analisada mais cuidadosa, o que foge do intuito deste artigo, portanto dê uma olhada no que aconteceu no diretório /home/cvs/ e no conteúdo dos arquivos ali gerados.
Configurações mínimas num repositório
Após configurar o servidor é necessário configurar quais usuários terão acesso ao repositório e qual o tipo de acesso que lhes será dado.
Como as senhas são armazenadas e trafegam sem criptografia nenhuma é recomendado que seja criado um arquivo passwd diferente do usado no sistema.
O formato desse arquivo é como o do /etc/passwd, com a diferença de que ele possui menos campos. São obrigatórios dois campos: nome de usuário e senha. Há um terceiro campo opcional que permite associar um usuário do CVS com um usuário existente na máquina.
anonimo::cvs anonymous: godoy:jUiJ2mNdt4PEo joao:ul8XNX4NYpVQM:cvs-proj1
As duas primeiras linhas garantem acesso a quaisquer usuários que se identifiquem como anonimo ou anonymous, não dando importância à senha fornecida por eles. A primeira ainda mapeia todas as ações para o usuário de sistema cvs, o que pode ser interessante para o gerenciamento do repositório.
A terceira linha cria um usuário godoy com uma senha qualquer e que terá suas atividades restritas de acordo com as permissões deste usuário no sistema.
A quarta linha atribui ao usuário joao uma senha e restringe suas atividades de acordo com as permissões do usuário do sistema cvs-proj1.
Usuários que não foram mapeados para usuários no sistema deverão existir neste último, ou seja, no exemplo o usuário godoy deve ser válido no sistema, bem como o usuários anonymous.
Para que o arquivo de senhas do CVS seja usado ao invés do arquivo de senhas do sistema, o arquivo $CVSROOT/CVSROOT/config ($CVSROOT aponta, no servidor, para /home/cvs. No cliente, sua formação é explicada a seguir) deve conter a linha
SystemAuth=no
Por motivos de segurança, é normal que o arquivo passwd seja editado diretamente no repositório, sem fazer sua retirada.
Configuração do cliente
Não é necessário que o usuário do CVS tenha algum tipo de acesso à máquina diferente do via CVS. Pode-se trabalhar em uma máquina e manter o repositório em outra.
O CVS trabalha no estilo cliente/servidor. Você executa-o em uma máquina que pode montar o seu diretório de trabalho, conhecido como cliente e solicitar que ela busque o repositório em uma outra máquina, conhecida como servidora.
O uso de um repositório remoto se dá da mesma maneira que um local, apenas muda a forma de declaração do repositório na variável CVSROOT.
:método:usuário@máquina:/caminho/para/o/repositório
Dentre os vários métodos de autenticação disponíveis, o mais comum é o pserver, método este semelhante ao de validação de senhas por rsh ou telnet. Suas senhas trafegam em clear-text, ou seja, sem criptografia nenhuma, portanto recomenda-se o uso de uma senha diferente para o CVS e para o uso cotidiano em sua máquina.
Caso se esteja trabalhando com diversos servidores / repositórios, a configuração de variáveis de ambiente pode ser delegada a aliases ou pode-se passar o repositório ou servidor desejado na linha de comandos.
Por uma questão de praticidade e preguiça de digitação, escolhi criar aliases. Tenho, então, aqui algo do tipo:
cvsdbk='CVS_RSH=ssh cvs -d :ext:godoy@cvs.docbook.sourceforge.net:/cvsroot/docbook' cvsnexus='cvs -d :pserver:godoy@nexus.conectiva:/home/cvs' cvsrcs='cvs -d :pserver:godoy@sup-rcs.conectiva:/var/cvs/sup-rcs'
onde os aliases cvsdbk, cvsnexus e cvsrcs funcionam como se fossem comandos, só que executam os comandos entre aspas em seu lugar.
A sintaxe para ser usada em linha de comandos está demonstrada no mesmo exemplo e é a que está entre aspas como comando a ser executado pelos aliases.
Tipos de acesso
Acesso ao repositório apenas para leitura
É possível garantir acesso apenas de leitra a repositórios usando autenticação por senha. Para restrição quando o usuário tem acesso local deve-se utilizar os métodos padrões de restrições de arquivos do sistema operacional em uso.
Pode-se fazer com que um usuário tenha acesso de leitura a um repositório de duas maneiras diferentes: por inclusão ou por exclusão.
Acesso para leitura pelo método de inclusão
O método de inclusão possui este nome pois implica na inclusão dos usuários em um arquivo chamado readers. Este arquivo é formado por um nome de usuário em cada linha (estes devem ser os mesmos do primeiro campo do arquivo passwd do CVS) e termina com uma linha em branco.
Este arquivo fica em $CVSROOT/CVSROOT/readers e seu conteúdo seria algo como
anonimo anonymous
Acesso para leitura pelo método de exclusão
Este método funciona impedindo que os que não estejam explicitamente listados com acesso de escrita façam alterações nos arquivos do CVS. O formato do arquivo writersé o mesmo que o do arquivo readers.
Este arquivo fica em $CVSROOT/CVSROOT/writers e seu conteúdo seria algo como
godoy joao
Conflitos
Como funciona o sistema de decisão se um usuário pode ou não escrever em um repositório?
Se o arquivo readers existe e o usuário está listado nele, então ele terá apenas acesso para leitura. Se o arquivo writers existe e o arquivo não está listado nele, então ele terá acesso apenas para leitura. Se nenhuma dessas condições for satisfeita, o usuário terá acesso apenas para leitura.
É óbvio que é gerado um conflito caso o usuário pertença aos dois arquivos. Esse conflito é resolvido da maneira mais conservativa possível visando proteger os dados do repositório: tal usuário terá acesso apenas para leitura.
Como funciona a numeração de versões no CVS?
O CVS faz a numeração automática de versões e isso é suficiente para muitos usuários. Entretanto, para alguns usos mais específicos é interessante ter um conhecimento e controle maiores sobre como funciona o CVS nesse sistema de numeração.
Revisões
Cada versão de um arquivo tem um único número de revisão. Números de revisão se parecem com 1.1, 1.2, 1.2.3.4, etc. Um número de revisão sempre possui um número par de inteiros decimais separados por pontos.
Versões, revisões e liberações
Um arquivo pode ter diversas versões, como descrito acima. De maneira semelhante, um software pode ter diferentes versões. Para um software é sempre dada uma versão do tipo 4.2.1.
No conceito do CVS, o primeiro tipo de versão é chamado revisão e o segundo de liberação, vindo, respectivamente, do inglês revision e release.
Designando revisões
O padrão do CVS é designar revisões mantendo constante o primeiro número e mudando apenas o segundo, portanto teríamos 1.1, 1.2 e assim sucessivamente.
Quando um novo arquivo é adicionado, o segundo número será sempre um e o primeiro será igual ao maior primeiro número presente neste diretório. Por exemplo, suponha que em um diretório existam arquivos nas revisões 1.15, 3.12 e 5.5. O próximo arquivo a ser adicionado terá a revisão 5.1.
Pense nas revisões como um controle interno do CVS e não como algo que deva ser atrelado ao documento ou software em desenvolvimento. Para fazer essa amarração pode-se usar o recurso de marcas presente no CVS.
Entretanto, se para você o número da revisão de um arquivo é importante, este pode ser ajustado com a opção -r no comando cvs commit. Para adicionar um arquivo como revisão 6.0 no diretório exemplificado acima, o comando dado seria cvs commit -r 6.0 arquivo. O número da revisão que está sendo enviada deve ser maior que os da já existentes no diretório e, ainda no exemplo acima, seria impossível, por exemplo, enviar um arquivo como pertencente à revisão 4.0.
Marcas — Revisões simbólicas
Pode-se agrupar sob um nome fictício diversas revisões diferentes de arquivos de modo a considerá-las como um produto ou um dos estágios de desenvolvimento deste.
Exemplo: Uso de marcas para controle de desenvolvimento
$ ls -l cvs* -rw-rw-r-- 1 godoy godoy 28664 Feb 16 16:02 cvs-admin.sgml -rw-rw-r-- 1 godoy godoy 10800 Feb 16 01:10 cvs.sgml $ cvs tag CVS-1_0 cvs.sgml cvs-admin.sgml $
A partir da seqüência de comandos do Exemplo 4 pode-se referir aos arquivos cvs.sgml e cvs-admin.sgml como CVS-1_0. Repare no uso do sinal ``_'' ao invés de um ``.'': o CVS possui algumas restrições quanto a caracteres que podem ou não ser utilizados. Dentre os que não podem ser utilizados encontram-se @;. e outros.
A partir desse momento, em todos os lugares onde você poderia citar a revisão de um arquivo, você poderá incluir o nome simbólico CVS-1_0.
É interessante a equipe ter uma abordagem única para a nomenclatura dessas marcações.
Opções mais avançadas estão descritas na seção 4 do manual do CVS.
Removendo as marcas
Se em algum instante do desenvolvimento uma das marcas criadas mostrar-se desinteressante ou mesmo se for incorretamente atribuída, pode-se removê-la com o comando cvs rtag -d CVS-1_0 arquivos.
Criando ramificações em um projeto
Em algumas situações de desenvolvimento é interessante verificar algumas possibilidades na elaboração de um documento ou programa. O que pode ser feito é uma divisão na equipe e cada uma abordar o problema por um ângulo diferente ou até mesmo abordarem problemas diferentes.
O CVS pode, no futuro, juntar os dois ramos de desenvolvimento ou os desenvolvedores podem abandonar o que deu resultados menos satisfatórios ou ainda podem ser mantidas as duas versões separadamente. Mudanças em um ramo podem ser repassadas para o outro ramo também.
Ramificações são criadas pelo comando
cvs tag -b lib-1_0-patches
Você irá lidar com as ramificações da mesma maneira que lidou com as marcas: usando a opção -r quando aplicável.
Para juntar dois ramos de desenvolvimento usa-se a opção -j seguida pelo nome do ramo e do arquivo ou módulo que você quer que receba as alterações.
Como trabalhar com os arquivos
Criando uma cópia pessoal de um repositório
Suponhamos que você esteja trabalhando num conjunto de arquivos que está sob o módulo de nome projeto. Para trabalhar nesses arquivos você deve ter uma cópia do módulo ou dos arquivos necessários em sua máquina ou diretório de trabalho.
Para obter os dados do repositório copiando-os para a sua máquina você deve fazer o seguinte:
$ cd diretório-de-trabalho $ cvs checkout projeto
Nesse caso será criado um diretório de nome projeto e este terá todo o conteúdo armazenado no repositório projeto.
A partir do momento em que você já obteve uma cópia do repositório, é possível que você comece a trabalhar nele.
Atualizando sua cópia
Para atualizar a sua cópia em relação ao repositório deve ser dado o comando cvs update.
Os arquivos que forem atualizados terão a letra U mostradas antes de seu nome. Arquivos modificados por você mas que ainda não foram enviados para o repositório serão marcados com a letra M.
Caso ocorra algum conflito você será informado pelo CVS e as linhas conflitantes serão marcadas nos respectivos arquivos com indicadores do tipo < < < e > > >.
Enviando mudanças para o repositório
Após realizar todas as modificações que desejar, você deve atualizar a sua cópia local de acordo com o procedimento anterior e somente então, poderá enviar suas próprias alterações para o CVS.
O comando para envio é o cvs commit. Será então apresentada uma ``janela'' (não no sentido gráfico de janela, mas no sentido de interface com o edito de textos definido como padrão) onde deverá ser preenchido um comentário a respeito das mudanças feitas no documento.
Ao sair do editor seus arquivos serão automaticamente enviados para o servidor CVS e, caso você tenha permissão de gravação no repositório, serão automaticamente atualizados.
Caso ocorra alguma mensagem de erro, corrija o erro assinalado e novamente envie o arquivo para o repositório.
Adicionando e removendo arquivos
Caso as mudanças que você tenha feito envolvam a criação ou remoção de arquivos é necessário que você comunique isto ao servidor CVS.
Para adicionar um arquivo ao repositório deve-se dar o comando cvs add arquivo.
Para remover um arquivo o comando é bem parecido: cvs remove arquivo.
Tais mudanças só serão atualizadas no repositório quando este for atualizado de acordo com o descrito anteriormente.
Encerrando o trabalho
Após trabalhar nos arquivos, você geralmente irá removê-los de sua máquina. Uma maneira aceitável de fazê-lo é a mostrada abaixo:
$ cd .. $ rm -rf módulo
Entretanto, uma maneira ainda melhor é a utilizando o comando release do CVS.
$ cd .. $ cvs release -d modulo M arquivo1 ? modulo You have [1] altered files in this repository. Are tou sure you want to release (and delete) directory `modulo': n ** `release' aborted by user choice.
Como vantagens do segundo método, pode-se citar a verificação dos arquivos. Se alguma mudança ainda não foi enviada para o repositório, você será informado pelo CVS. Se a opção de registro de históricos estiver ativada, será feita uma anotação nesse registro. O parâmetro -d faz com que o comando release também remova o diretório onde você estava trabalhando.
Dicas e comandos úteis
Pode-se visualizar as mensagens de alteração e o nome do usuários que as realizou através do comando cvs log arquivo.
Os arquivos diff podem ser vistos com o comando cvs diff arquivo.
Para mover um arquivo no repositório, mova-o normalmente, remova-o e depois adicione-o já com o novo nome.
Para desistir de suas alterações e voltar à versão presente no repositório, remova o arquivo e faça uma atualização de sua cópia.
Caso haja conflitos no momento da atualização do arquivo, o seu arquivo é guardado com o nome .#arquivo.versão.
Todos os comandos citados aceitam a opção -n, que não realiza a ação, mas mostra a você o que teria acontecido caso a mesma fosse realizada.
Informações deste documento
Autor: Jorge Godoy
Data: 28 de agosto de 2002
Última atualização: 14 de janeiro de 2003