Skip to content

Commit 368af75

Browse files
committed
Initial commit
1 parent fef171d commit 368af75

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# svn-xattr
2+
A command-line utility to facilitate using the Subversion VCS to manage files with extended attributes (a.k.a. xattrs, metadata, macOS Resource Forks, macOS Rez, macOS File Type and Creator, AppleSingle, AppleDouble, Finder information, detritus).
3+
4+
## Example: storing a macOS Alias in a Subversion repo
5+
Say you've created a macOS Alias (created with Finder; a.k.a. Bookmark; not to be confused with symlink) called `my-alias` in your `working-copy` folder.
6+
7+
```bash
8+
cd working-copy
9+
svn add my-alias
10+
svn-xattr update my-alias
11+
svn commit
12+
```
13+
14+
Then, when checking out the repo:
15+
```bash
16+
svn update
17+
svn-xattr restore
18+
```

svn-xattr

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/php
2+
<?php
3+
4+
$app = basename($argv[0]);
5+
array_shift($argv);
6+
$command = $argv[0] ?? '';
7+
array_shift($argv);
8+
9+
if ($command === 'update') {
10+
// For each argument (which may or may not be a glob):
11+
foreach ($argv as $glob) {
12+
foreach (glob($glob) as $file) {
13+
// Get the names of all xattrs for this file.
14+
$attrs = [];
15+
exec('/usr/bin/xattr ' . escapeshellarg($file), $attrs, $exitCode);
16+
if ($exitCode)
17+
die("Error: xattr exited with non-zero status $exitCode.\n" . implode("\n", $attrs));
18+
19+
foreach ($attrs as $attr) {
20+
if (in_array($attr, [
21+
'com.apple.lastuseddate#PS',
22+
]))
23+
continue;
24+
25+
// Get the value of this xattr.
26+
$value = [];
27+
exec('/usr/bin/xattr -p ' . escapeshellarg($attr) . ' ' . escapeshellarg($file), $value, $exitCode);
28+
if ($exitCode)
29+
die("Error: xattr exited with non-zero status $exitCode.\n" . implode("\n", $value));
30+
31+
// Store the value as a Subversion property.
32+
system('svn propset ' . escapeshellarg('xattr:' . $attr) . ' ' . escapeshellarg(implode(' ', $value)) . ' ' . escapeshellarg($file));
33+
}
34+
}
35+
}
36+
}
37+
38+
elseif ($command === 'restore') {
39+
// Use Subversion's `wc.db` as an efficient way
40+
// to find all files with Subversion xattr:* properties.
41+
$wcRoot = exec('svn info --show-item wc-root');
42+
if (!is_dir($wcRoot))
43+
die("Error: Can't find the root of the working copy.\n");
44+
45+
$wcDBPath = "$wcRoot/.svn/wc.db";
46+
$files = [];
47+
exec('/usr/bin/sqlite3 ' . escapeshellarg($wcDBPath) . ' "SELECT local_relpath FROM nodes_current WHERE properties LIKE \'%xattr:%\'"', $files, $exitCode);
48+
if ($exitCode)
49+
die("Error: sqlite3 exited with non-zero status $exitCode.\n" . implode("\n", $files));
50+
51+
foreach ($files as $file) {
52+
$filePath = "$wcRoot/$file";
53+
54+
// Get the names of all xattrs for this file.
55+
$attrs = [];
56+
exec('svn proplist ' . escapeshellarg($filePath) . ' | fgrep xattr:', $attrs, $exitCode);
57+
if ($exitCode)
58+
die("Error: svn exited with non-zero status $exitCode.\n" . implode("\n", $attrs));
59+
60+
foreach ($attrs as $attr) {
61+
$attr = trim($attr);
62+
63+
// Get the value of this xattr.
64+
$value = [];
65+
exec('svn propget ' . escapeshellarg($attr) . ' ' . escapeshellarg($filePath), $value, $exitCode);
66+
if ($exitCode)
67+
die("Error: svn exited with non-zero status $exitCode.\n" . implode("\n", $value));
68+
69+
// Apply the value to the file in the working copy.
70+
echo "$file: applying $attr\n";
71+
system('xattr -v -w -x ' . escapeshellarg(substr($attr, strlen('xattr:'))) . ' ' . escapeshellarg(implode(' ', $value)) . ' ' . escapeshellarg($filePath));
72+
}
73+
}
74+
}
75+
76+
else {
77+
$spc = str_repeat(' ', strlen($app));
78+
die("Usage:
79+
80+
$app update [file …] — Adds or updates Subversion xattr:* properties for the specified file(s).
81+
$spc Ignores `com.apple.lastuseddate#PS`.
82+
83+
$app restore — Recursively applies Subversion xattr:* properties to files in the working copy.\n");
84+
}

0 commit comments

Comments
 (0)