Skip to content

Commit

Permalink
fix(std/utils/patch): preserve xattrs on linux
Browse files Browse the repository at this point in the history
- add test verifying xattrs are preserved
- bump file_cmds version, cleanup implementation
- add patch_cmds build for macOS that does not preserve
  • Loading branch information
deciduously committed Dec 3, 2024
1 parent fab0654 commit f533c75
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 18 deletions.
19 changes: 3 additions & 16 deletions packages/std/utils/file_cmds.tg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import * as std from "../tangram.ts";

export const metadata = {
name: "file_cmds",
version: "430.100.5",
version: "448.0.3",
};

export const source = tg.target(async () => {
const { name, version } = metadata;
const checksum =
"sha256:035272979817edb250e3527b95a028e59b5bff546a13346c4a4e0e83c4d7ac20";
"sha256:d5cf241a751a9d36f43a4cd759d06835f4346c3150c62147a05c7bdec67b057c";
const owner = "apple-oss-distributions";
const repo = "file_cmds";
const tag = std.download.packageName({ name, version });
Expand Down Expand Up @@ -84,31 +84,18 @@ export const compileUtil = async (arg: UtilArg) => {
// Grab args.
const { destDir, fileName, utilName, utilSource } = arg;

// Grab prerequisites.
const dashArtifact = await bootstrap.shell(host);
const toolchainArtifact = await bootstrap.toolchain(host);
const macOsSdk = await bootstrap.macOsSdk();

// Compile the util.
const script =
arg.script ??
(await tg`
cc -Oz -o $OUTPUT ${utilSource}/${fileName}
`);

const dependencies = [toolchainArtifact, dashArtifact];

const util = tg.File.expect(
await (
await tg.target(await tg.template(script), {
host: std.triple.archAndOs(build),
env: std.env.arg(
arg.env ?? {},
{
SDKROOT: macOsSdk,
},
...dependencies,
),
env: std.env.arg(arg.env ?? {}, bootstrap.sdk.env(host)),
})
).output(),
);
Expand Down
118 changes: 116 additions & 2 deletions packages/std/utils/patch.tg.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import * as bootstrap from "../bootstrap.tg.ts";
import * as std from "../tangram.ts";
import { buildUtil, prerequisites } from "../utils.tg.ts";
import attr from "./attr.tg.ts";
import libiconv from "./libiconv.tg.ts";
import coreutils from "./coreutils.tg.ts";
import diffutils from "./diffutils.tg.ts";
import rlimitFix from "./patch-rlimit-fix.patch" with { type: "file" };
import macOsPatchCmds from "./patch_cmds.tg.ts";

export const metadata = {
name: "patch",
Expand Down Expand Up @@ -43,11 +48,30 @@ export const build = tg.target(async (arg?: Arg) => {
const host = host_ ?? (await std.triple.host());
const build = build_ ?? host;

if (std.triple.os(host) === "darwin") {
return macOsPatchCmds(arg);
}

const configure = {
args: ["--disable-dependency-tracking"],
};

const env = std.env.arg(env_, prerequisites(build));
const dependencies: tg.Unresolved<std.Args<std.env.Arg>> = [
prerequisites(build),
];
if (std.triple.os(host) === "linux") {
dependencies.push(
attr({
build,
env: env_,
host,
sdk,
staticBuild: false,
usePrerequisites: true,
}),
);
}
const env = std.env.arg(env_, ...dependencies);

const output = buildUtil({
...(await std.triple.rotate({ build, host })),
Expand All @@ -65,5 +89,95 @@ export default build;
export const test = tg.target(async () => {
const host = await bootstrap.toolchainTriple(await std.triple.host());
const sdk = await bootstrap.sdk(host);
return build({ host, sdk: false, env: sdk });
const system = std.triple.archAndOs(host);
const os = std.triple.os(system);
const patchArtifact = await build({ host, sdk: false, env: sdk });

// Ensure the installed command preserves xattrs.
let expected;
let script;
if (os === "linux") {
script = tg`
env
log() {
echo "$1" | tee -a "$OUTPUT"
}
# Create original file with content
echo "original content" > test-file.txt
log "Setting xattrs..."
setfattr -n user.tangram -v "test value" test-file.txt
log "Getting xattrs from original file:"
log "$(getfattr -n user.tangram test-file.txt)"
# Create modified version for patch
echo "modified content" > test-file-new.txt
diff -u test-file.txt test-file-new.txt > changes.patch
# Create test directory and copy original file
mkdir patch-test
cp test-file.txt patch-test/
# Apply patch
cd patch-test
log "Applying patch..."
patch < ../changes.patch
log "Getting xattrs from patched file:"
log "$(getfattr -n user.tangram test-file.txt)"
`;
expected = `Setting xattrs...\nGetting xattrs from original file:\n# file: test-file.txt\nuser.tangram="test value"\nApplying patch...\nGetting xattrs from patched file:\n# file: test-file.txt\nuser.tangram="test value"`;
} else if (os === "darwin") {
script = tg`
log() {
echo "$1" | tee -a "$OUTPUT"
}
# Create original file with content
echo "original content" > test-file.txt
log "Setting xattrs..."
xattr -w user.tangram "test value" test-file.txt
log "Getting xattrs from original file:"
log "$(xattr -p user.tangram test-file.txt)"
# Create modified version for patch
echo "modified content" > test-file-new.txt
diff -u test-file.txt test-file-new.txt > changes.patch
# Create test directory and copy original file
mkdir patch-test
cp test-file.txt patch-test/
# Apply patch
cd patch-test
log "Applying patch..."
patch < ../changes.patch
log "Getting xattrs from patched file:"
log "$(xattr -p user.tangram test-file.txt)"
`;
expected = `Setting xattrs...\nGetting xattrs from original file:\ntest value\nApplying patch...\nGetting xattrs from patched file:\ntest value`;
} else {
return tg.unreachable();
}
// Run the script.
const platformSupportLib =
os === "darwin"
? libiconv({ host, sdk: false, env: sdk })
: attr({ host, sdk: false, env: sdk });
const output = tg.File.expect(
await (
await tg.target(script, {
env: std.env.arg(
coreutils({ host, sdk: false, env: sdk }),
diffutils({ host, sdk: false, env: sdk }),
platformSupportLib,
patchArtifact,
),
})
).output(),
);

const contents = (await output.text()).trim();
tg.assert(contents === expected);

return patchArtifact;
});
80 changes: 80 additions & 0 deletions packages/std/utils/patch_cmds.tg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as bootstrap from "../bootstrap.tg.ts";
import * as std from "../tangram.ts";

export const metadata = {
name: "patch_cmds",
version: "66",
};

export const source = tg.target(async () => {
const { name, version } = metadata;
const checksum =
"sha256:ce39ccafd2690e1f7cf825d20043a42614814e6f7bc9f7638fbbec328a0f282d";
const owner = "apple-oss-distributions";
const repo = name;
const tag = std.download.packageName({ name, version });
return std.download.fromGithub({
checksum,
source: "tag",
owner,
repo,
tag,
});
});

export type Arg = {
build?: string | undefined;
env?: std.env.Arg;
host?: string | undefined;
sdk?: std.sdk.Arg | boolean;
source?: tg.Directory;
};

/** Produce an `patch` executable that preserves xattrs on macOS. */
export const macOsPatchCmds = tg.target(async (arg?: Arg) => {
const build = arg?.build ?? (await std.triple.host());
const os = std.triple.os(build);

// Assert that the system is macOS.
if (os !== "darwin") {
throw new Error(`patchCmds is only supported on macOS, detected ${os}.`);
}

const sourceDir = await source();

const script = tg`
set -eux
cp -R ${sourceDir}/patch/* .
CC="cc"
CFLAGS="-Wall -Oz"
SOURCES="backupfile.c inp.c mkpath.c pch.c util.c patch.c vcs.c"
OBJS=$(echo "$SOURCES" | sed 's/\.c$/\.o/')
for src in $SOURCES; do
obj=$(echo "$src" | sed 's/\.c$/\.o/')
$CC $CFLAGS -c "$src" -o "$obj"
if [ $? -ne 0 ]; then
echo "Error compiling $src"
exit 1
fi
done
mkdir -p $OUTPUT/bin
$CC $CFLAGS $OBJS -o $OUTPUT/bin/patch
if [ $? -ne 0 ]; then
echo "Linking failed"
exit 1
fi
rm -f $OBJS
`;

const result = await tg
.target(script, {
host: std.triple.archAndOs(build),
env: std.env.arg(arg.env ?? {}, bootstrap.sdk.env()),
})
.then((target) => target.output())
.then(tg.Directory.expect);

return result;
});

export default macOsPatchCmds;

0 comments on commit f533c75

Please sign in to comment.