X-Git-Url: http://nitlanguage.org diff --git a/src/android_annotations.nit b/src/android_annotations.nit index f456f96..6ef4e04 100644 --- a/src/android_annotations.nit +++ b/src/android_annotations.nit @@ -18,11 +18,11 @@ # by calling `ModelBuilder::android_project_for`. module android_annotations -import parser_util -import modelbuilder -import modelize_property +private import parser_util +import modelize import literal -import typing +import semantize +private import annotation # Metadata associated to an Android project class AndroidProject @@ -35,12 +35,24 @@ class AndroidProject # Version of the Android application and APK var version: nullable String = null + # Numerical version code of the Android application and APK + var version_code: Int = 0 + # Custom lines to add to the AndroidManifest.xml in the node var manifest_lines = new Array[String] # Custom lines to add to the AndroidManifest.xml in the node var manifest_application_lines = new Array[String] + # Minimum API level required for the application to run + var min_api: nullable Int = null + + # Build target API level + var target_api: nullable Int = null + + # Maximum API level on which the application will be allowed to run + var max_api: nullable Int = null + redef fun to_s do return """ name: {{{name or else "null"}}} namespace: {{{java_package or else "null"}}} @@ -53,106 +65,60 @@ redef class ModelBuilder do var project = new AndroidProject - var annot = priority_annotation_on_modules("app_name", mmodule) + var annot = lookup_annotation_on_modules("app_name", mmodule) if annot != null then project.name = annot.arg_as_string(self) - annot = priority_annotation_on_modules("app_version", mmodule) + annot = lookup_annotation_on_modules("app_version", mmodule) if annot != null then project.version = annot.as_version(self) - annot = priority_annotation_on_modules("java_package", mmodule) + annot = lookup_annotation_on_modules("java_package", mmodule) if annot != null then project.java_package = annot.arg_as_string(self) - var annots = collect_annotations_on_modules("android_manifest", mmodule) - for an in annots do project.manifest_lines.add an.arg_as_string(self) - - annots = collect_annotations_on_modules("android_manifest_application", mmodule) - for an in annots do project.manifest_application_lines.add an.arg_as_string(self) - - toolcontext.check_errors - - return project - end - - # Recursively collect all annotations by name in `mmodule` and its importations (direct and indirect) - private fun collect_annotations_on_modules(name: String, mmodule: MModule): Array[AAnnotation] - do - var annotations = new Array[AAnnotation] - for mmod in mmodule.in_importation.greaters do - if not mmodule2nmodule.keys.has(mmod) then continue - var amod = mmodule2nmodule[mmod] - var module_decl = amod.n_moduledecl - if module_decl == null then continue - var aas = module_decl.collect_annotations_by_name(name) - annotations.add_all aas - end - return annotations - end - - # Get an annotation by name from `mmodule` and its super modules. Will recursively search - # in imported module to find the "latest" declaration and detects priority conflicts. - private fun priority_annotation_on_modules(name: String, mmodule: MModule): nullable AAnnotation - do - if mmodule2nmodule.keys.has(mmodule) then - var amod = mmodule2nmodule[mmodule] - var module_decl = amod.n_moduledecl - if module_decl != null then - var annotations = module_decl.collect_annotations_by_name(name) - if annotations.length == 1 then - return annotations.first - else if annotations.length > 1 then - toolcontext.error(mmodule.location, - "Multiple declaration of annotation {name}, it must be defined only once.") - end + var annots = collect_annotations_on_modules("min_api_version", mmodule) + if not annots.is_empty then + var i = annots.pop.arg_as_int(self) + if i == null then i = 0 + project.min_api = i + for an in annots do + i = an.arg_as_int(self) + if i == null then continue + project.min_api = project.min_api.max(i) end end - var sources = new Array[MModule] - var annotations = null - for mmod in mmodule.in_importation.direct_greaters do - var res = priority_annotation_on_modules(name, mmod) - if res != null then - sources.add mmod - annotations = res + annots = collect_annotations_on_modules("max_api_version", mmodule) + if not annots.is_empty then + var i = annots.pop.arg_as_int(self) + if i == null then i = 0 + project.max_api = i + for an in annots do + i = an.arg_as_int(self) + if i == null then continue + project.max_api = project.max_api.min(i) end end - if sources.length > 1 then - toolcontext.error(mmodule.location, - "Priority conflict on annotation {name}, it has been defined in: {sources.join(", ")}") - return null - end - return annotations - end -end -redef class AAnnotation - # Get the single argument of `self` as a `String`. Raise error on any inconsistency. - private fun arg_as_string(modelbuilder: ModelBuilder): String - do - var annotation_name = n_atid.n_id.text - var format_error = "Annotation error: \"{annotation_name}\" expects a single String as argument." + annot = lookup_annotation_on_modules("target_api_version", mmodule) + if annot != null then project.target_api = annot.arg_as_int(self) or else 0 - var args = n_args - var platform_name - if args.length != 1 then - modelbuilder.error(self, format_error) - return "" - else - var arg = args.first - - if not arg isa AExprAtArg then - modelbuilder.error(self, format_error) - return "" - end + annots = collect_annotations_on_modules("android_manifest", mmodule) + for an in annots do project.manifest_lines.add an.arg_as_string(self) or else "" - var expr = arg.n_expr - if not expr isa AStringFormExpr then - modelbuilder.error(self, format_error) - return "" - end - return expr.value.as(not null) - end + annots = collect_annotations_on_modules("android_manifest_application", mmodule) + for an in annots do project.manifest_application_lines.add an.arg_as_string(self) or else "" + + # Get the date and time (down to the minute) as string + var local_time = new Tm.localtime + var local_time_s = local_time.strftime("%y%m%d%H%M") + project.version_code = local_time_s.to_i + + toolcontext.check_errors + + return project end +end +redef class AAnnotation # Returns a version string (example: "1.5.6b42a7c") from an annotation `version(1, 5, git_revision)`. # # The user can enter as many fields as needed. The call to `git_revision` will be replaced by the short @@ -165,33 +131,26 @@ redef class AAnnotation var args = n_args var platform_name if args.length < 1 then - modelbuilder.error(self, "Annotation error: \"{annotation_name}\" expects at least a single argument.") + modelbuilder.error(self, "Annotation error: \"{name}\" expects at least a single argument.") return "" else for arg in args do - var format_error = "Annotation error: \"{annotation_name}\" expects its arguments to be of type Int or a call to `git_revision`" + var format_error = "Annotation error: \"{name}\" expects its arguments to be of type Int or a call to `git_revision`" - if not arg isa AExprAtArg then - modelbuilder.error(self, format_error) - return "" + var value + value = arg.as_int + if value != null then + version_fields.add value + continue end - var expr = arg.n_expr - if expr isa AIntExpr then - var value = expr.value - assert value != null + value = arg.as_string + if value != null then version_fields.add value - else if expr isa AStringFormExpr then - version_fields.add expr.value.as(not null) - else if expr isa ACallExpr then - # We support calls to "git" only - var exec_args = expr.n_args.to_a - if expr.n_id.text != "git_revision" or not exec_args.is_empty then - modelbuilder.error(self, - "Annotation error: \"{annotation_name}\" accepts only calls to `git_revision` with the command as arguments.") - return "" - end + end + value = arg.as_id + if value == "git_revision" then # Get Git short revision var proc = new IProcess("git", "rev-parse", "--short", "HEAD") proc.wait @@ -207,10 +166,11 @@ redef class AAnnotation if dirty then revision += ".d" version_fields.add revision - else - modelbuilder.error(self, format_error) - return "" + continue end + + modelbuilder.error(self, format_error) + return "" end end