-
Notifications
You must be signed in to change notification settings - Fork 0
feature/demrum 1571 dsym extensions #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
74fec5c
f5c84a1
2076a5c
bd0d542
e967b8b
a060ba2
6173c7c
0b35284
12ab4b9
2e01418
2f35d1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ | |
|
||
import { tmpdir } from 'os'; | ||
import { execSync } from 'child_process'; | ||
import { join, resolve } from 'path'; | ||
import { join, resolve, basename, dirname } from 'path'; | ||
import { copyFileSync, mkdtempSync, readdirSync, rmSync, statSync } from 'fs'; | ||
import { UserFriendlyError, throwAsUserFriendlyErrnoException } from '../utils/userFriendlyErrors'; | ||
|
||
|
@@ -26,21 +26,101 @@ import { UserFriendlyError, throwAsUserFriendlyErrnoException } from '../utils/u | |
export function validateDSYMsPath(dsymsPath: string): string { | ||
const absPath = resolve(dsymsPath); | ||
|
||
if (!absPath.endsWith('dSYMs')) { | ||
throw new UserFriendlyError(null, `Invalid input: Expected a path ending in 'dSYMs'.`); | ||
if (absPath.endsWith('/dSYMs') || absPath === 'dSYMs') { | ||
try { | ||
const stats = statSync(absPath); | ||
if (!stats.isDirectory()) { | ||
throw new UserFriendlyError(null, `Invalid input: Expected a 'dSYMs/' directory but got a file.`); | ||
} | ||
} catch (err) { | ||
throwAsUserFriendlyErrnoException(err, { | ||
ENOENT: `Path not found: Ensure the provided directory exists before re-running.`, | ||
}); | ||
} | ||
return absPath; | ||
} | ||
|
||
try { | ||
const stats = statSync(absPath); | ||
if (!stats.isDirectory()) { | ||
throw new UserFriendlyError(null, `Invalid input: Expected a 'dSYMs/' directory but got a file.`); | ||
if (absPath.endsWith('.dSYM.zip') || absPath.endsWith('.dSYMs.zip')) { | ||
try { | ||
const stats = statSync(absPath); | ||
if (!stats.isFile()) { | ||
throw new UserFriendlyError(null, `Invalid input: Expected a '.dSYM.zip' or '.dSYMs.zip' file.`); | ||
} | ||
} catch (err) { | ||
throwAsUserFriendlyErrnoException(err, { | ||
ENOENT: `File not found: Ensure the provided file [${absPath}] exists before re-running.`, | ||
}); | ||
} | ||
} catch (err) { | ||
throwAsUserFriendlyErrnoException(err, { | ||
ENOENT: `Path not found: Ensure the provided directory exists before re-running.`, | ||
}); | ||
return absPath; | ||
} | ||
return absPath; | ||
|
||
if (absPath.endsWith('.dSYM')) { | ||
try { | ||
const stats = statSync(absPath); | ||
if (!stats.isDirectory()) { | ||
throw new UserFriendlyError(null, `Invalid input: Expected a '.dSYM' directory but got a file.`); | ||
} | ||
} catch (err) { | ||
throwAsUserFriendlyErrnoException(err, { | ||
ENOENT: `Directory not found: Ensure the provided directory exists before re-running.`, | ||
}); | ||
} | ||
return absPath; | ||
} | ||
|
||
throw new UserFriendlyError(null, `Invalid input: Expected a path named 'dSYMs' or ending in '.dSYM', '.dSYMs.zip', or '.dSYM.zip'.`); | ||
} | ||
|
||
/** | ||
* Given a dSYMs path, process the input as per the specified format and return | ||
* the zipped files or copied files as necessary. | ||
**/ | ||
export function getZippedDSYMs(dsymsPath: string): { zipFiles: string[], uploadPath: string } { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd consider adding debug logging in a function like this, to provide some level of visibility into what the tool is zipping together based on the command options. I added logging to a similar command for sourcemaps that traverses file system and operates on some specific files under some specific conditions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea. I've added it with logger.info() at the moment which gives us at least the imports and access to the logger object to enhance it more with logger.debug() in case of errors -- it's only used in one spot but please let me know if it maps to what you had in mind. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's along the lines of what I was thinking: log the results of the directory scanning so we can clearly show what files are getting touched. Since in cases like this (and I'd suggest logging in the next for-loop, too (line 92), for similar reasons. That way we could clearly see the other files that we found and are operating on. Not sure if logger.info() or logger.debug() is more appropriate. Originally, I was thinking a debug log would be nice in the other And |
||
const absPath = validateDSYMsPath(dsymsPath); | ||
|
||
// Create a unique system temp directory for storing zip files | ||
const uploadPath = mkdtempSync(join(tmpdir(), 'splunk_dSYMs_upload_')); | ||
|
||
if (absPath.endsWith('dSYMs')) { | ||
const { dSYMDirs, dSYMZipFiles } = scanDSYMsDirectory(absPath); | ||
const results: string[] = []; | ||
|
||
for (const dSYMDir of dSYMDirs) { | ||
results.push(zipDSYMDirectory(absPath, dSYMDir, uploadPath)); | ||
} | ||
|
||
for (const zipFile of dSYMZipFiles) { | ||
const srcPath = join(absPath, zipFile); | ||
const destPath = join(uploadPath, zipFile); | ||
try { | ||
copyFileSync(srcPath, destPath); | ||
} catch (err) { | ||
throwAsUserFriendlyErrnoException(err, { | ||
ENOENT: `Failed to copy ${srcPath} to ${destPath}. Please ensure the file exists and is not in use.`, | ||
EACCES: `Permission denied while copying ${srcPath}. Please check your access rights.`, | ||
}); | ||
} | ||
results.push(destPath); | ||
} | ||
|
||
return { zipFiles: results, uploadPath }; | ||
} else if (absPath.endsWith('.dSYM.zip') || absPath.endsWith('.dSYMs.zip')) { | ||
const destPath = join(uploadPath, basename(absPath)); | ||
try { | ||
copyFileSync(absPath, destPath); | ||
} catch (err) { | ||
throwAsUserFriendlyErrnoException(err, { | ||
ENOENT: `Failed to copy ${absPath} to ${destPath}. Please ensure the file exists and is not in use.`, | ||
EACCES: `Permission denied while copying ${absPath}. Please check your access rights.`, | ||
}); | ||
} | ||
return { zipFiles: [destPath], uploadPath }; | ||
} else if (absPath.endsWith('.dSYM')) { | ||
const zipPath = zipDSYMDirectory(dirname(absPath), basename(absPath), uploadPath); | ||
return { zipFiles: [zipPath], uploadPath }; | ||
} | ||
|
||
throw new UserFriendlyError(null, `Unexpected error with the provided input path.`); | ||
} | ||
|
||
/** | ||
|
@@ -100,51 +180,3 @@ export function cleanupTemporaryZips(uploadPath: string): void { | |
console.warn(`Warning: Failed to remove temporary directory '${uploadPath}'.`, err); | ||
} | ||
} | ||
|
||
/** | ||
* Given a dSYMs/ directory path, visit the contents of the directory and gather | ||
* zipped copies of all the .dSYM/ directories it contains, including .dSYM/ | ||
* directories that were already zipped before we arrived. If both a .dSYM/ and | ||
* its corresponding .dSYM.zip file exist, make a fresh .zip; if only the .zip | ||
* exists, accept the .zip file. Put files (or, in the case of existing .zips, | ||
* copies of them) in a temp dir `uploadPath`, then return the full list `zipFiles` | ||
* of all .zip files placed there, along with the path to the temp dir itself. | ||
**/ | ||
export function getZippedDSYMs(dsymsPath: string): { zipFiles: string[], uploadPath: string } { | ||
const absPath = validateDSYMsPath(dsymsPath); | ||
const { dSYMDirs, dSYMZipFiles } = scanDSYMsDirectory(absPath); | ||
|
||
// Create a unique system temp directory for storing zip files | ||
const uploadPath = mkdtempSync(join(tmpdir(), 'splunk_dSYMs_upload_')); | ||
|
||
const results: string[] = []; | ||
|
||
// Build a Set of `*.dSYM.zip` filenames without the `.zip` extension for quick lookup | ||
const existingZipBasenames = new Set(dSYMZipFiles.map(f => f.replace(/\.zip$/, ''))); | ||
|
||
for (const dSYMDir of dSYMDirs) { | ||
results.push(zipDSYMDirectory(absPath, dSYMDir, uploadPath)); | ||
} | ||
|
||
for (const zipFile of dSYMZipFiles) { | ||
const baseName = zipFile.replace(/\.zip$/, ''); | ||
if (!existingZipBasenames.has(baseName)) { | ||
// Only copy *.dSYM.zip files that don't have a corresponding *.dSYM/ directory | ||
const srcPath = join(absPath, zipFile); | ||
const destPath = join(uploadPath, zipFile); | ||
try { | ||
copyFileSync(srcPath, destPath); | ||
} catch (err) { | ||
throwAsUserFriendlyErrnoException(err, { | ||
ENOENT: `Failed to copy ${srcPath} to ${destPath}. Please ensure the file exists and is not in use.`, | ||
EACCES: `Permission denied while copying ${srcPath}. Please check your access rights.`, | ||
}); | ||
} | ||
results.push(destPath); | ||
} | ||
} | ||
|
||
return { zipFiles: results, uploadPath }; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The option is named
--directory
, but it can take a file, too.--path
would work better, is there any other alternative? Other commands in CLI don't use--path
option right now, they only use--directory
or--file
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hah good point... --path sounds good to me unless we want the extra sort of runtime type check of having two different ones. I could go either way, have both --file and --directory with checks, or just --path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just --path is going to be more simple to present in the usage message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated