-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feat/rotate-catalyst-servers-to-retry
- Loading branch information
Showing
10 changed files
with
4,521 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,7 @@ contents | |
yarn-error.log | ||
.env.local | ||
*.log | ||
api/src/migrations | ||
api/src/migrations | ||
|
||
cli/textures-output | ||
cli/textures |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Command-Line Interface | ||
|
||
This workspace provides various methods for managing badges. Below is a list of available actions and instructions on how to execute them within this project. | ||
|
||
## Upload a badge texture | ||
|
||
This action uploads badge textures. Upon running the command, it will prompt the following: | ||
* The directory path where badge textures are stored (_directory containing directories with different badges' textures_) | ||
* AWS Programmatic User Access Keys | ||
|
||
Before proceeding, ensure that the badge texture directories follow the service’s naming and structural conventions: | ||
|
||
- **Directory Name**: It should match the badge ID, using lowercase letters and snake_case (e.g., `all_day_adventurer`). | ||
- **Directory Structure**: | ||
- Each directory should contain two subdirectories named `2d` and `3d` for storing textures in each format. | ||
- The `2d` subdirectory must contain a single file named `normal.png`. | ||
- The `3d` subdirectory should include three files: `basecolor.png`, `hrm.png`, and `normal.png`. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import prompts from 'prompts' | ||
import fs from 'fs' | ||
import path from 'path' | ||
import AWS from 'aws-sdk' | ||
import mime from 'mime-types' | ||
|
||
import { logAllFilesWithinDirectory, parseTexturesDirectoryName, trimBadgeName } from './utils' | ||
|
||
const outputDirectory = path.join(__dirname, '../../textures-output') | ||
|
||
const renameAndCopyFiles = (srcDir: string, destDir: string, badgeName: string) => { | ||
fs.readdir(srcDir, (err, files) => { | ||
if (err) throw err | ||
|
||
files.forEach((file) => { | ||
const srcFilePath = path.join(srcDir, file) | ||
const stat = fs.statSync(srcFilePath) | ||
|
||
if (stat.isDirectory()) { | ||
const trimmedName = trimBadgeName(file, badgeName) | ||
let newDirectoryName: string = parseTexturesDirectoryName(trimmedName) | ||
|
||
const match = trimmedName.match(/2d|3d/i) // Check for "2d" or "3d" | ||
if (match) { | ||
newDirectoryName = match[0].toLowerCase() // Force lowercase "2d" or "3d" | ||
console.log(`Matched special directory name: ${newDirectoryName}`) // Debug log | ||
} | ||
|
||
// If the directory is called "base", rename it to "starter" | ||
if (newDirectoryName === 'base') { | ||
newDirectoryName = 'starter' | ||
} | ||
|
||
const newDestDir = path.join(destDir, newDirectoryName) | ||
|
||
fs.mkdirSync(newDestDir, { recursive: true }) | ||
|
||
// Recursively process the directory | ||
renameAndCopyFiles(srcFilePath, newDestDir, badgeName) | ||
} else { | ||
if (file !== '.DS_Store') { | ||
let newFileName = file | ||
|
||
if (newFileName.includes('_basecolor')) { | ||
newFileName = 'basecolor.png' | ||
} else if (newFileName.includes('_hrm')) { | ||
newFileName = 'hrm.png' | ||
} else if (newFileName.includes('_normal') || newFileName.match(/\.png$/)) { | ||
newFileName = 'normal.png' | ||
} | ||
|
||
const destFilePath = path.join(destDir, newFileName) | ||
|
||
// Copy the file to the new location with the new name | ||
fs.copyFileSync(srcFilePath, destFilePath) | ||
} | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
const processDirectory = (srcRoot: string, destRoot: string) => { | ||
fs.mkdirSync(destRoot, { recursive: true }) | ||
|
||
fs.readdir(srcRoot, (err, directories) => { | ||
if (err) throw err | ||
|
||
directories.forEach((dir) => { | ||
const srcDirPath = path.join(srcRoot, dir) | ||
const stat = fs.statSync(srcDirPath) | ||
|
||
if (stat.isDirectory()) { | ||
const newDirName = parseTexturesDirectoryName(dir) | ||
const newDestDirPath = path.join(destRoot, newDirName) | ||
|
||
fs.mkdirSync(newDestDirPath, { recursive: true }) | ||
|
||
// Process each subdirectory within the badge directory | ||
renameAndCopyFiles(srcDirPath, newDestDirPath, dir) | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
export async function uploadTextures() { | ||
const directory = await prompts({ | ||
type: 'text', | ||
name: 'src', | ||
message: 'Enter the directory holding the textures (src):' | ||
}) | ||
|
||
processDirectory(directory.src, outputDirectory) | ||
logAllFilesWithinDirectory(outputDirectory) | ||
|
||
const shouldWeContinue = await prompts({ | ||
type: 'confirm', | ||
name: 'continue', | ||
message: 'Do you want to continue?' | ||
}) | ||
|
||
if (!shouldWeContinue.continue) { | ||
console.log('Removing textures output directory...') | ||
fs.rmdirSync(outputDirectory, { recursive: true }) | ||
return | ||
} else { | ||
// select bucket from two options | ||
const selection = await prompts({ | ||
type: 'select', | ||
name: 'bucket', | ||
message: 'Select the S3 bucket environment:', | ||
choices: [ | ||
{ title: 'prd', value: 'assets-cdn-decentraland-org-contentbucket-6898728' }, | ||
{ title: 'dev', value: 'assets-cdn-decentraland-zone-contentbucket-79cb984' } | ||
] | ||
}) | ||
|
||
const awsAccessKeyId = await prompts({ | ||
type: 'text', | ||
name: 'key', | ||
message: 'Enter your AWS Access Key ID:' | ||
}) | ||
|
||
const awsSecretAccessKey = await prompts({ | ||
type: 'text', | ||
name: 'key', | ||
message: 'Enter your AWS Secret Access Key:' | ||
}) | ||
|
||
const s3 = new AWS.S3({ | ||
accessKeyId: awsAccessKeyId.key, | ||
secretAccessKey: awsSecretAccessKey.key, | ||
region: 'us-east-1' // default region, do not change | ||
}) | ||
|
||
await uploadDirectory(s3, selection.bucket, outputDirectory) | ||
} | ||
} | ||
|
||
const uploadDirectory = async (s3Client: AWS.S3, bucketName: string, dirPath: string, s3Folder: string = '') => { | ||
console.log('Uploading textures...') | ||
|
||
const files = fs.readdirSync(dirPath) | ||
|
||
for (const fileName of files) { | ||
if (fileName && fileName === '.DS_Store') { | ||
continue | ||
} | ||
|
||
const fullPath = path.join(dirPath, fileName) | ||
const fileStats = fs.statSync(fullPath) | ||
|
||
if (fileStats.isDirectory()) { | ||
// Recursively upload inner directories | ||
await uploadDirectory(s3Client, bucketName, fullPath, `${s3Folder}${fileName}/`) | ||
} else { | ||
const fileContent = fs.readFileSync(fullPath) | ||
const mimeType = mime.lookup(fullPath) || 'application/octet-stream' | ||
|
||
const params = { | ||
Bucket: bucketName, | ||
Key: `${s3Folder}${fileName}`, | ||
Body: fileContent, | ||
ContentType: mimeType | ||
} | ||
|
||
await s3Client.upload(params).promise() | ||
console.log(`Uploaded ${fileName} to ${bucketName}/${s3Folder}${fileName}`) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './textures-manager-utils' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
|
||
function is2dOr3dDirectoryName(directoryName: string): boolean { | ||
return ( | ||
directoryName === '2d' || | ||
directoryName === '3d' || | ||
directoryName.includes('2d') || | ||
(directoryName.includes('3d') && | ||
(directoryName.includes('starter') || | ||
directoryName.includes('bronze') || | ||
directoryName.includes('silver') || | ||
directoryName.includes('gold') || | ||
directoryName.includes('platinum') || | ||
directoryName.includes('diamond') || | ||
directoryName.includes('base'))) | ||
) | ||
} | ||
|
||
export function parseTexturesDirectoryName(directoryName: string): string { | ||
return is2dOr3dDirectoryName(directoryName) | ||
? directoryName | ||
: directoryName | ||
.replace(/([a-z])([A-Z])/g, '$1_$2') // Convert PascalCase to snake_case | ||
.replace(/([a-zA-Z])(\d)/g, '$1_$2') // Add underscore between letters and numbers | ||
.replace(/(\d)([a-zA-Z])/g, '$1_$2') // Add underscore between numbers and letters | ||
.toLowerCase() | ||
} | ||
|
||
export function trimBadgeName(name: string, badgeName: string): string { | ||
return name.replace(new RegExp(`^${badgeName}`, 'i'), '').toLowerCase() | ||
} | ||
|
||
export function logAllFilesWithinDirectory(directoryPath: string): void { | ||
fs.readdirSync(directoryPath).forEach((file) => { | ||
if (fs.statSync(path.join(directoryPath, file)).isDirectory()) { | ||
console.log(`Directory: ${file}`) | ||
logAllFilesWithinDirectory(path.join(directoryPath, file)) | ||
} else { | ||
console.log(`File: ${file}`) | ||
} | ||
}) | ||
} |
Oops, something went wrong.