Свойства

Мы уже подробно рассмотрели, каким образом Subversion сохраняет и извлекает различные версии файлов и каталогов из хранилища. Несколько глав было посвящено этой самой фундаментальной функциональной возможности данного инструмента. И даже если бы поддержка версионирования этим исчерпывалась, Subversion все равно мог бы считаться полноценным средством управления версиями.

Однако Subversion этим не ограничивается.

Помимо версионированния каталогов и файлов, Subversion позволяет для каждого версионированного каталога или файла добавлять, изменять и удалять версионированные метаданные. Мы обращаемся к этим метаданным как к свойствам, которые можно представить в виде таблицы с двумя столбцами, присоединенной к каждому элементу рабочей копии и сопоставляющей имена свойств соответствующим значениям. Вообще, имена и значения свойств могут быть какими угодно; единственное ограничение — имена должны быть читаемым текстом. Самое главное — то, что свойства версионированы точно так же, как и текстовое содержимое файлов. Изменять, фиксировать свойства или возвращать их в исходное состояние так же просто, как и делать то же самое с содержимым файлов. Отправка и получение измененных свойств происходит точно так же, как и обычные фиксации и обновления — для этого нет необходимости менять обычный порядок действий.

В Subversion существует еще одна разновидность свойств. Так же, как и файлы и каталоги, произвольные свойства и соответствующие им значения может иметь каждая правка. Ограничения здесь те же самые — свойство должно иметь читаемое имя и может принимать любое бинарное значение. Главное отличие заключается в том, что свойства правок не версионируются. Другими словами, если изменить значение свойства правки или удалить такое свойство, Subversion не сможет восстановить предыдущее значение.

В Subversion нет жестко определенных правил по использованию свойств. Она требует только того, чтобы имена свойств не начинались с префикса svn:, поскольку это пространство имен закреплено для служебного использования. Subversion действительно использует свойства, как версионированные, так и неверсионированные, для внутренних целей. Ряд версионированных свойств играет особую роль при поиске файлов и каталогов или хранит определенную информацию о правках, в которых они найдены. Ряд свойств автоматически присоединяется к правкам в процессе фиксации, и несет о них определенную информацию . Большинство таких свойств упоминаются в этой или других главах при обсуждении более обших тем, к которым они относятся. Исчерпывающий список предопределенных свойств Subversion приводится в Свойства Subversion.

В этом разделе мы рассмотрим полезность поддержки свойств как для пользователя, так и для самой Subversion. Вы узнаете о командах svn, относящихся к свойствам, и о том, как изменение свойств влияет на привычный рабочий цикл. Надеемся, вы убедитесь в том, что свойства в Subversion расширяют возможности управления версиями.

Зачем нужны свойства?

Итак, Subversion использует свойства, чтобы хранить дополнительную информацию файлах, каталогах и правках. Вы можете найти свойствам аналогичное применение. Наличие места рядом с версионированными данными, в котором можно хранить пользовательские метаданные об этих данных, может пригодиться для поддержки ваших регламентов работы с кодом, или, возможно, для использования какими-то дополнительными утилитами.

Допустим, вы разрабатываете веб-сайт, содержащий много цифровых фотографий и показывающий их с подписями и датой. Набор этих фотографий постоянно изменяется, поэтому сайт нужно по возможности максимально автоматизировать. Фотографии могут быть большого размера, поэтому, как обычно делают на таких сайтах, посетителям потребуется показывать миниатюры изображений.

Эту задачу можно решить с помощью обычных файлов. Рядом, в одном каталоге, вы можете иметь файлы image123.jpg и image123-thumbnail.jpg. Если важно сохранить оригинальное имя файла, миниатюры могут размещаться в отдельном каталоге (например, thumbnails/image123.jpg). Таким же образом, отдельно от основного графического файла, можно хранить описание и дату. Проблема заключается в том, что файловая структура будет сильно разрастаться при каждом добавлении фотографии на сайт.

Теперь представим, как можно организовать работу того же веб-сайта, используя Subversion-свойства файлов. Допустим, имеется файл image123.jpg и у этого файла установлены свойства caption, datestamp и даже thumbnail. В этом случае рабочая копия выглядит гораздо нагляднее. Фактически, она выглядит так, как будто содержит только сами графические файлы, и ничего больше. Однако ваши скрипты автоматизации знают, что с помощью svn (а еще лучше языковой обвязки Subversion — см. «Using Languages Other than C and C++») можно получить дополнительную, необходимую для показа на сайте информацию, не занимаясь чтением индексного файла или манипуляциями с путями.

Не менее часто используются пользовательские свойства правок. Одним из типичных примеров является свойство, хранящее ID записи в трекере, с которой сопоставлена данная правка — например, потому что внесенные в правке изменения исправляют ошибку, зафиксированную в трекере с данным ID. Другие варианты использования свойств правок — задание правке более содержательного имени. Нелегко запомнить, что, к примеру, правка 1935 полностью протестирована! Если же, скажем, задать свойству результаты тестирования в этой правке значение пройдены все тесты, получится абсолютно четкая информация.

Использование свойств

Команда svn предоставляет несколько способов добавления или изменения свойств файлов и каталогов. Чтобы добавить свойство с коротким читаемым значением, наверное, проще всего указать его имя и значение в командной строке подкоманды propset.

$ svn propset copyright '(c) 2006 Red-Bean Software' calc/button.c
property 'copyright' set on 'calc/button.c'
$

Однако мы уже знаем о том, насколько гибкими могут быть свойства Subversion. И если вам необходимо задать свойству многострочное текстовое или даже бинарное значение, передавать его через командную строку будет неудобно. Для таких случаев команда propset имеет параметр --file (-F), позволяющий указать имя файла с новым значением свойства.

$ svn propset license -F /path/to/LICENSE calc/button.c
property 'license' set on 'calc/button.c'
$

На имена свойств накладывается ряд ограничений. Имя должно начинаться с буквы, двоеточия (:) или подчеркивания (_); после них можно использовать цифры, тире (-) и точки (.). [13]

Кроме команды propset, svn предлагает команду propedit. Эта команда использует для добавления или изменения свойства заданную программу-редактор (см. «Config»). При выполнении команды svn вызывает редактор с временным файлом, содержащим текущее значение свойства (или с пустым файлом, если добавляется новое свойство). Затем вы просто изменяете в редакторе значение, пока оно не станет таким, каким вы хотели бы его видеть, сохраняете временный файл и выходите из редактора. Если Subversion обнаружит, что вы действительно изменили существующее значение свойства, будет записано новое значение. Если вы вышли из редактора, не внеся никаких изменений, модификации свойства не произойдет.

$ svn propedit copyright calc/button.c  ### exit the editor without changes
No changes to property 'copyright' on 'calc/button.c'
$

Обращаем ваше внимание на то, что, подобно другим командам svn, команды, относящиеся к свойствам, могут применяться к нескольким путям за раз. Это дает возможность одной командой изменять свойства целого набора файлов. Например, можно сделать вот так:

$ svn propset copyright '(c) 2006 Red-Bean Software' calc/*
property 'copyright' set on 'calc/Makefile'
property 'copyright' set on 'calc/button.c'
property 'copyright' set on 'calc/integer.c'
…
$

Все эти добавления и редактирования свойств были бы не слишком полезны, если бы нельзя было просто узнать значение свойства. Чтобы посмотреть имена и значения свойств, заданных для файлов и каталогов, в svn есть две подкоманды. Команда svn proplist перечисляет существующие для указанного пути свойства. После того как вы узнаете имя свойства, с помощью svn propget можно запросить его значение. Эта команда выведет в стандартный поток ввода-вывода значение свойства для элемента по указанному пути (или путям) и с указанным именем.

$ svn proplist calc/button.c
Properties on 'calc/button.c':
  copyright
  license
$ svn propget copyright calc/button.c
(c) 2006 Red-Bean Software

Существует даже вариант команды proplist, перечисляющий как имена, так и значения свойств. Нужно просто добавить параметр --verbose (-v).

$ svn proplist --verbose calc/button.c
Properties on 'calc/button.c':
  copyright : (c) 2006 Red-Bean Software
  license : ================================================================
Copyright (c) 2006 Red-Bean Software.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the recipe for Fitz's famous
red-beans-and-rice.
…

Последняя команда, относящаяся к свойствам — propdel. Несмотря на то, что Subversion позволяет сохранять свойства с пустыми значениями, полностью удалить свойство с помощью propedit или propset нельзя. Например, такая команда не даст желаемого эффекта:

$ svn propset license '' calc/button.c
property 'license' set on 'calc/button.c'
$ svn proplist --verbose calc/button.c
Properties on 'calc/button.c':
  copyright : (c) 2006 Red-Bean Software
  license :
$

Для полного удаления свойств необходимо пользоваться подкомандой propdel. Ее синтаксис такой же, как и у других команд для работы со свойствами:

$ svn propdel license calc/button.c
property 'license' deleted from 'calc/button.c'.
$ svn proplist --verbose calc/button.c
Properties on 'calc/button.c':
  copyright : (c) 2006 Red-Bean Software
$

Помните, мы говорили о неверсионированных свойствах правок? Их тоже можно изменять с помощью svn. Просто добавьте параметр командной строки --revprop и укажите правку, свойство которой вы хотите изменить. Поскольку правки глобальны, указывать пути не требуется до тех пор, пока вы находитесь в рабочей копии того хранилища, свойство правки в котором вам нужно изменить. В противном случае, нужно просто указать URL любого пути в интересующем вас хранилище (в том числе это может быть и корневой URL хранилища). Например, вы можете заменить лог-сообщение фиксации в существующей правке. [14] Если текущий рабочий каталог является частью рабочей копии хранилища, можно просто выполнить команду svn propset, не указывая целевой путь:

$ svn propset svn:log '* button.c: Fix a compiler warning.' -r11 --revprop
property 'svn:log' set on repository revision '11'
$

Но даже если вы не выгружали из хранилища рабочую копию, можно изменить свойство, указав корневой URL хранилища:

$ svn propset svn:log '* button.c: Fix a compiler warning.' -r11 --revprop \
              http://svn.example.com/repos/project
property 'svn:log' set on repository revision '11'
$

Обратите внимание на то, что изменение этих неверсионированных свойств должно быть явно разрешено администратором (см. «Hook Scripts»). Учитывая то, что свойства не версионируются, при неаккуратном редактировании вы рискуете потерять информацию. Чтобы предотвратить потерю информации, администратор хранилища может принять меры предосторожности, и по умолчанию изменение неверсионированных свойств запрещено.

[Подсказка] Подсказка

Пользователям следует, по возможности, пользоваться svn propedit вместо svn propset. Хотя конечный результат обеих команд будет одинаков, первая позволит увидеть текущее значение свойства перед изменением, и таким образом удостовериться, что вносятся именно те изменения, которые были задуманы. В особенности это справедливо для модификации неверсионированных свойств правок. Да и изменять свойства с многострочными значениями гораздо проще в текстовом редакторе, а не в командной строке.

Свойства и рабочий цикл Subversion

Теперь, когда вы познакомились со всеми командами svn, имеющими отношение к свойствам, давайте посмотрим, как изменения свойств влияют на привычный порядок работы с Subversion. Как мы уже говорили, свойства файлов и каталогов версионированы аналогично содержимому файлов. Поэтому Subversion предоставляет те же возможности по слиянию — в случае конфликтных ситуаций — чужих изменений с вашими собственными.

Так же как и в случае с содержимым файлов, изменения свойств являются локальной модификацией и становятся постоянными только при их фиксации в хранилище с помощью svn commit. Изменение свойств можно легко отменить — команда svn revert восстановит файлы и каталоги в их первоначальное состояние, включая содержимое, свойства и все остальное. Кроме того, интересную информацию о состоянии свойств файлов и каталогов можно получить с помощью команд svn status и svn diff.

$ svn status calc/button.c
 M     calc/button.c
$ svn diff calc/button.c
Property changes on: calc/button.c
___________________________________________________________________
Name: copyright
   + (c) 2006 Red-Bean Software

$

Обратите внимание на то, что подкоманда status показала M не в первой, а во второй колонке. Это произошло потому, что в calc/button.c изменились свойства, а не текстовое содержимое. Если бы мы изменили и то и другое, в первой колонке также стояла бы буква M (см. «svn status»).

Кроме того, нужно помнить о нестандартном подходе, используемом Subversion при выводе различий для свойств. Безусловно, можно запустить svn diff и перенаправить вывод для создания работоспособного патч-файла. Но программа patch будет просто игнорировать различия свойств — как правило, она игнорирует любой мусор, который не может обработать. К сожалению, это означает, что для полного применения патча, сгенерированного svn diff, изменения свойств придется вносить вручную.

Автоматическая установка свойств

Поддержка свойств — мощная функциональная особенность Subversion. Свойства служат базовым механизмом для реализации многих других функций Subversion, обсуждаемых в книге — поддержки текстового поиска различий и слияния, подстановки ключевых слов, трансляции символов перевода строки и т. д. Однако, чтобы получить реальную выгоду от свойств, их нужно задавать для соответствующих файлов и каталогов. К сожалению, среди повседневных забот об этом очень легко забыть, особенно учитывая то, что неустановка значения свойства обычно не приводит к явно заметным ошибкам (по сравнению, скажем, с недобавлением файла под версионный контроль). Чтобы помочь в установке свойств для нужных элементов, Subversion обеспечивает пару простых, но полезных функций.

При каждом добавлении файла под версионный контроль с помощью команд svn add или svn import Subversion пытается автоматически установить несколько базовых свойств файлов. Во-первых, в операционных системах, файловые системы которых поддерживают бит разрешения выполнения, Subversion автоматически задает свойство svn:executable для вновь добавленных или импортированных файлов, у которых этот бит установлен. (Обратитесь к «Исполнимость файла» за дополнительной информации об этом свойстве.) Во-вторых, Subversion выполняет очень простую эвристическую процедуру, чтобы определить, имеет ли файл читаемое содержимое. Если это не так, Subversion автоматически устанавливает свойство svn:mime-type этого файла в значение application/octet-stream (это базовый MIME-тип, обозначающий «набор байтов»). Конечно, если Subversion угадает тип файла неправильно, или если вы пожелаете присвоить свойству svn:mime-type более точное значение — например, image/png или application/x-shockwave-flash — вы всегда можете удалить или отредактировать это свойство. (За дополнительной информацией об использовании MIME-типов в Subversion обратитесь к «Тип содержимого файла».)

Через собственную систему конфигурирования среды исполнения (см. «Параметры времени выполнения») Subversion также поддерживает более гибкую возможность автоматической установки свойств, которая позволяет задавать соответствия между масками имен файлов и именами и значениями свойств. Еще раз: эти соответствия воздействуют на добавление и импорт, и могут не только переопределять решение о MIME-типе по умолчанию, принимаемое Subversion в ходе этих операций, но и устанавливать другие стандартные или пользовательские свойства. Например, вы могли бы задать соответствие, чтобы при каждом добавлении JPEG-файла — то есть элемента, соответствующего маске *.jpg — Subversion автоматически присваивал бы свойству svn:mime-type значение image/jpeg. Или, к примеру, для всех файлов, соответствующих маске *.cpp, свойство svn:eol-style устанавливалось бы в native, а svn:keywords — в Id. Поддержка автоматических свойств — это, пожалуй, наиболее удобный инструмент Subversion в части работы со свойствами среди всего набора доступных средств. См. «Config» для дополнительной информации о настройке такой поддержки.



[13] Если вы знакомы с XML, то синтаксис XML "Name" допускает практически то же подмножество символов ASCII.

[14] Исправление в лог-сообщениях орфографических, грамматических ошибок, «просто ошибочных» записей — наверное, самый распространенный случай использования параметра --revprop.