backstage

Форк
0
176 строк · 5.1 Кб
1
/*
2
 * Copyright 2020 The Backstage Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
import fs from 'fs';
18
import { dirname, resolve as resolvePath } from 'path';
19

20
/**
21
 * A function that takes a set of path fragments and resolves them into a
22
 * single complete path, relative to some root.
23
 *
24
 * @public
25
 */
26
export type ResolveFunc = (...paths: string[]) => string;
27

28
/**
29
 * Common paths and resolve functions used by the cli.
30
 * Currently assumes it is being executed within a monorepo.
31
 *
32
 * @public
33
 */
34
export type Paths = {
35
  // Root dir of the cli itself, containing package.json
36
  ownDir: string;
37

38
  // Monorepo root dir of the cli itself. Only accessible when running inside Backstage repo.
39
  ownRoot: string;
40

41
  // The location of the app that the cli is being executed in
42
  targetDir: string;
43

44
  // The monorepo root package of the app that the cli is being executed in.
45
  targetRoot: string;
46

47
  // Resolve a path relative to own repo
48
  resolveOwn: ResolveFunc;
49

50
  // Resolve a path relative to own monorepo root. Only accessible when running inside Backstage repo.
51
  resolveOwnRoot: ResolveFunc;
52

53
  // Resolve a path relative to the app
54
  resolveTarget: ResolveFunc;
55

56
  // Resolve a path relative to the app repo root
57
  resolveTargetRoot: ResolveFunc;
58
};
59

60
// Looks for a package.json with a workspace config to identify the root of the monorepo
61
export function findRootPath(
62
  searchDir: string,
63
  filterFunc: (pkgJsonPath: string) => boolean,
64
): string | undefined {
65
  let path = searchDir;
66

67
  // Some confidence check to avoid infinite loop
68
  for (let i = 0; i < 1000; i++) {
69
    const packagePath = resolvePath(path, 'package.json');
70
    const exists = fs.existsSync(packagePath);
71
    if (exists && filterFunc(packagePath)) {
72
      return path;
73
    }
74

75
    const newPath = dirname(path);
76
    if (newPath === path) {
77
      return undefined;
78
    }
79
    path = newPath;
80
  }
81

82
  throw new Error(
83
    `Iteration limit reached when searching for root package.json at ${searchDir}`,
84
  );
85
}
86

87
// Finds the root of a given package
88
export function findOwnDir(searchDir: string) {
89
  const path = findRootPath(searchDir, () => true);
90
  if (!path) {
91
    throw new Error(
92
      `No package.json found while searching for package root of ${searchDir}`,
93
    );
94
  }
95
  return path;
96
}
97

98
// Finds the root of the monorepo that the package exists in. Only accessible when running inside Backstage repo.
99
export function findOwnRootDir(ownDir: string) {
100
  const isLocal = fs.existsSync(resolvePath(ownDir, 'src'));
101
  if (!isLocal) {
102
    throw new Error(
103
      'Tried to access monorepo package root dir outside of Backstage repository',
104
    );
105
  }
106

107
  return resolvePath(ownDir, '../..');
108
}
109

110
/**
111
 * Find paths related to a package and its execution context.
112
 *
113
 * @public
114
 * @example
115
 *
116
 * const paths = findPaths(__dirname)
117
 */
118
export function findPaths(searchDir: string): Paths {
119
  const ownDir = findOwnDir(searchDir);
120
  // Drive letter can end up being lowercased here on Windows, bring back to uppercase for consistency
121
  const targetDir = fs
122
    .realpathSync(process.cwd())
123
    .replace(/^[a-z]:/, str => str.toLocaleUpperCase('en-US'));
124

125
  // Lazy load this as it will throw an error if we're not inside the Backstage repo.
126
  let ownRoot = '';
127
  const getOwnRoot = () => {
128
    if (!ownRoot) {
129
      ownRoot = findOwnRootDir(ownDir);
130
    }
131
    return ownRoot;
132
  };
133

134
  // We're not always running in a monorepo, so we lazy init this to only crash commands
135
  // that require a monorepo when we're not in one.
136
  let targetRoot = '';
137
  const getTargetRoot = () => {
138
    if (!targetRoot) {
139
      targetRoot =
140
        findRootPath(targetDir, path => {
141
          try {
142
            const content = fs.readFileSync(path, 'utf8');
143
            const data = JSON.parse(content);
144
            return Boolean(data.workspaces?.packages);
145
          } catch (error) {
146
            throw new Error(
147
              `Failed to parse package.json file while searching for root, ${error}`,
148
            );
149
          }
150
        }) ?? targetDir; // We didn't find any root package.json, assume we're not in a monorepo
151
    }
152
    return targetRoot;
153
  };
154

155
  return {
156
    ownDir,
157
    get ownRoot() {
158
      return getOwnRoot();
159
    },
160
    targetDir,
161
    get targetRoot() {
162
      return getTargetRoot();
163
    },
164
    resolveOwn: (...paths) => resolvePath(ownDir, ...paths),
165
    resolveOwnRoot: (...paths) => resolvePath(getOwnRoot(), ...paths),
166
    resolveTarget: (...paths) => resolvePath(targetDir, ...paths),
167
    resolveTargetRoot: (...paths) => resolvePath(getTargetRoot(), ...paths),
168
  };
169
}
170

171
/**
172
 * The name of the backstage's config file
173
 *
174
 * @public
175
 */
176
export const BACKSTAGE_JSON = 'backstage.json';
177

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.