solanaCli.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { Language } from './getLanguage';
  2. import { RenderContext } from './getRenderContext';
  3. import {
  4. hasCommand,
  5. readStdout,
  6. spawnCommand,
  7. waitForCommand,
  8. } from './runCommands';
  9. export async function detectSolanaVersion(language: Language): Promise<string> {
  10. const hasSolanaCli = await hasCommand('solana');
  11. if (!hasSolanaCli) {
  12. throw new Error(
  13. language.errors.solanaCliNotFound.replace('$command', 'solana')
  14. );
  15. }
  16. const child = spawnCommand('solana', ['--version']);
  17. const [stdout] = await Promise.all([
  18. readStdout(child),
  19. waitForCommand(child),
  20. ]);
  21. const version = stdout.join('').match(/(\d+\.\d+\.\d+)/)?.[1];
  22. return version!;
  23. }
  24. export async function detectAnchorVersion(language: Language): Promise<string> {
  25. const hasAnchorCli = await hasCommand('anchor');
  26. if (!hasAnchorCli) {
  27. throw new Error(
  28. language.errors.solanaCliNotFound.replace('$command', 'anchor')
  29. );
  30. }
  31. const child = spawnCommand('anchor', ['--version']);
  32. const [stdout] = await Promise.all([
  33. readStdout(child),
  34. waitForCommand(child),
  35. ]);
  36. const version = stdout.join('').match(/(\d+\.\d+\.\d+)/)?.[1];
  37. return version!;
  38. }
  39. export async function patchSolanaDependencies(
  40. ctx: Pick<RenderContext, 'solanaVersion' | 'targetDirectory'>
  41. ): Promise<void> {
  42. const patchMap: Record<string, string[]> = {
  43. '1.17': ['-p ahash@0.8 --precise 0.8.6'],
  44. };
  45. const patches = patchMap[ctx.solanaVersion] ?? [];
  46. await Promise.all(
  47. patches.map((patch) =>
  48. waitForCommand(
  49. spawnCommand('cargo', ['update', ...patch.split(' ')], {
  50. cwd: ctx.targetDirectory,
  51. })
  52. )
  53. )
  54. );
  55. }
  56. export function toMinorSolanaVersion(
  57. language: Language,
  58. version: string
  59. ): string {
  60. const validVersion = version.match(/^(\d+\.\d+)/);
  61. if (!validVersion) {
  62. throw new Error(
  63. language.errors.invalidSolanaVersion.replace('$version', version)
  64. );
  65. }
  66. return validVersion[0];
  67. }
  68. export async function generateKeypair(
  69. language: Language,
  70. outfile: string
  71. ): Promise<string> {
  72. const hasSolanaKeygen = await hasCommand('solana-keygen');
  73. if (!hasSolanaKeygen) {
  74. throw new Error(
  75. language.errors.solanaCliNotFound.replace('$command', 'solana-keygen')
  76. );
  77. }
  78. // Run the solana-keygen command to generate a new keypair.
  79. const child = spawnCommand('solana-keygen', [
  80. 'new',
  81. '--no-bip39-passphrase',
  82. '--outfile',
  83. outfile,
  84. ]);
  85. // Wait for the command to finish and read the stdout.
  86. const [stdout] = await Promise.all([
  87. readStdout(child),
  88. waitForCommand(child),
  89. ]);
  90. // Update the render context with the generated address.
  91. const address = stdout.join('').match(/pubkey: (\w+)/)?.[1];
  92. if (!address) {
  93. throw new Error(language.errors.solanaKeygenFailed);
  94. }
  95. return address;
  96. }