@@ -3,6 +3,12 @@ import path from 'path';
33import { execSync } from 'child_process' ;
44import yaml from 'js-yaml' ;
55
6+ /**
7+ * Clones a Git repository to a specified directory
8+ * @param {string } url The URL of the Git repository
9+ * @param {string } directory The target directory to clone the repository to
10+ * @returns
11+ */
612const cloneRepository = ( url , directory ) => {
713 try {
814 // Clone the repository
@@ -14,6 +20,12 @@ const cloneRepository = (url, directory) => {
1420 }
1521} ;
1622
23+ /**
24+ * Gets the GitHub URL of a Git repository from the local filesystem
25+ * @param {string } rootPath The root path of the Git repository
26+ * @returns {string } The GitHub URL of the repository
27+ * @returns {null } If an error occurs
28+ */
1729const getGitHubUrl = ( rootPath ) => {
1830 try {
1931 // Get the GitHub repository URL
@@ -29,6 +41,12 @@ const getGitHubUrl = (rootPath) => {
2941 }
3042} ;
3143
44+ /**
45+ * Gets the current Git branch of a local repository
46+ * @param {string } rootPath The root path of the Git repository
47+ * @returns {string } The name of the current branch
48+ * @returns {null } If an error occurs
49+ */
3250const getCurrentBranch = ( rootPath ) => {
3351 try {
3452 // Get the current branch name
@@ -40,42 +58,95 @@ const getCurrentBranch = (rootPath) => {
4058 }
4159} ;
4260
43- const getRepositoryRoot = ( rootPath ) => {
61+ /**
62+ * Gets the root folder of a Git repository (the one containing the .git folder)
63+ * @param {string } aPath The path to a file or directory within the repository
64+ * @returns {string } The root folder of the repository
65+ * @returns {null } If an error occurs
66+ */
67+ const getRepositoryRoot = ( aPath ) => {
4468 try {
4569 // Get the root folder of the repository
46- const repositoryRoot = execSync ( 'git rev-parse --show-toplevel' , { cwd : rootPath , encoding : 'utf-8' } ) . trim ( ) ;
70+ const repositoryRoot = execSync ( 'git rev-parse --show-toplevel' , { cwd : aPath , encoding : 'utf-8' } ) . trim ( ) ;
4771 return repositoryRoot ;
4872 } catch ( error ) {
4973 console . error ( `Error getting repository root: ${ error . message } ` ) ;
5074 return null ;
5175 }
5276} ;
5377
54- const searchPackages = ( directory , outputFilename , indexUrl ) => {
78+ /**
79+ * Constructs a GitHub URL for a specific directory in a Git repository.
80+ * @param {string } baseUrl The base URL of the GitHub repository
81+ * @param {string } branch The current branch of the repository
82+ * @param {string } repositoryRoot The root folder of the repository
83+ * @param {string } dirPath The path to the directory within the repository
84+ * @returns {string } The GitHub URL for the directory
85+ */
86+ const constructGitHubUrl = ( baseUrl , branch , repositoryRoot , dirPath ) => {
87+ const relativePath = path . relative ( repositoryRoot , dirPath ) ;
88+ const normalizedPath = relativePath . replace ( / \\ / g, '/' ) ; // Normalize path separators for Windows
89+
90+ return `${ baseUrl } /tree/${ branch } /${ normalizedPath } ` ;
91+ } ;
92+
93+ /**
94+ * Extracts the description from a manifest.py file
95+ * @param {string } filePath The path to the manifest.py file
96+ * @returns {string } The description extracted from the file
97+ * @returns {null } If an error occurs
98+ */
99+ function extractDescription ( filePath ) {
100+ try {
101+ const content = fs . readFileSync ( filePath , 'utf8' ) ;
102+ const descriptionMatch = / d e s c r i p t i o n = " ( .* ?) " / . exec ( content ) ;
103+
104+ if ( descriptionMatch && descriptionMatch [ 1 ] ) {
105+ return descriptionMatch [ 1 ] ;
106+ }
107+ } catch ( error ) {
108+ console . error ( `Error reading ${ filePath } : ${ error . message } ` ) ;
109+ return null ;
110+ }
111+ }
112+
113+ /**
114+ * Generates a list of packages from directories containing a package.json file
115+ * @param {string } directory The starting directory to search for packages
116+ * @param {string } indexUrl The URL of the package index to be assigned to each package
117+ * @param {RegExp } excludePattern A regular expression to exclude certain directories
118+ * @returns {string } A YAML representation of the package list as a string
119+ */
120+ const generatePackageList = ( directory , indexUrl , excludePattern ) => {
55121 const result = { packages : [ ] } ;
56122
57123 const repositoryRoot = getRepositoryRoot ( directory ) ;
124+ console . log ( `Repository root: ${ repositoryRoot } from ${ directory } ` ) ;
58125 const gitHubUrl = getGitHubUrl ( repositoryRoot ) ;
59126 const currentBranch = getCurrentBranch ( repositoryRoot ) ;
60127
61128 if ( ! repositoryRoot || ! gitHubUrl || ! currentBranch ) {
62129 return ;
63130 }
64131
65- const search = ( dir , rootPath ) => {
132+ const collectPackages = ( dir , rootPath ) => {
66133 const files = fs . readdirSync ( dir ) ;
67134
68135 for ( const file of files ) {
69136 const filePath = path . join ( dir , file ) ;
70137 const isDirectory = fs . statSync ( filePath ) . isDirectory ( ) ;
71138
72139 if ( isDirectory ) {
73- search ( filePath , rootPath ) ;
140+ collectPackages ( filePath , rootPath ) ;
74141 } else {
75142 const isPackageJson = file === 'package.json' ;
76143 const isManifestPy = file === 'manifest.py' ;
77144 const packageName = path . basename ( dir ) ;
78145
146+ if ( excludePattern && excludePattern . test ( dir ) ) {
147+ continue ; // Skip excluded packages
148+ }
149+
79150 if ( packageName . startsWith ( "_" ) ) {
80151 continue ; // Skip "private" packages
81152 }
@@ -89,16 +160,8 @@ const searchPackages = (directory, outputFilename, indexUrl) => {
89160 } ;
90161
91162 if ( isManifestPy ) {
92- try {
93- const content = fs . readFileSync ( filePath , 'utf8' ) ;
94- const descriptionMatch = / d e s c r i p t i o n = " ( .* ?) " / . exec ( content ) ;
95-
96- if ( descriptionMatch && descriptionMatch [ 1 ] ) {
97- packageInfo . description = descriptionMatch [ 1 ] ;
98- }
99- } catch ( error ) {
100- console . error ( `Error reading ${ file } : ${ error . message } ` ) ;
101- }
163+ const description = extractDescription ( filePath , packageInfo , file ) ;
164+ packageInfo . description = description ;
102165 }
103166
104167 result . packages . push ( packageInfo ) ;
@@ -107,22 +170,8 @@ const searchPackages = (directory, outputFilename, indexUrl) => {
107170 }
108171 } ;
109172
110- const constructGitHubUrl = ( baseUrl , branch , repositoryRoot , dirPath ) => {
111- const relativePath = path . relative ( repositoryRoot , dirPath ) ;
112- const normalizedPath = relativePath . replace ( / \\ / g, '/' ) ; // Normalize path separators for Windows
113-
114- return `${ baseUrl } /tree/${ branch } /${ normalizedPath } ` ;
115- } ;
116-
117- search ( directory , repositoryRoot ) ;
118-
119- try {
120- const yamlData = yaml . dump ( result ) ;
121- fs . writeFileSync ( outputFilename , `---\n${ yamlData } ` ) ;
122- console . log ( `YAML file saved to ${ outputFilename } ` ) ;
123- } catch ( error ) {
124- console . error ( `Error writing YAML file: ${ error . message } ` ) ;
125- }
173+ collectPackages ( directory , repositoryRoot ) ;
174+ return yaml . dump ( result ) ;
126175} ;
127176
128177// Check if command line arguments are provided
@@ -142,6 +191,13 @@ if (process.argv.length < 3) {
142191 const directory = "build/micropython-lib" ;
143192 const indexUrl = "https://micropython.org/pi/v2" ;
144193 const outputFilename = process . argv [ 2 ] ;
194+ const excludePattern = / \/ u n i x - f f i \/ / ; // Skip Unix-specific packages
145195
146- searchPackages ( directory , outputFilename , indexUrl ) ;
196+ const packageList = generatePackageList ( directory , indexUrl , excludePattern ) ;
197+ try {
198+ fs . writeFileSync ( outputFilename , `---\n${ packageList } ` ) ;
199+ console . log ( `YAML file saved to ${ outputFilename } ` ) ;
200+ } catch ( error ) {
201+ console . error ( `Error writing YAML file: ${ error . message } ` ) ;
202+ }
147203}
0 commit comments