hsync-cli 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.js +47 -17
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -68316,10 +68316,12 @@ class LocalScanner {
68316
68316
  excludePatterns;
68317
68317
  respectGitignore;
68318
68318
  ignoreRules;
68319
+ includeBases;
68319
68320
  constructor(localPath, filePatterns, excludePatterns, respectGitignore = false) {
68320
68321
  this.localPath = localPath;
68321
68322
  this.filePatterns = filePatterns || [];
68322
68323
  this.excludePatterns = excludePatterns || [];
68324
+ this.includeBases = this.filePatterns.map((p) => import_micromatch.default.scan(p).base);
68323
68325
  this.respectGitignore = respectGitignore;
68324
68326
  this.ignoreRules = respectGitignore ? [{ base: "", glob: "**/.git", negate: false, dirOnly: true }] : [];
68325
68327
  }
@@ -68355,7 +68357,15 @@ class LocalScanner {
68355
68357
  return results;
68356
68358
  }
68357
68359
  async walk(dirPath, results) {
68358
- const entries = await fs2.readdir(dirPath, { withFileTypes: true });
68360
+ let entries;
68361
+ try {
68362
+ entries = await fs2.readdir(dirPath, { withFileTypes: true });
68363
+ } catch (err) {
68364
+ if (err.code !== "EACCES" && err.code !== "EPERM")
68365
+ throw err;
68366
+ console.warn(`[LocalScanner] Skipping unreadable folder: ${dirPath}`);
68367
+ return;
68368
+ }
68359
68369
  if (this.respectGitignore && entries.some((e) => e.isFile() && e.name === ".gitignore")) {
68360
68370
  this.ignoreRules.push(...parseGitignore(await fs2.readFile(path3.join(dirPath, ".gitignore"), "utf8"), path3.relative(this.localPath, dirPath).split(path3.sep).join("/")));
68361
68371
  }
@@ -68363,7 +68373,11 @@ class LocalScanner {
68363
68373
  const fullPath = path3.join(dirPath, entry.name);
68364
68374
  const relativePath = path3.relative(this.localPath, fullPath);
68365
68375
  if (entry.isDirectory()) {
68366
- if (!matchesRules(this.ignoreRules, relativePath.split(path3.sep).join("/"), true)) {
68376
+ const dir = relativePath.split(path3.sep).join("/");
68377
+ if (this.includeBases.length > 0 && !this.includeBases.some((b) => b === "" || b === dir || b.startsWith(dir + "/") || dir.startsWith(b + "/"))) {
68378
+ continue;
68379
+ }
68380
+ if (!matchesRules(this.ignoreRules, dir, true)) {
68367
68381
  await this.walk(fullPath, results);
68368
68382
  }
68369
68383
  continue;
@@ -68409,9 +68423,8 @@ class RemoteClient {
68409
68423
  const response = await this.client.get(`/api/buckets/${slug}/files/tree`, {
68410
68424
  params: { path: cleanPath }
68411
68425
  });
68412
- const isSingleFile = response.data.files.length === 1 && response.data.files[0].path === cleanPath && !response.data.files[0].isDirectory;
68413
- if (isSingleFile) {
68414
- const f = response.data.files[0];
68426
+ const f = response.data.files.find((file) => file.path === cleanPath && !file.isDirectory);
68427
+ if (cleanPath && f) {
68415
68428
  return [
68416
68429
  {
68417
68430
  path: "",
@@ -68422,7 +68435,7 @@ class RemoteClient {
68422
68435
  ];
68423
68436
  }
68424
68437
  const prefix = cleanPath ? cleanPath + "/" : "";
68425
- return response.data.files.filter((f) => !f.isDirectory).map((f) => ({
68438
+ return response.data.files.filter((f) => !f.isDirectory && f.path.startsWith(prefix)).map((f) => ({
68426
68439
  path: prefix ? f.path.slice(prefix.length) : f.path,
68427
68440
  hash: f.hash || "",
68428
68441
  size: f.size,
@@ -70437,13 +70450,14 @@ async function push(localPath, remoteTarget, options) {
70437
70450
  const remoteClient = new RemoteClient(serverUrl, apiKey);
70438
70451
  const remoteFiles = await remoteClient.getTree(remote.slug, remote.remotePath);
70439
70452
  spinner.stop();
70453
+ const isFileToFile = !!remote.remotePath && (await fs6.stat(resolvedLocalPath)).isFile() && (remoteFiles.length === 1 && remoteFiles[0].path === "" || remoteFiles.length === 0 && path8.posix.basename(remote.remotePath) === localFiles[0].relativePath);
70440
70454
  console.log(source_default.cyan(`Found ${localFiles.length} local files, ${remoteFiles.length} remote files.`));
70441
70455
  const prompter = new OverwritePrompter(forceYes);
70442
70456
  let pushCount = 0;
70443
70457
  let skipCount = 0;
70444
70458
  for (const localFile of localFiles) {
70445
- const remoteFile = remoteFiles.find((f) => f.path === localFile.relativePath);
70446
- const destinationPath = remote.remotePath ? `${remote.remotePath}/${localFile.relativePath}` : localFile.relativePath;
70459
+ const remoteFile = remoteFiles.find((f) => f.path === (isFileToFile ? "" : localFile.relativePath));
70460
+ const destinationPath = isFileToFile ? remote.remotePath : remote.remotePath ? `${remote.remotePath}/${localFile.relativePath}` : localFile.relativePath;
70447
70461
  let shouldUpload = false;
70448
70462
  if (!remoteFile) {
70449
70463
  shouldUpload = true;
@@ -70491,8 +70505,24 @@ async function pull(remoteTarget, localPath, options) {
70491
70505
  const remoteClient = new RemoteClient(serverUrl, apiKey);
70492
70506
  const remoteFiles = await remoteClient.getTree(remote.slug, remote.remotePath);
70493
70507
  spinner.text = "Scanning local files...";
70494
- await fs6.mkdir(resolvedLocalPath, { recursive: true });
70495
- const localFiles = await scanLocalPath(resolvedLocalPath, resolvedLocalPath);
70508
+ let singleFileDest = "";
70509
+ let localFiles = [];
70510
+ if (remoteFiles.length === 1 && remoteFiles[0].path === "") {
70511
+ singleFileDest = resolvedLocalPath;
70512
+ let isDir = localPath.endsWith("/");
70513
+ try {
70514
+ isDir = isDir || (await fs6.stat(resolvedLocalPath)).isDirectory();
70515
+ } catch {}
70516
+ if (isDir) {
70517
+ singleFileDest = path8.join(resolvedLocalPath, path8.posix.basename(remote.remotePath));
70518
+ }
70519
+ try {
70520
+ localFiles = [{ ...(await scanLocalPath(singleFileDest, singleFileDest))[0], relativePath: "" }];
70521
+ } catch {}
70522
+ } else {
70523
+ await fs6.mkdir(resolvedLocalPath, { recursive: true });
70524
+ localFiles = await scanLocalPath(resolvedLocalPath, resolvedLocalPath);
70525
+ }
70496
70526
  spinner.stop();
70497
70527
  console.log(source_default.cyan(`Found ${remoteFiles.length} remote files, ${localFiles.length} local files.`));
70498
70528
  const prompter = new OverwritePrompter(forceYes);
@@ -70500,13 +70530,13 @@ async function pull(remoteTarget, localPath, options) {
70500
70530
  let skipCount = 0;
70501
70531
  for (const remoteFile of remoteFiles) {
70502
70532
  const localFile = localFiles.find((f) => f.relativePath === remoteFile.path);
70503
- const localDestPath = path8.join(resolvedLocalPath, remoteFile.path);
70504
- const sourcePath = remote.remotePath ? `${remote.remotePath}/${remoteFile.path}` : remoteFile.path;
70533
+ const localDestPath = singleFileDest || path8.join(resolvedLocalPath, remoteFile.path);
70534
+ const sourcePath = singleFileDest ? remote.remotePath : remote.remotePath ? `${remote.remotePath}/${remoteFile.path}` : remoteFile.path;
70505
70535
  let shouldDownload = false;
70506
70536
  if (!localFile) {
70507
70537
  shouldDownload = true;
70508
70538
  } else if (localFile.hash !== remoteFile.hash) {
70509
- const confirm = await prompter.shouldOverwrite(remoteFile.path);
70539
+ const confirm = await prompter.shouldOverwrite(remoteFile.path || remote.remotePath);
70510
70540
  if (confirm) {
70511
70541
  shouldDownload = true;
70512
70542
  } else {
@@ -70516,13 +70546,13 @@ async function pull(remoteTarget, localPath, options) {
70516
70546
  skipCount++;
70517
70547
  }
70518
70548
  if (shouldDownload) {
70519
- const fileSpinner = ora2(`Pulling ${remoteFile.path}...`).start();
70549
+ const fileSpinner = ora2(`Pulling ${remoteFile.path || remote.remotePath}...`).start();
70520
70550
  try {
70521
70551
  await remoteClient.downloadFile(remote.slug, sourcePath, localDestPath);
70522
- fileSpinner.succeed(source_default.green(`Pulled ${remoteFile.path}`));
70552
+ fileSpinner.succeed(source_default.green(`Pulled ${remoteFile.path || remote.remotePath}`));
70523
70553
  pullCount++;
70524
70554
  } catch (downloadErr) {
70525
- fileSpinner.fail(source_default.red(`Failed to pull ${remoteFile.path}: ${downloadErr.message}`));
70555
+ fileSpinner.fail(source_default.red(`Failed to pull ${remoteFile.path || remote.remotePath}: ${downloadErr.message}`));
70526
70556
  }
70527
70557
  }
70528
70558
  }
@@ -71488,7 +71518,7 @@ Press Ctrl+C to stop the server...
71488
71518
  // package.json
71489
71519
  var package_default = {
71490
71520
  name: "hsync-cli",
71491
- version: "1.1.5",
71521
+ version: "1.1.7",
71492
71522
  description: "hsync CLI for file sync operations",
71493
71523
  bin: {
71494
71524
  hsync: "./dist/bin.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hsync-cli",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "hsync CLI for file sync operations",
5
5
  "bin": {
6
6
  "hsync": "./dist/bin.js"