@shoper/cli 0.1.0-29 → 0.1.0-30

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.
package/build/index.js CHANGED
@@ -47,3 +47,40 @@ export const COMMANDS = {
47
47
  ...THEME_COMMANDS
48
48
  };
49
49
  export { runCLI } from './cli/index.js';
50
+ /**
51
+ * Przetestowane na win
52
+ * oglne
53
+ * moduly:
54
+ * - stworzony w admince
55
+ * - pull w cli - v
56
+ * - updejt modulu w adminc i pull w cli - v
57
+ * - zmiana nazwy katalogu w cli, modzenie w admince i pull - v
58
+ * - kopiowanie stworzonego modulu w admince i push (usuniety id i code) - v
59
+ * - zminaa w cli i push - v
60
+ * - tworzenie modulu w cli, min plikow i push
61
+ * - aktualizowanie js/twig/settings/schema
62
+ * - zmiana w adminc i pull
63
+ * - usuwanie modulu z cli - v
64
+ * - usuwanie modulu z adminki - v
65
+ * - dodanie niedozwolonego pliku do folderu modulu
66
+ * - dodanie niedozwolonego pliku do folderu modules/
67
+ * - translacje - v
68
+ * macro:
69
+ * - dodawanie pliku do macros - v
70
+ * - usuniecie macro - v
71
+ * - modzneie makro - v
72
+ * - dodawanie customowego macro - v
73
+ * - push customowego macro - v
74
+ * - modzenie w admince i pull - v
75
+ * settingsy:
76
+ * - uzupelniania schemy w admince, pull w cli
77
+ * - uzupelnianie wartosci a admince i pull
78
+ * - modzenie w cli
79
+ * - usuniecie pliku w cli
80
+ * styles:
81
+ * - modzenie stylu w src - niedozwolone - v
82
+ * - modzenie custom - v
83
+ * - usuniecie custom - v
84
+ * - modzenie schema i settings - v
85
+ * dodanie czegos w .shoper
86
+ */
@@ -0,0 +1,174 @@
1
+ import { copyFile, fileExists, readJSONFile, readJSONFileSync, removeFile } from '../../../utils/fs/fs_utils.js';
2
+ import { ThemeChecksumsUtils } from './theme_checksums_utils.js';
3
+ import { isWindowsOs } from '../../../utils/platform_utils.js';
4
+ import { join, mapKeysPathsToWindowPlatform, toCurrentPlatformPath } from '../../../utils/path_utils.js';
5
+ import { createWriteStream } from 'node:fs';
6
+ import { JSON_FILE_INDENT } from '../../../cli/cli_constants.js';
7
+ import { ThemeChecksumsErrorFactory } from './theme_checksums_error_factory.js';
8
+ import { computeChecksumsFromFilesStructure, computeDirectoriesChecksums, computeFileChecksum } from '../../../utils/checksums/checksums_utils.js';
9
+ import { normalize } from 'node:path';
10
+ import { ThemePushUtils } from '../../../theme/features/theme/push/theme_push_utils.js';
11
+ import { SHOPER_THEME_METADATA_DIR } from '../../../theme/constants/directory_contstants.js';
12
+ import { THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME, THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME } from '../../../theme/features/theme/theme_constants.js';
13
+ export class ThemeChecksums {
14
+ #themeDir;
15
+ #currentChecksumsFilePath;
16
+ #currentChecksumsVerificationFilePath;
17
+ #initialChecksumsFilePath;
18
+ #initialChecksumsVerificationFilePath;
19
+ #initialChecksums;
20
+ #currentChecksums;
21
+ constructor(themeDir) {
22
+ this.#themeDir = themeDir;
23
+ this.#currentChecksumsFilePath = ThemeChecksumsUtils.getCurrentThemeChecksumsFilePath(themeDir);
24
+ this.#currentChecksumsVerificationFilePath = ThemeChecksumsUtils.getCurrentThemeChecksumsVerificationFilePath(themeDir);
25
+ this.#initialChecksumsFilePath = ThemeChecksumsUtils.getInitialThemeChecksumsFilePath(themeDir);
26
+ this.#initialChecksumsVerificationFilePath = ThemeChecksumsUtils.getInitialThemeChecksumsVerificationFilePath(themeDir);
27
+ }
28
+ async getInitialChecksums() {
29
+ if (this.#initialChecksums)
30
+ return this.#initialChecksums;
31
+ this.#initialChecksums = await this._getChecksums(this.#initialChecksumsFilePath);
32
+ return this.#initialChecksums;
33
+ }
34
+ getInitialChecksumsSync() {
35
+ if (this.#initialChecksums)
36
+ return this.#initialChecksums;
37
+ this.#initialChecksums = this._getChecksumsSync(this.#initialChecksumsFilePath);
38
+ return this.#initialChecksums;
39
+ }
40
+ async getCurrentChecksums() {
41
+ if (this.#currentChecksums)
42
+ return this.#currentChecksums;
43
+ this.#currentChecksums = await this._getChecksums(this.#currentChecksumsFilePath);
44
+ return this.#currentChecksums;
45
+ }
46
+ getCurrentChecksumsSync() {
47
+ if (this.#currentChecksums)
48
+ return this.#currentChecksums;
49
+ this.#currentChecksums = this._getChecksumsSync(this.#currentChecksumsFilePath);
50
+ return this.#currentChecksums;
51
+ }
52
+ async getCurrentChecksumFromPath(path) {
53
+ const checksums = await this.getCurrentChecksums();
54
+ return checksums[toCurrentPlatformPath(path)];
55
+ }
56
+ getCurrentChecksumFromPathSync(path) {
57
+ const checksums = this.getCurrentChecksumsSync();
58
+ return checksums[toCurrentPlatformPath(path)];
59
+ }
60
+ async getInitialChecksumFromPath(path) {
61
+ const checksums = await this.getInitialChecksums();
62
+ return checksums[toCurrentPlatformPath(path)];
63
+ }
64
+ getInitialChecksumFromPathSync(path) {
65
+ const checksums = this.getInitialChecksumsSync();
66
+ return checksums[toCurrentPlatformPath(path)];
67
+ }
68
+ async hasThemeBeenModified() {
69
+ const initialChecksums = await this._getInitialChecksumsVerification();
70
+ const currentChecksums = await this._getCurrentChecksumsVerification();
71
+ return !!initialChecksums && !!currentChecksums && initialChecksums !== currentChecksums;
72
+ }
73
+ async hasThemeFileBeenCreated(path) {
74
+ const initialChecksum = await this.getInitialChecksumFromPath(path);
75
+ return !initialChecksum && (await fileExists(join(this.#themeDir, path)));
76
+ }
77
+ async hasThemeFileBeenModified(path) {
78
+ const currentChecksum = await this.getCurrentChecksumFromPath(path);
79
+ const initialChecksum = await this.getInitialChecksumFromPath(path);
80
+ return !!currentChecksum && !!initialChecksum && currentChecksum !== initialChecksum;
81
+ }
82
+ async verify() {
83
+ const initialChecksumFilePath = this.#initialChecksumsFilePath;
84
+ const initialChecksumVerifyFilePath = this.#initialChecksumsVerificationFilePath;
85
+ const initialChecksum = await computeFileChecksum(initialChecksumFilePath);
86
+ const initialChecksumVerify = await readJSONFile(initialChecksumVerifyFilePath);
87
+ return initialChecksum === initialChecksumVerify;
88
+ }
89
+ async updateAllChecksums() {
90
+ const checksums = await this.computeThemeChecksums();
91
+ return new Promise((resolve, reject) => {
92
+ const currentChecksumFilePath = this.#currentChecksumsFilePath;
93
+ const initialChecksumFilePath = this.#initialChecksumsFilePath;
94
+ const checksumStream = createWriteStream(initialChecksumFilePath);
95
+ checksumStream.write(JSON.stringify(checksums, null, JSON_FILE_INDENT));
96
+ checksumStream.end();
97
+ checksumStream
98
+ .on('finish', async () => {
99
+ const initialChecksumVerifyFilePath = this.#initialChecksumsVerificationFilePath;
100
+ const currentChecksumVerifyFilePath = this.#currentChecksumsVerificationFilePath;
101
+ await this._createThemeChecksumVerifyFile(initialChecksumFilePath, initialChecksumVerifyFilePath);
102
+ await copyFile(initialChecksumFilePath, currentChecksumFilePath);
103
+ await copyFile(initialChecksumVerifyFilePath, currentChecksumVerifyFilePath);
104
+ resolve();
105
+ })
106
+ .on('error', async (err) => {
107
+ await removeFile(initialChecksumFilePath, { force: true });
108
+ reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack));
109
+ });
110
+ });
111
+ }
112
+ async updateCurrentChecksums() {
113
+ const checksums = await this.computeThemeChecksums();
114
+ return new Promise((resolve, reject) => {
115
+ const currentChecksumFilePath = this.#currentChecksumsFilePath;
116
+ const checksumStream = createWriteStream(currentChecksumFilePath);
117
+ checksumStream.write(JSON.stringify(checksums, null, JSON_FILE_INDENT));
118
+ checksumStream.end();
119
+ checksumStream
120
+ .on('finish', async () => {
121
+ const currentChecksumVerifyFilePath = this.#currentChecksumsVerificationFilePath;
122
+ await this._createThemeChecksumVerifyFile(currentChecksumFilePath, currentChecksumVerifyFilePath);
123
+ resolve();
124
+ })
125
+ .on('error', async (err) => {
126
+ await removeFile(currentChecksumFilePath, { force: true });
127
+ reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack));
128
+ });
129
+ });
130
+ }
131
+ async computeThemeChecksums() {
132
+ const filesToIgnoreInChecksums = [
133
+ join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_FILE_NAME),
134
+ join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME),
135
+ join(SHOPER_THEME_METADATA_DIR, THEME_INITIAL_CHECKSUMS_FILE_NAME),
136
+ join(SHOPER_THEME_METADATA_DIR, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME)
137
+ ];
138
+ const filesToComputeChecksums = (await ThemePushUtils.getAllFilesThatAreSendToRemote(this.#themeDir))
139
+ .filter((path) => !filesToIgnoreInChecksums.some((ignorePath) => normalize(path) === ignorePath))
140
+ .map((relativePath) => join(this.#themeDir, relativePath));
141
+ const { filesChecksumsInDirectories, filesChecksums } = await computeChecksumsFromFilesStructure(filesToComputeChecksums, this.#themeDir);
142
+ const directoriesChecksums = computeDirectoriesChecksums(filesChecksumsInDirectories);
143
+ return { ...filesChecksums, ...directoriesChecksums };
144
+ }
145
+ async _getInitialChecksumsVerification() {
146
+ return await readJSONFile(this.#initialChecksumsVerificationFilePath);
147
+ }
148
+ async _getCurrentChecksumsVerification() {
149
+ return await readJSONFile(this.#currentChecksumsVerificationFilePath);
150
+ }
151
+ async _getChecksums(path) {
152
+ const checksums = await readJSONFile(path);
153
+ if (!isWindowsOs())
154
+ return checksums;
155
+ return mapKeysPathsToWindowPlatform(checksums);
156
+ }
157
+ _getChecksumsSync(path) {
158
+ const checksums = readJSONFileSync(path);
159
+ if (!isWindowsOs())
160
+ return checksums;
161
+ return mapKeysPathsToWindowPlatform(checksums);
162
+ }
163
+ async _createThemeChecksumVerifyFile(checksumFilePath, checksumVerifyFullPath) {
164
+ const checksumVerifyStream = createWriteStream(checksumVerifyFullPath);
165
+ const checksumVerify = await computeFileChecksum(checksumFilePath);
166
+ checksumVerifyStream
167
+ .on('error', async (err) => {
168
+ await removeFile(checksumFilePath, { force: true });
169
+ throw ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack);
170
+ })
171
+ .write(JSON.stringify(checksumVerify));
172
+ checksumVerifyStream.end();
173
+ }
174
+ }
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
1
+ import { AppError } from '../../../cli/class/errors/app/app_error.js';
2
2
  export class ThemeChecksumsErrorFactory {
3
3
  static createThemeChecksumError(stack) {
4
4
  return new AppError({
@@ -0,0 +1,17 @@
1
+ import { join } from '../../../utils/path_utils.js';
2
+ import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../features/theme/theme_constants.js';
3
+ import { HiddenDirectoryUtils } from '../../features/theme/utils/hidden_directory/hidden_directory_utils.js';
4
+ export class ThemeChecksumsUtils {
5
+ static getCurrentThemeChecksumsFilePath(themeDir) {
6
+ return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_CURRENT_CHECKSUMS_FILE_NAME);
7
+ }
8
+ static getInitialThemeChecksumsFilePath(themeDir) {
9
+ return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_INITIAL_CHECKSUMS_FILE_NAME);
10
+ }
11
+ static getCurrentThemeChecksumsVerificationFilePath(themeDir) {
12
+ return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME);
13
+ }
14
+ static getInitialThemeChecksumsVerificationFilePath(themeDir) {
15
+ return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME);
16
+ }
17
+ }
@@ -26,6 +26,7 @@ import { THEME_WORK_URL_MISMATCH_ERROR } from '../../features/theme/utils/meta_d
26
26
  import { ThemeWorkUrlMismatch } from '../ui/theme_work_url_mismatch.js';
27
27
  import { Error } from '../../../ui/message_box/error.js';
28
28
  import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
29
+ import { ThemeChecksums } from '../../class/checksums/theme_checksums.js';
29
30
  //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
30
31
  export class ThemePullCommand extends BaseThemeCommand {
31
32
  static summary = 'Downloads the current version of your theme from the store and overwrites your local theme files.';
@@ -175,7 +176,8 @@ export class ThemePullCommand extends BaseThemeCommand {
175
176
  await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(themeModulesPath, join(tmpDir, name, 'modules'), join(tmpDir, name));
176
177
  this.#spinner.stop();
177
178
  const changes = await themeMergeApi.getChangesBetweenThemes(join(tmpDir, name), executionContext.themeRootDir);
178
- if (changes.length && (await themeMergeApi.hasThemeBeenModified(executionContext.themeRootDir))) {
179
+ const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
180
+ if (changes.length && (await themeChecksums.hasThemeBeenModified())) {
179
181
  renderOnce(React.createElement(ThemePullUnpublishedChangesWarning, { changes: changes }));
180
182
  const { proceed } = await promptConfirmation('Do you want to continue and overwrite local changes?');
181
183
  if (!proceed) {
@@ -6,7 +6,6 @@ import { THEME_ARCHIVE_UPLOAD_ERROR, THEME_FILES_UPLOAD_ERROR, THEME_PUSH_API_NA
6
6
  import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
7
7
  import { mapChecksumToTree } from '../../../utils/checksums/checksums_utils.js';
8
8
  import { mapToPermissionsTree } from '../../utils/directory_validator/directory_validator_utils.js';
9
- import { ThemeChecksumsUtils } from '../../features/theme/utils/checksums/theme_checksums_utils.js';
10
9
  import { renderOnce } from '../../../ui/ui_utils.js';
11
10
  import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
12
11
  import React from 'react';
@@ -17,7 +16,6 @@ import ora from 'ora';
17
16
  import { MissingThemeFiles } from '../ui/missing_theme_files.js';
18
17
  import { SHOPER_THEME_METADATA_DIR } from '../../constants/directory_contstants.js';
19
18
  import { THEME_FILES_STRUCTURE_FILE_NAME } from '../../features/theme/theme_constants.js';
20
- import { THEME_MERGE_API_NAME } from '../../features/theme/merge/theme_merge_constants.js';
21
19
  import { ThemePushSkipInfo } from './ui/theme_push_skip_into.js';
22
20
  import { ThemeUnpermittedActionsError } from './ui/theme_unpermitted_actions_error.js';
23
21
  import { Error } from '../../../ui/message_box/error.js';
@@ -27,6 +25,7 @@ import { THEME_WORK_URL_MISMATCH_ERROR } from '../../features/theme/utils/meta_d
27
25
  import { ThemeFilesStructureUtils } from '../../features/theme/utils/files_structure/theme_files_structure_utils.js';
28
26
  import { ThemeInfoUtils } from '../../features/theme/info/theme_info_utils.js';
29
27
  import { ValidationErrors } from '../../../cli/ui/validation_errors/validation_errors.js';
28
+ import { ThemeChecksums } from '../../class/checksums/theme_checksums.js';
30
29
  export class ThemePushCommand extends BaseThemeCommand {
31
30
  static summary = 'Uploads your local theme files to the store and overwrites the current version of the theme in your store.';
32
31
  static description = 'Check your local changes before pushing.\n\nYou must run this command from a specific theme directory (ID not needed).';
@@ -53,6 +52,7 @@ export class ThemePushCommand extends BaseThemeCommand {
53
52
  }
54
53
  let spinner;
55
54
  try {
55
+ const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
56
56
  await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
57
57
  const pushAction = themeActionsApi.getThemeAction({
58
58
  actionType: THEME_ACTIONS_TYPES.push,
@@ -63,18 +63,17 @@ export class ThemePushCommand extends BaseThemeCommand {
63
63
  renderOnce(React.createElement(UnpermittedCommandError, { themeId: executionContext.themeId, commandName: "push" }));
64
64
  return;
65
65
  }
66
- const checksums = await ThemeChecksumsUtils.getThemeInitialChecksums(executionContext.themeRootDir);
66
+ const initialChecksums = await themeChecksums.getInitialChecksums();
67
67
  const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
68
- if (!checksums || !permissions)
68
+ if (!initialChecksums || !permissions)
69
69
  this.error('Theme checksums or permissions not found. Please ensure you are in the correct theme directory.');
70
- const themeMergeApi = this.getApi(THEME_MERGE_API_NAME);
71
- const hasLocalChanges = await themeMergeApi.hasThemeBeenModified(executionContext.themeRootDir);
72
- if (!hasLocalChanges) {
70
+ if (!(await themeChecksums.hasThemeBeenModified())) {
73
71
  renderOnce(React.createElement(ThemePushSkipInfo, null));
74
72
  return;
75
73
  }
76
74
  const validationResult = await ThemeFilesStructureUtils.validateThemeDirectoryStructure({
77
- checksums: mapChecksumToTree(checksums),
75
+ //TDO przeniesc do theme checksums
76
+ checksums: mapChecksumToTree(initialChecksums),
78
77
  permissions: mapToPermissionsTree(permissions),
79
78
  rootDirectory: executionContext.themeRootDir
80
79
  });
@@ -92,9 +91,9 @@ export class ThemePushCommand extends BaseThemeCommand {
92
91
  spinner = ora('Pushing theme...').start();
93
92
  await themePushApi.push({
94
93
  credentials,
95
- checksums,
96
94
  filesStructure,
97
95
  pushAction,
96
+ themeChecksums,
98
97
  executionContext
99
98
  });
100
99
  spinner.stop();
@@ -3,8 +3,8 @@ import { CLI_AUTH_API_NAME } from '../../cli/auth/cli_auth_constants.js';
3
3
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../cli/features/execution_context/execution_context_constants.js';
4
4
  import { mapToPermissionsTree } from '../utils/directory_validator/directory_validator_utils.js';
5
5
  import { mapChecksumToTree } from '../../utils/checksums/checksums_utils.js';
6
- import { ThemeChecksumsUtils } from '../features/theme/utils/checksums/theme_checksums_utils.js';
7
6
  import { ThemeFilesStructureUtils } from '../features/theme/utils/files_structure/theme_files_structure_utils.js';
7
+ import { ThemeChecksums } from '../class/checksums/theme_checksums.js';
8
8
  export class ThemeVerifyCommand extends BaseThemeCommand {
9
9
  static description = 'Verify theme files structure';
10
10
  static hidden = true;
@@ -17,13 +17,13 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
17
17
  const executionContext = await executionContextApi.getExecutionContext();
18
18
  if (executionContext.type !== EXECUTION_CONTEXTS.theme)
19
19
  this.error('You cannot run this command outside theme context.');
20
- const checksums = await ThemeChecksumsUtils.getThemeInitialChecksums(executionContext.themeRootDir);
20
+ const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
21
21
  const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
22
- if (!checksums || !permissions)
22
+ if (!themeChecksums || !permissions)
23
23
  this.error('Theme checksums or permissions not found. Please ensure you are in the correct theme directory.');
24
24
  try {
25
25
  const validationResult = await ThemeFilesStructureUtils.validateThemeDirectoryStructure({
26
- checksums: mapChecksumToTree(checksums),
26
+ checksums: mapChecksumToTree(await themeChecksums.getInitialChecksums()),
27
27
  permissions: mapToPermissionsTree(permissions),
28
28
  rootDirectory: executionContext.themeRootDir
29
29
  });
@@ -10,12 +10,12 @@ import { jsonIndentTransform } from '../../../../../utils/stream_transforms/json
10
10
  import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
11
11
  import { THEME_FILES_LIST_FILE_NAME } from '../../push/theme_push_constants.js';
12
12
  import { JSON_FILE_INDENT } from '../../../../../cli/cli_constants.js';
13
- import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
14
13
  import { createWriteStream } from 'node:fs';
15
14
  import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
16
15
  import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
17
16
  import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
18
17
  import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
18
+ import { ThemeChecksums } from '../../../../../theme/class/checksums/theme_checksums.js';
19
19
  export class ThemeFetchService {
20
20
  #themeHttpApi;
21
21
  #httpApi;
@@ -55,8 +55,10 @@ export class ThemeFetchService {
55
55
  }
56
56
  await this._createGitIgnoreFile(themeDir);
57
57
  await this._updateMetadataFileWithWorkUrl(themeDir, credentials.shopUrl);
58
- const checksums = await ThemeChecksumsUtils.computeThemeChecksums(themeDir);
59
- await ThemeChecksumsUtils.createThemeChecksumsFiles(themeDir, checksums);
58
+ /**
59
+ * moze to nie powinno lezec tutaj :?
60
+ */
61
+ await new ThemeChecksums(themeDir).updateAllChecksums();
60
62
  return {
61
63
  name: basename
62
64
  };
@@ -3,9 +3,9 @@ import process from 'process';
3
3
  import tmp from 'tmp-promise';
4
4
  import { downloadFile } from '../../../../../utils/download_file/download_file_utils.js';
5
5
  import { extractZip } from '../../../../../utils/zip/extract_zip_utils.js';
6
- import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
7
6
  import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
8
7
  import { ThemeInfoUtils } from '../../info/theme_info_utils.js';
8
+ import { ThemeChecksums } from '../../../../../theme/class/checksums/theme_checksums.js';
9
9
  export class ThemeInitService {
10
10
  #httpApi;
11
11
  constructor({ httpApi }) {
@@ -23,8 +23,7 @@ export class ThemeInitService {
23
23
  source: join(tmpDir, filename),
24
24
  dist: distDir
25
25
  });
26
- const checksums = await ThemeChecksumsUtils.computeThemeChecksums(distDir);
27
- await ThemeChecksumsUtils.createThemeChecksumsFiles(join(process.cwd(), basename), checksums);
26
+ new ThemeChecksums(distDir).updateAllChecksums();
28
27
  const themeMetaData = await ThemeMetaDataUtils.getThemeMetadata(distDir);
29
28
  return {
30
29
  themeId: themeMetaData.themeId,
@@ -7,19 +7,10 @@ export class ThemeMergeApi extends FeatureApi {
7
7
  super();
8
8
  this.#service = service;
9
9
  }
10
- hasThemeBeenModified(themeRootDir) {
11
- return this.#service.hasThemeBeenModified(themeRootDir);
12
- }
13
10
  getChangesBetweenThemes(theme1, theme2) {
14
11
  return this.#service.getChangesBetweenThemes(theme1, theme2);
15
12
  }
16
13
  applyChanges(fromTheme, toTheme, changes) {
17
14
  return this.#service.applyChanges(fromTheme, toTheme, changes);
18
15
  }
19
- hasFileBeenCreated(path, themeDir) {
20
- return this.#service.hasFileBeenCreated(path, themeDir);
21
- }
22
- hasFileBeenModified(path, themeDir) {
23
- return this.#service.hasFileBeenModified(path, themeDir);
24
- }
25
16
  }
@@ -1,9 +1,8 @@
1
1
  import FSTree from 'fs-tree-diff';
2
- import { copyFileSync, fileExists, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
3
- import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
2
+ import { copyFileSync, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
4
3
  import walkSync from 'walk-sync';
5
4
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
6
- import { join } from '../../../../../utils/path_utils.js';
5
+ import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
7
6
  export class ThemeMergeService {
8
7
  async applyChanges(fromTheme, toTheme, changes) {
9
8
  FSTree.applyPatch(fromTheme, toTheme, changes, {
@@ -14,8 +13,7 @@ export class ThemeMergeService {
14
13
  copyFileSync(inputPath, outputPath);
15
14
  }
16
15
  });
17
- const checksums = await ThemeChecksumsUtils.computeThemeChecksums(toTheme);
18
- await ThemeChecksumsUtils.createThemeChecksumsFiles(toTheme, checksums);
16
+ new ThemeChecksums(toTheme).updateAllChecksums();
19
17
  }
20
18
  async getChangesBetweenThemes(theme1, theme2) {
21
19
  const theme1Tree = new FSTree({
@@ -24,8 +22,8 @@ export class ThemeMergeService {
24
22
  const theme2Tree = new FSTree({
25
23
  entries: walkSync.entries(theme2)
26
24
  });
27
- const theme1Checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(theme1);
28
- const theme2Checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(theme2);
25
+ const theme1Checksums = new ThemeChecksums(theme1);
26
+ const theme2Checksums = new ThemeChecksums(theme2);
29
27
  const rootDirectories = await getAllDirectoriesNamesInside(theme1, {
30
28
  recursive: false,
31
29
  hidden: true
@@ -34,24 +32,11 @@ export class ThemeMergeService {
34
32
  .calculatePatch(theme1Tree, (entryA, entryB) => {
35
33
  if (entryA.isDirectory() && entryB.isDirectory())
36
34
  return true;
37
- return theme1Checksums[entryA.relativePath] === theme2Checksums[entryB.relativePath];
35
+ return (theme1Checksums.getCurrentChecksumFromPathSync(entryA.relativePath) ===
36
+ theme2Checksums.getCurrentChecksumFromPathSync(entryB.relativePath));
38
37
  })
39
38
  .filter(([_, name]) => {
40
39
  return !name.startsWith(SHOPER_THEME_METADATA_DIR) && rootDirectories.some((rootDir) => name.startsWith(rootDir));
41
40
  });
42
41
  }
43
- async hasThemeBeenModified(themeRootDir) {
44
- const initialChecksums = await ThemeChecksumsUtils.getInitialChecksumsVerification(themeRootDir);
45
- const currentChecksums = await ThemeChecksumsUtils.getThemeCurrentChecksumsVerification(themeRootDir);
46
- return initialChecksums !== currentChecksums;
47
- }
48
- async hasFileBeenCreated(path, themeDir) {
49
- const initialChecksum = await ThemeChecksumsUtils.getInitialChecksumFromPath(path, themeDir);
50
- return !initialChecksum && (await fileExists(join(themeDir, path)));
51
- }
52
- async hasFileBeenModified(path, themeDir) {
53
- const currentChecksum = await ThemeChecksumsUtils.getCurrentChecksumFromPath(path, themeDir);
54
- const initialChecksum = await ThemeChecksumsUtils.getInitialChecksumFromPath(path, themeDir);
55
- return !!currentChecksum && !!initialChecksum && currentChecksum !== initialChecksum;
56
- }
57
42
  }
@@ -2,7 +2,7 @@ import tmp from 'tmp-promise';
2
2
  import { THEME_ACTION_DATA_TYPE, THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
3
3
  import { createZip } from '../../../../../utils/zip/create_zip_utils.js';
4
4
  import { basename, dirname, extname, join, looksLikeDirectory, toUnixPath } from '../../../../../utils/path_utils.js';
5
- import fs, { createReadStream } from 'node:fs';
5
+ import { createReadStream } from 'node:fs';
6
6
  import { v4 as uuid } from 'uuid';
7
7
  import globs from 'fast-glob';
8
8
  import { THEME_WILDCARD_ACTION_NAME } from '../../actions/service/theme_actions_service_constants.js';
@@ -14,27 +14,24 @@ import { ThemeImagesUtils } from '../../utils/theme_images_utils.js';
14
14
  import { ThemePublishUtils } from '../../publish/theme_publish_utils.js';
15
15
  import { formatJSONFile, removeFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
16
16
  import { MODULES_DIRECTORY_NAME } from '../../theme_constants.js';
17
- import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
18
17
  import path from 'node:path';
19
18
  export class ThemePushService {
20
19
  #themePushHttpApi;
21
- #themeMergeApi;
22
20
  #themeFetchApi;
23
- constructor({ themePushHttpApi, themeMergeApi, themeFetchApi }) {
21
+ constructor({ themePushHttpApi, themeFetchApi }) {
24
22
  this.#themePushHttpApi = themePushHttpApi;
25
- this.#themeMergeApi = themeMergeApi;
26
23
  this.#themeFetchApi = themeFetchApi;
27
24
  }
28
- async push({ pushAction, filesStructure, credentials, executionContext }) {
25
+ async push({ pushAction, filesStructure, credentials, executionContext, themeChecksums }) {
29
26
  const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
30
- if (await this.#themeMergeApi.hasFileBeenCreated(ThemePublishUtils.getSkinStoreSettingsFilePath(executionContext.themeRootDir), executionContext.themeRootDir))
27
+ if (await themeChecksums.hasThemeFileBeenCreated(ThemePublishUtils.getSkinStoreSettingsFilePath(executionContext.themeRootDir)))
31
28
  throw ThemePushErrorsFactory.createErrorWhilePushingUnpublishedThemeWithSkinstoreData(credentials.shopUrl);
32
29
  const { uploadData, localFiles } = await this._getActionDataForFilesToUpload({
33
30
  pushAction,
34
31
  filesStructure,
35
- executionContext
32
+ executionContext,
33
+ themeChecksums
36
34
  });
37
- console.log('uploadData', uploadData);
38
35
  if (uploadData.length) {
39
36
  await this._uploadThemeFiles({
40
37
  filesToUpload: uploadData,
@@ -67,8 +64,7 @@ export class ThemePushService {
67
64
  if (resources)
68
65
  await this.#themeFetchApi.fetchResources(credentials.shopUrl, executionContext.themeRootDir, resources);
69
66
  await removeFile(join(executionContext.themeRootDir, THEME_FILES_LIST_FILE_NAME));
70
- const checksums = await ThemeChecksumsUtils.computeThemeChecksums(executionContext.themeRootDir);
71
- await ThemeChecksumsUtils.createThemeChecksumsFiles(executionContext.themeRootDir, checksums);
67
+ await themeChecksums.updateAllChecksums();
72
68
  }
73
69
  async _createThemeArchive({ themeRootDir, filesToArchive, dist }) {
74
70
  const filesInThemeDirectory = await globs(filesToArchive, {
@@ -124,36 +120,31 @@ export class ThemePushService {
124
120
  async _uploadFiles(uploadData, credentials) {
125
121
  const uploadedImageData = [];
126
122
  const rejectedImageData = [];
127
- console.log('uploadData', uploadData);
128
- await Promise.all(uploadData.map(({ actionData, path }) => {
129
- const fstat = fs.lstatSync(path);
130
- console.log('fstat', fstat);
131
- return this.#themePushHttpApi
132
- .pushThemeData({
133
- actionData,
134
- stream: createReadStream(path),
135
- shopUrl: credentials.shopUrl
136
- })
137
- .response.then((response) => {
138
- uploadedImageData.push({
139
- location: dirname(path),
140
- originalFilename: basename(path),
141
- uploadedFilename: response.data.imageId
142
- });
143
- })
144
- .catch(() => {
145
- rejectedImageData.push({
146
- location: dirname(path),
147
- originalFilename: basename(path)
148
- });
123
+ await Promise.all(uploadData.map(({ actionData, path }) => this.#themePushHttpApi
124
+ .pushThemeData({
125
+ actionData,
126
+ stream: createReadStream(path),
127
+ shopUrl: credentials.shopUrl
128
+ })
129
+ .response.then((response) => {
130
+ uploadedImageData.push({
131
+ location: dirname(path),
132
+ originalFilename: basename(path),
133
+ uploadedFilename: response.data.imageId
134
+ });
135
+ })
136
+ .catch(() => {
137
+ rejectedImageData.push({
138
+ location: dirname(path),
139
+ originalFilename: basename(path)
149
140
  });
150
- }));
141
+ })));
151
142
  return {
152
143
  uploadedImageData,
153
144
  rejectedImageData
154
145
  };
155
146
  }
156
- async _getActionDataForFilesToUpload({ pushAction, filesStructure, executionContext }) {
147
+ async _getActionDataForFilesToUpload({ pushAction, filesStructure, executionContext, themeChecksums }) {
157
148
  const uploadData = [];
158
149
  const localFiles = {};
159
150
  for (const [actionKey, actionData] of Object.entries(pushAction.data)) {
@@ -175,8 +166,8 @@ export class ThemePushService {
175
166
  localFiles[fileGlob] = files.length ? basename(files[0]) : null;
176
167
  }
177
168
  for (const filePath of files) {
178
- if ((await this.#themeMergeApi.hasFileBeenCreated(filePath, executionContext.themeRootDir)) ||
179
- (await this.#themeMergeApi.hasFileBeenModified(filePath, executionContext.themeRootDir))) {
169
+ if ((await themeChecksums.hasThemeFileBeenCreated(filePath)) ||
170
+ (await themeChecksums.hasThemeFileBeenModified(filePath))) {
180
171
  uploadData.push({
181
172
  actionData,
182
173
  actionKey,
@@ -3,16 +3,13 @@ import { ThemePushService } from './service/theme_push_service.js';
3
3
  import { THEME_PUSH_FEATURE_NAME } from './theme_push_constants.js';
4
4
  import { ThemePushApi } from './api/theme_push_api.js';
5
5
  import { ThemePushHttpApi } from './http_api/theme_push_http_api.js';
6
- import { THEME_MERGE_API_NAME } from '../merge/theme_merge_constants.js';
7
6
  import { THEME_FETCH_API_NAME } from '../fetch/theme_fetch_constants.js';
8
7
  export class ThemePushInitializer extends SyncFeatureInitializer {
9
8
  static featureName = THEME_PUSH_FEATURE_NAME;
10
9
  init() {
11
10
  const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
12
- const themeMergeApi = this.getApiSync(THEME_MERGE_API_NAME);
13
11
  const service = new ThemePushService({
14
12
  themePushHttpApi: new ThemePushHttpApi(httpApi),
15
- themeMergeApi,
16
13
  themeFetchApi: this.getApiSync(THEME_FETCH_API_NAME)
17
14
  });
18
15
  return {
@@ -1,16 +1,14 @@
1
- import { ThemeChecksumsUtils } from '../checksums/theme_checksums_utils.js';
2
1
  import { getAllFilesNamesInside } from '../../../../../utils/fs/fs_utils.js';
3
2
  import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
4
3
  import { join } from '../../../../../utils/path_utils.js';
5
4
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
6
5
  import { computeFileChecksum } from '../../../../../utils/checksums/checksums_utils.js';
6
+ import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
7
7
  export class HiddenDirectoryUtils {
8
8
  static async ensureFilesInsideThemeMetaDataDirectoryUntouched(themeDirectory) {
9
9
  const themeMetadataPath = this.getThemeHiddenDirectoryPath(themeDirectory);
10
- const checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(themeDirectory);
11
- if (!checksums)
12
- throw new Error(`Checksums file not found in theme metadata directory: ${themeMetadataPath}`);
13
- if (!(await ThemeChecksumsUtils.verifyThemeChecksums(themeDirectory)))
10
+ const themeChecksums = new ThemeChecksums(themeDirectory);
11
+ if (!(await themeChecksums.verify()))
14
12
  throw new Error('Theme checksum file is not valid');
15
13
  const filesNames = (await getAllFilesNamesInside(themeMetadataPath)).filter((fileName) => fileName !== THEME_CURRENT_CHECKSUMS_FILE_NAME &&
16
14
  fileName !== THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME &&
@@ -22,7 +20,8 @@ export class HiddenDirectoryUtils {
22
20
  const fileFullPath = join(themeMetadataPath, fileName);
23
21
  const fileRelativePath = join(SHOPER_THEME_METADATA_DIR, fileName);
24
22
  const currentChecksum = await computeFileChecksum(fileFullPath);
25
- if (currentChecksum !== checksums[fileRelativePath]) {
23
+ const initialChecksum = await themeChecksums.getInitialChecksumFromPath(fileRelativePath);
24
+ if (currentChecksum !== initialChecksum) {
26
25
  throw new Error(`File ${fileName} inside theme metadata directory (${themeMetadataPath}) has been modified. You cannot modify files inside .shoper directory`);
27
26
  }
28
27
  }
@@ -3,7 +3,7 @@ import walkSync from 'walk-sync';
3
3
  import { THEME_FILES_OPERATIONS } from '../../merge/theme_merge_constants.js';
4
4
  import { fileExists, readJSONFile, renameFile } from '../../../../../utils/fs/fs_utils.js';
5
5
  import { join } from '../../../../../utils/path_utils.js';
6
- import { ThemeChecksumsUtils } from '../checksums/theme_checksums_utils.js';
6
+ import { ThemeChecksums } from '../../../../../theme/class/checksums/theme_checksums.js';
7
7
  export class ThemeResourcesWithIdDirectoryUtils {
8
8
  static async updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localResourcesDir, remoteResourcesDir, remoteThemeDir) {
9
9
  const localThemeTree = new FSTree({
@@ -37,8 +37,7 @@ export class ThemeResourcesWithIdDirectoryUtils {
37
37
  /**
38
38
  * If these become performance bottlenecks, we can consider computing checksums only for the changed directories.
39
39
  */
40
- const checksums = await ThemeChecksumsUtils.computeThemeChecksums(remoteThemeDir);
41
- await ThemeChecksumsUtils.createThemeChecksumsFiles(remoteThemeDir, checksums);
40
+ await new ThemeChecksums(remoteThemeDir).updateAllChecksums();
42
41
  }
43
42
  }
44
43
  static async _getResourceIdToFilePathMap(entries) {
@@ -1,7 +1,7 @@
1
1
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
2
2
  import { useApi } from '../../../cli/hooks/ensure_cli_initialized_hook.js';
3
- import { ThemeChecksumsUtils } from '../../features/theme/utils/checksums/theme_checksums_utils.js';
4
3
  import { THEME_COMMANDS_THAT_REQUIRES_UP_TO_DATE_CHECKSUMS } from './ensure_theme_current_checksums_up_to_date_constants.js';
4
+ import { ThemeChecksums } from '../../../theme/class/checksums/theme_checksums.js';
5
5
  export const ensureThemeChecksumsUpToDate = async ({ Command }) => {
6
6
  if (!THEME_COMMANDS_THAT_REQUIRES_UP_TO_DATE_CHECKSUMS.includes(Command.id))
7
7
  return;
@@ -9,12 +9,10 @@ export const ensureThemeChecksumsUpToDate = async ({ Command }) => {
9
9
  const executionContext = await executionContextApi.getExecutionContext();
10
10
  if (executionContext.type !== EXECUTION_CONTEXTS.theme)
11
11
  return;
12
- await ThemeChecksumsUtils.removeCurrentChecksumsFiles(executionContext.themeRootDir);
13
12
  /**
14
13
  * Naive solution, recalculate checksums every time a command based on checksums calculation is executed;
15
14
  * If performance becomes an issue, we can implement a more sophisticated solution, eg. recalculate checksums only when files in the theme directory have changed.
16
15
  */
17
- const checksums = await ThemeChecksumsUtils.computeThemeChecksums(executionContext.themeRootDir);
18
- await ThemeChecksumsUtils.createThemeCurrentChecksumsFile(executionContext.themeRootDir, checksums);
16
+ await new ThemeChecksums(executionContext.themeRootDir).updateCurrentChecksums();
19
17
  };
20
18
  export default ensureThemeChecksumsUpToDate;
@@ -1,5 +1,5 @@
1
1
  import fsPromises from 'node:fs/promises';
2
- import fs, { createReadStream } from 'node:fs';
2
+ import fs, { createReadStream, readFileSync } from 'node:fs';
3
3
  import { isHiddenFile } from 'is-hidden-file';
4
4
  import process from 'node:process';
5
5
  import { basename, join, resolve } from '../path_utils.js';
@@ -39,6 +39,17 @@ export const readJSONFile = async (path, options = { encoding: 'utf-8', flag: 'r
39
39
  throw new Error(`Failed to parse JSON from file ${path}: ${error}`);
40
40
  }
41
41
  };
42
+ export const readJSONFileSync = (path, options = { encoding: 'utf-8', flag: 'r' }) => {
43
+ const fileContent = readFileSync(path, options);
44
+ if (typeof fileContent !== 'string')
45
+ throw new Error('File content is not a string');
46
+ try {
47
+ return JSON.parse(fileContent);
48
+ }
49
+ catch (error) {
50
+ throw new Error(`Failed to parse JSON from file ${path}: ${error}`);
51
+ }
52
+ };
42
53
  export const writeJSONFile = async (path, data) => {
43
54
  try {
44
55
  await writeFile(path, JSON.stringify(data, null, JSON_FILE_INDENT), {
@@ -1,5 +1,6 @@
1
1
  import path, { basename as pathBaseName, dirname as pathDirname, extname as pathExtname, join as pathJoin, normalize, parse as parsePath, relative as pathRelative, resolve as resolvePath, sep } from 'node:path';
2
2
  import fs from 'node:fs';
3
+ import { isWindowsOs } from './platform_utils.js';
3
4
  export const resolve = (...paths) => {
4
5
  return resolvePath(...paths);
5
6
  };
@@ -49,3 +50,4 @@ export const mapKeysPathsToWindowPlatform = (paths) => {
49
50
  };
50
51
  }, {});
51
52
  };
53
+ export const toCurrentPlatformPath = (path) => (isWindowsOs() ? toWinowsPath(path) : toUnixPath(path));
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@shoper/cli",
3
3
  "packageManager": "yarn@3.2.0",
4
4
  "sideEffects": false,
5
- "version": "0.1.0-29",
5
+ "version": "0.1.0-30",
6
6
  "description": "CLI tool for Shoper",
7
7
  "author": "Joanna Firek",
8
8
  "license": "MIT",
@@ -1,137 +0,0 @@
1
- import { join, mapKeysPathsToWindowPlatform, toUnixPath, toWinowsPath } from '../../../../../utils/path_utils.js';
2
- import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
3
- import { createWriteStream } from 'fs';
4
- import { copyFile, readJSONFile, removeFile } from '../../../../../utils/fs/fs_utils.js';
5
- import { ThemeChecksumsErrorFactory } from './theme_checksums_error_factory.js';
6
- import { computeChecksumsFromFilesStructure, computeDirectoriesChecksums, computeFileChecksum } from '../../../../../utils/checksums/checksums_utils.js';
7
- import { JSON_FILE_INDENT } from '../../../../../cli/cli_constants.js';
8
- import { ThemePushUtils } from '../../push/theme_push_utils.js';
9
- import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
10
- import { isWindowsOs } from '../../../../../utils/platform_utils.js';
11
- import { normalize } from 'path';
12
- import { HiddenDirectoryUtils } from '../hidden_directory/hidden_directory_utils.js';
13
- export class ThemeChecksumsUtils {
14
- static getCurrentThemeChecksumsFilePath(themeDir) {
15
- return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_CURRENT_CHECKSUMS_FILE_NAME);
16
- }
17
- static getInitialThemeChecksumsFilePath(themeDir) {
18
- return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_INITIAL_CHECKSUMS_FILE_NAME);
19
- }
20
- static getCurrentThemeChecksumsVerificationFilePath(themeDir) {
21
- return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME);
22
- }
23
- static getInitialThemeChecksumsVerificationFilePath(themeDir) {
24
- return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME);
25
- }
26
- static async createThemeChecksumsFiles(themeDir, checksums) {
27
- return new Promise((resolve, reject) => {
28
- const currentChecksumFilePath = this.getCurrentThemeChecksumsFilePath(themeDir);
29
- const initialChecksumFilePath = this.getInitialThemeChecksumsFilePath(themeDir);
30
- const checksumStream = createWriteStream(initialChecksumFilePath);
31
- checksumStream.write(JSON.stringify(checksums, null, JSON_FILE_INDENT));
32
- checksumStream.end();
33
- checksumStream
34
- .on('finish', async () => {
35
- const initialChecksumVerifyFilePath = this.getInitialThemeChecksumsVerificationFilePath(themeDir);
36
- const currentChecksumVerifyFilePath = this.getCurrentThemeChecksumsVerificationFilePath(themeDir);
37
- await this.createThemeChecksumVerifyFile(initialChecksumFilePath, initialChecksumVerifyFilePath);
38
- await copyFile(initialChecksumFilePath, currentChecksumFilePath);
39
- await copyFile(initialChecksumVerifyFilePath, currentChecksumVerifyFilePath);
40
- resolve();
41
- })
42
- .on('error', async (err) => {
43
- await removeFile(initialChecksumFilePath, { force: true });
44
- reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack));
45
- });
46
- });
47
- }
48
- static async createThemeCurrentChecksumsFile(themeDir, checksums) {
49
- return new Promise((resolve, reject) => {
50
- const currentChecksumFilePath = this.getCurrentThemeChecksumsFilePath(themeDir);
51
- const checksumStream = createWriteStream(currentChecksumFilePath);
52
- checksumStream.write(JSON.stringify(checksums, null, JSON_FILE_INDENT));
53
- checksumStream.end();
54
- checksumStream
55
- .on('finish', async () => {
56
- const currentChecksumVerifyFilePath = this.getCurrentThemeChecksumsVerificationFilePath(themeDir);
57
- await this.createThemeChecksumVerifyFile(currentChecksumFilePath, currentChecksumVerifyFilePath);
58
- resolve();
59
- })
60
- .on('error', async (err) => {
61
- await removeFile(currentChecksumFilePath, { force: true });
62
- reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack));
63
- });
64
- });
65
- }
66
- static async createThemeChecksumVerifyFile(checksumFilePath, checksumVerifyFullPath) {
67
- const checksumVerifyStream = createWriteStream(checksumVerifyFullPath);
68
- const checksumVerify = await computeFileChecksum(checksumFilePath);
69
- checksumVerifyStream
70
- .on('error', async (err) => {
71
- await removeFile(checksumFilePath, { force: true });
72
- throw ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack);
73
- })
74
- .write(JSON.stringify(checksumVerify));
75
- checksumVerifyStream.end();
76
- }
77
- static async getThemeCurrentChecksums(themeDir) {
78
- const checksumFilePath = this.getCurrentThemeChecksumsFilePath(themeDir);
79
- const checksums = await readJSONFile(checksumFilePath);
80
- if (!isWindowsOs())
81
- return checksums;
82
- return mapKeysPathsToWindowPlatform(checksums);
83
- }
84
- static async getThemeInitialChecksums(themeDir) {
85
- const checksumFilePath = this.getInitialThemeChecksumsFilePath(themeDir);
86
- const checksums = await readJSONFile(checksumFilePath);
87
- if (!isWindowsOs())
88
- return checksums;
89
- return mapKeysPathsToWindowPlatform(checksums);
90
- }
91
- static async verifyThemeChecksums(themeDir) {
92
- const initialChecksumFilePath = this.getInitialThemeChecksumsFilePath(themeDir);
93
- const initialChecksumVerifyFilePath = this.getInitialThemeChecksumsVerificationFilePath(themeDir);
94
- const initialChecksum = await computeFileChecksum(initialChecksumFilePath);
95
- const initialChecksumVerify = await readJSONFile(initialChecksumVerifyFilePath);
96
- return initialChecksum === initialChecksumVerify;
97
- }
98
- static async getThemeCurrentChecksumsVerification(themeDir) {
99
- return await readJSONFile(this.getCurrentThemeChecksumsVerificationFilePath(themeDir));
100
- }
101
- static async getInitialChecksumsVerification(themeDir) {
102
- return await readJSONFile(this.getInitialThemeChecksumsVerificationFilePath(themeDir));
103
- }
104
- static async removeCurrentChecksumsFiles(themeDir) {
105
- const currentChecksumFilePath = this.getCurrentThemeChecksumsFilePath(themeDir);
106
- const currentChecksumVerifyFilePath = this.getCurrentThemeChecksumsVerificationFilePath(themeDir);
107
- try {
108
- await removeFile(currentChecksumFilePath, { force: true });
109
- await removeFile(currentChecksumVerifyFilePath, { force: true });
110
- }
111
- catch (err) {
112
- throw ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack);
113
- }
114
- }
115
- static async computeThemeChecksums(themeDir) {
116
- const filesToIgnoreInChecksums = [
117
- join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_FILE_NAME),
118
- join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME),
119
- join(SHOPER_THEME_METADATA_DIR, THEME_INITIAL_CHECKSUMS_FILE_NAME),
120
- join(SHOPER_THEME_METADATA_DIR, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME)
121
- ];
122
- const filesToComputeChecksums = (await ThemePushUtils.getAllFilesThatAreSendToRemote(themeDir))
123
- .filter((path) => !filesToIgnoreInChecksums.some((ignorePath) => normalize(path) === ignorePath))
124
- .map((relativePath) => join(themeDir, relativePath));
125
- const { filesChecksumsInDirectories, filesChecksums } = await computeChecksumsFromFilesStructure(filesToComputeChecksums, themeDir);
126
- const directoriesChecksums = computeDirectoriesChecksums(filesChecksumsInDirectories);
127
- return { ...filesChecksums, ...directoriesChecksums };
128
- }
129
- static async getCurrentChecksumFromPath(path, themeDir) {
130
- const checksums = await this.getThemeCurrentChecksums(themeDir);
131
- return checksums[isWindowsOs() ? toWinowsPath(path) : toUnixPath(path)];
132
- }
133
- static async getInitialChecksumFromPath(path, themeDir) {
134
- const checksums = await this.getThemeInitialChecksums(themeDir);
135
- return checksums[isWindowsOs() ? toWinowsPath(path) : toUnixPath(path)];
136
- }
137
- }