Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: native_client_sdk/src/project_templates/init_project.py

Issue 16972010: Dropping nacl sdk dead code (documentation, project_template). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """A simple project generator for Native Client projects written in C or C++.
7
8 This script accepts a few argument which it uses as a description of a new NaCl
9 project. It sets up a project with a given name and a given primary language
10 (default: C++, optionally, C) using the appropriate files from this area.
11 This script does not handle setup for complex applications, just the basic
12 necessities to get a functional native client application stub. When this
13 script terminates a compileable project stub will exist with the specified
14 name, at the specified location.
15
16 GetCamelCaseName(): Converts an underscore name to a camel case name.
17 GetCodeDirectory(): Decides what directory to pull source code from.
18 GetCodeSoureFiles(): Decides what source files to pull into the stub.
19 GetCommonSourceFiles(): Gives list of files needed by all project types.
20 GetHTMLDirectory(): Decides what directory to pull HTML stub from.
21 GetHTMLSourceFiles(): Gives HTML files to be included in project stub.
22 GetTargetFileName(): Converts a source file name into a project file name.
23 ParseArguments(): Parses the arguments provided by the user.
24 ReplaceInFile(): Replaces a given string with another in a given file.
25 ProjectInitializer: Maintains some state applicable to setting up a project.
26 main(): Executes the script.
27 """
28
29 __author__ = 'mlinck@google.com (Michael Linck)'
30
31 import fileinput
32 import optparse
33 import os.path
34 import shutil
35 import sys
36 import uuid
37
38 # A list of all platforms that should have make.cmd.
39 WINDOWS_BUILD_PLATFORMS = ['cygwin', 'win32']
40
41 # Tags that will be replaced in our the new project's source files.
42 PROJECT_NAME_TAG = '<PROJECT_NAME>'
43 PROJECT_NAME_CAMEL_CASE_TAG = '<ProjectName>'
44 SDK_ROOT_TAG = '<NACL_SDK_ROOT>'
45 NACL_PLATFORM_TAG = '<NACL_PLATFORM>'
46 VS_PROJECT_UUID_TAG = '<VS_PROJECT_UUID>'
47 VS_SOURCE_UUID_TAG = '<VS_SOURCE_UUID>'
48 VS_HEADER_UUID_TAG = '<VS_HEADER_UUID>'
49 VS_RESOURCE_UUID_TAG = '<VS_RESOURCE_UUID>'
50
51 # This string is the part of the file name that will be replaced.
52 PROJECT_FILE_NAME = 'project_file'
53
54 # Lists of source files that will be used for the new project.
55 COMMON_PROJECT_FILES = ['scons']
56 C_SOURCE_FILES = ['build.scons', '%s.c' % PROJECT_FILE_NAME]
57 CC_SOURCE_FILES = ['build.scons', '%s.cc' % PROJECT_FILE_NAME]
58 HTML_FILES = ['%s.html' % PROJECT_FILE_NAME]
59 VS_FILES = ['%s.sln' % PROJECT_FILE_NAME, '%s.vcproj' % PROJECT_FILE_NAME]
60
61 # Error needs to be a class, since we 'raise' it in several places.
62 class Error(Exception):
63 pass
64
65
66 def GetCamelCaseName(lower_case_name):
67 """Converts an underscore name to a camel case name.
68
69 Args:
70 lower_case_name: The name in underscore-delimited lower case format.
71
72 Returns:
73 The name in camel case format.
74 """
75 camel_case_name = ''
76 name_parts = lower_case_name.split('_')
77 for part in name_parts:
78 if part:
79 camel_case_name += part.capitalize()
80 return camel_case_name
81
82
83 def GetCodeDirectory(is_c_project, project_templates_dir):
84 """Decides what directory to pull source code from.
85
86 Args:
87 is_c_project: A boolean indicating whether this project is in C or not.
88 project_templates_dir: The path to the project_templates directory.
89
90 Returns:
91 The code directory for the given project type.
92 """
93 stub_directory = ''
94 if is_c_project:
95 stub_directory = os.path.join(project_templates_dir, 'c')
96 else:
97 stub_directory = os.path.join(project_templates_dir, 'cc')
98 return stub_directory
99
100
101 def GetCodeSourceFiles(is_c_project):
102 """Decides what source files to pull into the stub.
103
104 Args:
105 is_c_project: A boolean indicating whether this project is in C or not.
106
107 Returns:
108 The files that are specific to the requested type of project and live in its
109 directory.
110 """
111 project_files = []
112 if is_c_project:
113 project_files = C_SOURCE_FILES
114 else:
115 project_files = CC_SOURCE_FILES
116 return project_files
117
118
119 def GetCommonSourceFiles():
120 """Gives list of files needed by all project types.
121
122 Returns:
123 The files C and C++ projects have in common. These are the files that live
124 in the top level project_templates directory.
125 """
126 project_files = COMMON_PROJECT_FILES
127 if sys.platform in WINDOWS_BUILD_PLATFORMS:
128 project_files.extend(['scons.bat'])
129 return project_files
130
131
132 def GetVsDirectory(project_templates_dir):
133 """Decides what directory to pull Visual Studio stub from.
134
135 Args:
136 project_templates_dir: The path to the project_templates directory.
137
138 Returns:
139 The directory where the HTML stub is to be found.
140 """
141 return os.path.join(project_templates_dir, 'vs')
142
143
144 def GetVsProjectFiles():
145 """Gives VisualStudio files to be included in project stub.
146
147 Returns:
148 The VisualStudio files needed for the project.
149 """
150 return VS_FILES
151
152
153 def GetHTMLDirectory(project_templates_dir):
154 """Decides what directory to pull HTML stub from.
155
156 Args:
157 project_templates_dir: The path to the project_templates directory.
158
159 Returns:
160 The directory where the HTML stub is to be found.
161 """
162 return os.path.join(project_templates_dir, 'html')
163
164
165 def GetHTMLSourceFiles():
166 """Gives HTML files to be included in project stub.
167
168 Returns:
169 The HTML files needed for the project.
170 """
171 return HTML_FILES
172
173
174 def GetTargetFileName(source_file_name, project_name):
175 """Converts a source file name into a project file name.
176
177 Args:
178 source_file_name: The name of a file that is to be included in the project
179 stub, as it appears at the source location.
180 project_name: The name of the project that is being generated.
181
182 Returns:
183 The target file name for a given source file. All project files are run
184 through this filter and it modifies them as needed.
185 """
186 target_file_name = ''
187 if source_file_name.startswith(PROJECT_FILE_NAME):
188 target_file_name = source_file_name.replace(PROJECT_FILE_NAME,
189 project_name)
190 else:
191 target_file_name = source_file_name
192 return target_file_name
193
194
195 def GetDefaultProjectDir():
196 """Determines the default project directory.
197
198 The default directory root for new projects is called 'nacl_projects' under
199 the user's home directory. There are two ways to override this: you can set
200 the NACL_PROJECT_ROOT environment variable, or use the --directory option.
201
202 Returns:
203 An os-specific path to the default project directory, which is called
204 'nacl_projects' under the user's home directory.
205 """
206 return os.getenv('NACL_PROJECT_ROOT',
207 os.path.join(os.path.expanduser('~'), 'nacl_projects'))
208
209
210 def ParseArguments(argv):
211 """Parses the arguments provided by the user.
212
213 Parses the command line options and makes sure the script errors when it is
214 supposed to.
215
216 Args:
217 argv: The argument array.
218
219 Returns:
220 The options structure that represents the arguments after they have been
221 parsed.
222 """
223 parser = optparse.OptionParser()
224 parser.add_option(
225 '-n', '--name', dest='project_name',
226 default='',
227 help=('Required: the name of the new project to be stubbed out.\n'
228 'Please use lower case names with underscore, i.e. hello_world.'))
229 parser.add_option(
230 '-d', '--directory', dest='project_directory',
231 default=GetDefaultProjectDir(),
232 help=('Optional: If set, the new project will be created under this '
233 'directory and the directory created if necessary.'))
234 parser.add_option(
235 '-c', action='store_true', dest='is_c_project',
236 default=False,
237 help=('Optional: If set, this will generate a C project. Default '
238 'is C++.'))
239 parser.add_option(
240 '-p', '--nacl-platform', dest='nacl_platform',
241 default='pepper_17',
242 help=('Optional: if set, the new project will target the given nacl\n'
243 'platform. Default is the most current platform. e.g. pepper_17'))
244 parser.add_option(
245 '--vsproj', action='store_true', dest='is_vs_project',
246 default=False,
247 help=('Optional: If set, generate Visual Studio project files.'))
248 result = parser.parse_args(argv)
249 options = result[0]
250 args = result[1]
251 #options, args) = parser.parse_args(argv)
252 if args:
253 parser.print_help()
254 sys.exit(1)
255 elif not options.project_name.islower():
256 print('--name missing or in incorrect format. Please use -h for '
257 'instructions.')
258 sys.exit(1)
259 return options
260
261
262 class ProjectInitializer(object):
263 """Maintains the state of the project that is being created."""
264
265 def __init__(self, is_c_project, is_vs_project, project_name,
266 project_location, nacl_platform, project_templates_dir,
267 nacl_sdk_root=None, os_resource=os):
268 """Initializes all the fields that are known after parsing the parameters.
269
270 Args:
271 is_c_project: A boolean indicating whether this project is in C or not.
272 is_vs_project: A boolean indicating whether this project has Visual
273 Studio support.
274 project_name: A string containing the name of the project to be created.
275 project_location: A path indicating where the new project is to be placed.
276 project_templates_dir: The path to the project_templates directory.
277 os_resource: A resource to be used as os. Provided for unit testing.
278 """
279 self.__is_c_project = is_c_project
280 self.__is_vs_project = is_vs_project
281 self.__project_files = []
282 self.__project_dir = None
283 self.__project_name = project_name
284 self.__project_location = project_location
285 self.__nacl_platform = nacl_platform
286 self.__project_templates_dir = project_templates_dir
287 # System resources are properties so mocks can be inserted.
288 self.__fileinput = fileinput
289 self.__nacl_sdk_root = nacl_sdk_root
290 self.__os = os_resource
291 self.__shutil = shutil
292 self.__sys = sys
293 self.__CreateProjectDirectory()
294
295 def CopyAndRenameFiles(self, source_dir, file_names):
296 """Places files in the new project's directory and renames them as needed.
297
298 Copies the given files from the given source directory into the new
299 project's directory, renaming them as necessary. Each file that is created
300 in the project directory is also added to self.__project_files.
301
302 Args:
303 source_dir: A path indicating where the files are to be copied from.
304 file_names: The list of files that is to be copied out of source_dir.
305 """
306 for source_file_name in file_names:
307 target_file_name = GetTargetFileName(source_file_name,
308 self.__project_name)
309 copy_source_file = self.os.path.join(source_dir, source_file_name)
310 copy_target_file = self.os.path.join(self.__project_dir, target_file_name)
311 self.shutil.copy(copy_source_file, copy_target_file)
312 self.__project_files += [copy_target_file]
313
314 def __CreateProjectDirectory(self):
315 """Creates the project's directory and any parents as necessary."""
316 self.__project_dir = self.os.path.join(self.__project_location,
317 self.__project_name)
318 if self.os.path.exists(self.__project_dir):
319 raise Error("Error: directory '%s' already exists" % self.__project_dir)
320 self.os.makedirs(self.__project_dir)
321
322 def PrepareDirectoryContent(self):
323 """Prepares the directory for the new project.
324
325 This function's job is to know what directories need to be used and what
326 files need to be copied and renamed. It uses several tiny helper functions
327 to do this.
328 There are three locations from which files are copied to create a project.
329 That number may change in the future.
330 """
331 code_source_dir = GetCodeDirectory(self.__is_c_project,
332 self.__project_templates_dir)
333 code_source_files = GetCodeSourceFiles(self.__is_c_project)
334 html_source_dir = GetHTMLDirectory(self.__project_templates_dir)
335 html_source_files = GetHTMLSourceFiles()
336 common_source_files = GetCommonSourceFiles()
337 self.CopyAndRenameFiles(code_source_dir, code_source_files)
338 self.CopyAndRenameFiles(html_source_dir, html_source_files)
339 self.CopyAndRenameFiles(self.__project_templates_dir,
340 common_source_files)
341 if self.__is_vs_project:
342 vs_source_dir = GetVsDirectory(self.__project_templates_dir)
343 vs_files = GetVsProjectFiles()
344 self.CopyAndRenameFiles(vs_source_dir, vs_files)
345 print('init_project has copied the appropriate files to: %s' %
346 self.__project_dir)
347
348 def PrepareFileContent(self):
349 """Changes contents of files in the new project as needed.
350
351 Goes through each file in the project that is being created and replaces
352 contents as necessary.
353 """
354 camel_case_name = GetCamelCaseName(self.__project_name)
355 sdk_root_dir = self.__nacl_sdk_root
356 if not sdk_root_dir:
357 raise Error("Error: NACL_SDK_ROOT is not set")
358 sdk_root_dir = self.os.path.abspath(sdk_root_dir)
359 if self.__is_vs_project:
360 project_uuid = str(uuid.uuid4()).upper()
361 vs_source_uuid = str(uuid.uuid4()).upper()
362 vs_header_uuid = str(uuid.uuid4()).upper()
363 vs_resource_uuid = str(uuid.uuid4()).upper()
364 for project_file in self.__project_files:
365 self.ReplaceInFile(project_file, PROJECT_NAME_TAG, self.__project_name)
366 self.ReplaceInFile(project_file,
367 PROJECT_NAME_CAMEL_CASE_TAG,
368 camel_case_name)
369 self.ReplaceInFile(project_file, SDK_ROOT_TAG, sdk_root_dir)
370 self.ReplaceInFile(project_file, NACL_PLATFORM_TAG, self.__nacl_platform)
371 if self.__is_vs_project:
372 self.ReplaceInFile(project_file, VS_PROJECT_UUID_TAG, project_uuid)
373 self.ReplaceInFile(project_file, VS_SOURCE_UUID_TAG, vs_source_uuid)
374 self.ReplaceInFile(project_file, VS_HEADER_UUID_TAG, vs_header_uuid)
375 self.ReplaceInFile(project_file, VS_RESOURCE_UUID_TAG, vs_resource_uuid)
376
377 def ReplaceInFile(self, file_path, old_text, new_text):
378 """Replaces a given string with another in a given file.
379
380 Args:
381 file_path: The path to the file that is to be modified.
382 old_text: The text that is to be removed.
383 new_text: The text that is to be added in place of old_text.
384 """
385 for line in self.fileinput.input(file_path, inplace=1, mode='U'):
386 self.sys.stdout.write(line.replace(old_text, new_text))
387
388 # The following properties exist to make unit testing possible.
389
390 def _GetFileinput(self):
391 """Accessor for Fileinput property."""
392 return self.__fileinput
393
394 def __GetFileinput(self):
395 """Indirect Accessor for _GetFileinput."""
396 return self._GetFileinput()
397
398 def _SetFileinput(self, fileinput_resource):
399 """Accessor for Fileinput property."""
400 self.__fileinput = fileinput_resource
401
402 def __SetFileinput(self, fileinput_resource):
403 """Indirect Accessor for _SetFileinput."""
404 return self._SetFileinput(fileinput_resource)
405
406 fileinput = property(
407 __GetFileinput, __SetFileinput,
408 doc="""Gets and sets the resource to use as fileinput.""")
409
410 def _GetOS(self):
411 """Accessor for os property."""
412 return self.__os
413
414 def __GetOS(self):
415 """Indirect Accessor for _GetOS."""
416 return self._GetOS()
417
418 def _SetOS(self, os_resource):
419 """Accessor for os property."""
420 self.__os = os_resource
421
422 def __SetOS(self, os_resource):
423 """Indirect Accessor for _SetOS."""
424 return self._SetOS(os_resource)
425
426 os = property(__GetOS, __SetOS,
427 doc="""Gets and sets the resource to use as os.""")
428
429 def _GetShutil(self):
430 """Accessor for shutil property."""
431 return self.__shutil
432
433 def __GetShutil(self):
434 """Indirect Accessor for _GetShutil."""
435 return self._GetShutil()
436
437 def _SetShutil(self, shutil_resource):
438 """Accessor for shutil property."""
439 self.__shutil = shutil_resource
440
441 def __SetShutil(self, shutil_resource):
442 """Indirect Accessor for _SetShutil."""
443 return self._SetShutil(shutil_resource)
444
445 shutil = property(__GetShutil, __SetShutil,
446 doc="""Gets and sets the resource to use as shutil.""")
447
448 def _GetSys(self):
449 """Accessor for sys property."""
450 return self.__sys
451
452 def __GetSys(self):
453 """Indirect Accessor for _GetSys."""
454 return self._GetSys()
455
456 def _SetSys(self, sys_resource):
457 """Accessor for sys property."""
458 self.__sys = sys_resource
459
460 def __SetSys(self, sys_resource):
461 """Indirect Accessor for _SetSys."""
462 return self._SetSys(sys_resource)
463
464 sys = property(__GetSys, __SetSys,
465 doc="""Gets and sets the resource to use as sys.""")
466
467
468 def main(argv):
469 """Prepares the new project.
470
471 Args:
472 argv: The arguments passed to the script by the shell.
473 """
474 print 'init_project parsing its arguments.'
475 script_dir = os.path.abspath(os.path.dirname(__file__))
476 options = ParseArguments(argv)
477 print 'init_project is preparing your project.'
478 # Check to see if the project is going into the SDK bundle. If so, issue a
479 # warning.
480 sdk_root_dir = os.getenv('NACL_SDK_ROOT',
481 os.path.dirname(os.path.dirname(script_dir)))
482 if sdk_root_dir:
483 if os.path.normpath(options.project_directory).count(
484 os.path.normpath(sdk_root_dir)) > 0:
485 print('WARNING: It looks like you are creating projects in the NaCl SDK '
486 'directory %s.\nThese might be removed at the next update.' %
487 sdk_root_dir)
488 project_initializer = ProjectInitializer(options.is_c_project,
489 options.is_vs_project,
490 options.project_name,
491 options.project_directory,
492 options.nacl_platform,
493 script_dir,
494 nacl_sdk_root=sdk_root_dir)
495 project_initializer.PrepareDirectoryContent()
496 project_initializer.PrepareFileContent()
497 return 0
498
499
500 if __name__ == '__main__':
501 try:
502 sys.exit(main(sys.argv[1:]))
503 except Exception as error:
504 print error
505 sys.exit(1)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698