Differences between revisions 10 and 23 (spanning 13 versions)
Revision 10 as of 2009-07-28 17:31:53
Size: 6975
Editor: JonnyDee
Comment:
Revision 23 as of 2009-08-23 16:33:08
Size: 8388
Comment:
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
Mercurial as well as other well-known version control systems cannot version directories. A "workaround" for this issue is to use placeholder files which are placed into empty directories. These placeholder files can then be committed into the repository and will make sure that, upon checkout, the directory tree is entirely reconstructed. This solution is also suggested in the [[http://mercurial.selenic.com/wiki/FAQ#FAQ.2BAC8-CommonProblems.I_tried_to_check_in_an_empty_directory_and_it_failed.21|Mercurial FAQ]]. Note however, that using that workaround might not be a good idea. Creating missing directories during a build process should also be considered as an option. Mercurial as well as other well-known version control systems cannot version directories. In other words, you cannot add empty directories! A "workaround" for this issue is to use placeholder files which are placed into empty directories. These placeholder files can then be committed into the repository and will make sure that, upon checkout, the directory tree is entirely reconstructed. This solution is also suggested in the [[http://mercurial.selenic.com/wiki/FAQ#FAQ.2BAC8-CommonProblems.I_tried_to_check_in_an_empty_directory_and_it_failed.21|Mercurial FAQ]]. Note however, that using that workaround might not be a good idea. Creating missing directories during a build process should also be considered as an option.
Line 7: Line 7:
I had been confronted with such a situation several days ago and it wasn't the first time. This is why I decided to write an open source tool which can manage the creation/deletion of such placeholder files automatically. It creates placeholder files in all empty directories. If later on new files or directories are put into such directories, the placeholder files are not necessary anymore and, thus, are removed automatically. In the past, I had been confronted with such a situation several times. This is why I decided to write an open source tool which can manage the creation/deletion of such placeholder files automatically. It creates placeholder files in all empty directories. If later on new files or directories are put into such directories, the placeholder files are not necessary anymore and, thus, are removed automatically.
Line 9: Line 9:
This tool is licensed under the GPLv3 and runs under [[http://mono-project.com/Main_Page|Mono]] (Linux) as well as under [[http://www.microsoft.com/NET|Microsoft .NET]] platform (Windows). It can be downloaded here: [[http://code.google.com/p/markemptydirs/downloads/list]] This tool is licensed under the GPLv3 and runs on [[http://mono-project.com/Main_Page|Mono .NET platform]] (available for '''Linux''', '''MacOS X''' and '''Windows''') as well as on [[http://microsoft.com/net|Microsoft .NET platform]] (available only for '''Windows'''). You can download it here: [[http://code.google.com/p/markemptydirs]].
Line 63: Line 63:
 # Provide the content directly on command line:  * Provide the content directly on command line:
Line 67: Line 67:
 # Provide a template file:  * Provide a template file:
Line 74: Line 74:
|| *VARIABLE* || *DESCRIPTION* || *ARGUMENT DESCRIPTION* ||
|| `§datetime[:<format-pattern>]§` || get UTC time || `<format-pattern>`: C# DateTime format pattern string ||
|| `§env:<env-var-name>§` || get the value from an environment variable || `<env-var-name>`: the environment variable's name ||
|| '''VARIABLE''' || '''DESCRIPTION''' || '''ARGUMENT DESCRIPTION''' ||
|| `§datetime[:<format-pattern>]§` || get UTC time || `format-pattern`: C# DateTime format pattern string ||
|| `§dir[:<base|cur.abs|cur.rel>]§` || get the base directory or current directory (default is `base`) || `base` : base directory -- `cur.abs` : absolute path of current directory -- `cur.rel` : relative path to current directory ||
|| `§
env:<env-var-name>§` || get the value from an environment variable || `env-var-name` : the environment variable's name ||
Line 78: Line 79:
|| `§lf[:<count>]§` || get a line feed character || `<count>`: integer describing how many linefeeds should be returned ||
|| `§sp[:<count>]§` || get a space character || `<count>`: integer describing how many spaces should be returned ||
|| `§lf[:<count>]§` || get a line feed character || `count` : integer describing how many linefeeds should be returned ||
|| `§placeholder[:<name|fullname>]§` || get the placeholder name (default is `name`) || `name` : file name only -- `fullname` : full file path ||
|| `§separator:<dir|path|vol>§` || get platform specific directory, path, or volume separator || `dir` : directory level separator -- `path` : path separator -- `vol` : volume separator ||
|| `§sp[:<count>]§` || get a space character || `count` : integer describing how many spaces should be returned ||
Line 95: Line 98:
Using placeholder files with unique content allows to detect renames of directories automatically. Mercurial has such a feature which tries to guess a rename by comparing file similarities. Using placeholder files with unique content allows to detect renames of directories automatically. Mercurial has such a feature which tries to guess renames by considering file similarities.
Line 146: Line 149:
$> MarkEmptyDirs PROJECT $> MarkEmptyDirs.exe PROJECT
Line 156: Line 159:
$> MarkEmptyDirs --clean PROJECT $> MarkEmptyDirs.exe --clean PROJECT
Line 164: Line 167:
$> MarkEmptyDirs --list PROJECT $> MarkEmptyDirs.exe --list PROJECT
Line 170: Line 173:
$> MarkEmptyDirs --short --dry-run --clean PROJECT $> MarkEmptyDirs.exe --short --dry-run --clean PROJECT
Line 172: Line 175:

== Execute actions upon creation or deletion of placeholder files ==

Sometimes you might want to hook into the placeholder creation or deletion process in order to execute certain actions. For example, if you want the placeholder files be added to a Mercurial repository automatically you could tell MarkEmptyDirs to execute a `hg add <placeholder-file>` everytime a new placeholder is created. Likewise, you can tell it to execute a `hg rm -fA <placeholder-file>` everytime a placeholder is to be deleted. The following command line will exactly do this:

{{{
$> MarkEmptyDirs.exe --create-hook="hg add §placeholder§" --delete-hook="hg rm -fA §placeholder§" PROJECT
}}}
----
CategoryTipsAndTricks

Introduction

Mercurial as well as other well-known version control systems cannot version directories. In other words, you cannot add empty directories! A "workaround" for this issue is to use placeholder files which are placed into empty directories. These placeholder files can then be committed into the repository and will make sure that, upon checkout, the directory tree is entirely reconstructed. This solution is also suggested in the Mercurial FAQ. Note however, that using that workaround might not be a good idea. Creating missing directories during a build process should also be considered as an option.

Sometimes a solution where the missing directories are created by some magic is not practicable and people will face the problem of managing such placeholder files. In particular, the problem with using placeholder files is that you need to create them, and delete them, if they are not necessary anymore (because there were added sub-directories or files). With big source trees managing these placeholder files can be cumbersome and error prone.

In the past, I had been confronted with such a situation several times. This is why I decided to write an open source tool which can manage the creation/deletion of such placeholder files automatically. It creates placeholder files in all empty directories. If later on new files or directories are put into such directories, the placeholder files are not necessary anymore and, thus, are removed automatically.

This tool is licensed under the GPLv3 and runs on Mono .NET platform (available for Linux, MacOS X and Windows) as well as on Microsoft .NET platform (available only for Windows). You can download it here: http://code.google.com/p/markemptydirs.

Use Cases

In the following sections some typical use cases are described and it is shown how the tool can help you getting your work easily done. For clarity, I use directory names with upper case letters and file names with lowercase letters in the following examples.

Create placeholder files

Within a directory PROJECT find all "leaf" directories that do not contain any files or sub-directories, and create a placeholder file .emptydir within each such "leaf" directory.

For example, let's assume the following source tree:

[PROJECT]
        |
        *--[DIR1]
        |       |
        |       *--[DIR1-1]
        |
        *--[DIR2]
        |       |
        |       *--file1
        |
        *--[DIR3]

A tree with the corresponding placeholder files will then look like this:

[PROJECT]
        |
        *--[DIR1]
        |       |
        |       *--[DIR1-1]
        |                 |
        |                 *--.emptydir
        |
        *--[DIR2]
        |       |
        |       *--file1
        |
        *--[DIR3]
                |
                *--.emptydir

To create the .emptydir files use the MarkEmptyDirs tool simply like this:

$> MarkEmptyDirs.exe PROJECT

This creates empty .emptydir files. If you want the placeholder files to contain special content there are two ways.

  • Provide the content directly on command line:

$> MarkEmptyDirs.exe --text "Do not delete this file." PROJECT
  • Provide a template file:

$> MarkEmptyDirs.exe --file template.txt PROJECT

In both cases you can use template variables in your placeholder content which are evaluated everytime a new placeholder file is to be created. The evaluated results then replace the variables. Currently, the following variables are available:

VARIABLE

DESCRIPTION

ARGUMENT DESCRIPTION

§datetime[:<format-pattern>]§

get UTC time

format-pattern: C# DateTime format pattern string

§dir[:<base|cur.abs|cur.rel>]§

get the base directory or current directory (default is base)

base : base directory -- cur.abs : absolute path of current directory -- cur.rel : relative path to current directory

§env:<env-var-name>§

get the value from an environment variable

env-var-name : the environment variable's name

§guid§

get a new globally unique identifier

§lf[:<count>]§

get a line feed character

count : integer describing how many linefeeds should be returned

§placeholder[:<name|fullname>]§

get the placeholder name (default is name)

name : file name only -- fullname : full file path

§separator:<dir|path|vol>§

get platform specific directory, path, or volume separator

dir : directory level separator -- path : path separator -- vol : volume separator

§sp[:<count>]§

get a space character

count : integer describing how many spaces should be returned

So in order to create template files with a unique id and time information you could do:

$> MarkEmptyDirs.exe --text="CREATOR: §env:USER§§lf§ID: §guid§§lf§TIME: §datetime§§lf:2§Do not delete this file.§lf§" PROJECT

A generated placeholder file might then look like this:

CREATOR: jonnydee
ID: 36358168-b347-4758-adaa-63e198809c32
TIME: 28.07.2009 17:20:30

Do not delete this file.

Using placeholder files with unique content allows to detect renames of directories automatically. Mercurial has such a feature which tries to guess renames by considering file similarities.

Update placeholder files

Let's assume the PROJECT directory has undergone some changes. Directories and/or files have been added and/or deleted. This requires to synchronize the corresponding placeholder files. In particular, some now are not needed anymore and new ones may now be necessary.

For instance, have a look at the following tree:

[PROJECT]
        |
        *--[DIR1]
        |       |
        |       *--[DIR1-1]
        |                 |
        |                 *--.emptydir
        |                 |
        |                 *--newfile.txt
        |
        *--[DIR2]
        |
        *--[DIR3]
                |
                *--.emptydir

DIR1-1 now contains a new file newfile.txt and a previously created .emptydir file. The former now acts as a placholder and, thus, the latter is not needed anymore. DIR2 now is empty and requires a placeholder file.

Consequently, after updating the placeholder files the tree should look like this:

[PROJECT]
        |
        *--[DIR1]
        |       |
        |       *--[DIR1-1]
        |                 |
        |                 *--newfile.txt
        |
        *--[DIR2]
        |       |
        |       *--.emptydir
        |
        *--[DIR3]
                |
                *--.emptydir

Using the MarkEmptyDirs tool for synchronization one would simply do (again):

$> MarkEmptyDirs.exe PROJECT

Delete placeholder files

There are situations where one wants a clean tree which does not contain any placeholder files. So all .emptydir files should be removed.

This can simply be achieved by using the --clean option:

$> MarkEmptyDirs.exe --clean PROJECT

List placeholder files

In order to list all placeholder files just execute:

$> MarkEmptyDirs.exe --list PROJECT

Note that this command is simply a shorthand for:

$> MarkEmptyDirs.exe --short --dry-run --clean PROJECT

Execute actions upon creation or deletion of placeholder files

Sometimes you might want to hook into the placeholder creation or deletion process in order to execute certain actions. For example, if you want the placeholder files be added to a Mercurial repository automatically you could tell MarkEmptyDirs to execute a hg add <placeholder-file> everytime a new placeholder is created. Likewise, you can tell it to execute a hg rm -fA <placeholder-file> everytime a placeholder is to be deleted. The following command line will exactly do this:

$> MarkEmptyDirs.exe --create-hook="hg add §placeholder§" --delete-hook="hg rm -fA §placeholder§" PROJECT


CategoryTipsAndTricks

MarkEmptyDirs (last edited 2013-08-30 07:25:24 by Pierre-YvesDavid)