Merge: doc: fixed some typos and other misc. corrections
[nit.git] / src / platform / app_annotations.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Annotations to gather metadata on `app.nit` projects
16 module app_annotations
17
18 private import parser_util
19 import modelize
20 import literal
21 import semantize
22 private import annotation
23
24 # Metadata associated to an `app.nit` project
25 class AppProject
26 # Pretty name of the resulting application
27 var name: String = mainmodule.first_real_mmodule.name is lazy
28
29 # Short project name used in `namespace` and configuration files
30 var short_name: String = mainmodule.name.replace("-", "_") is lazy
31
32 # Namespace/package used to identify the application
33 var namespace = "org.nitlanguage.{short_name}" is lazy
34
35 # Version of the application
36 var version = "0.1"
37
38 # Numerical version code of the application
39 var version_code: Int is lazy do
40
41 # Get the date and time (down to the minute) as string
42 var gmtime = new Tm.gmtime
43 var local_time_s = gmtime.strftime("%y%m%d%H%M")
44 return local_time_s.to_i
45 end
46
47 # Extra folders where to find platform specific resource files
48 var files = new Array[String]
49
50 private var modelbuilder: ModelBuilder
51 private var mainmodule: MModule
52
53 init
54 do
55 var annot = modelbuilder.lookup_annotation_on_modules("app_name", mainmodule)
56 if annot != null then
57 var val = annot.arg_as_string(modelbuilder)
58 if val != null then name = val
59 end
60
61 annot = modelbuilder.lookup_annotation_on_modules("app_version", mainmodule)
62 if annot != null then version = annot.as_version(modelbuilder)
63
64 annot = modelbuilder.lookup_annotation_on_modules("app_namespace", mainmodule)
65 if annot != null then
66 var val = annot.arg_as_string(modelbuilder)
67 if val != null then namespace = val
68 end
69
70 var annots = modelbuilder.collect_annotations_on_modules("app_files", mainmodule)
71 for a in annots do files.add_all a.as_relative_paths(modelbuilder)
72
73 modelbuilder.toolcontext.check_errors
74 end
75
76 redef fun to_s do return """
77 name: {{{name}}}
78 namespace: {{{namespace}}}
79 version: {{{version}}}"""
80 end
81
82 redef class AAnnotation
83 # Returns a version string (example: "1.5.6b42a7c") from an annotation `version(1, 5, git_revision)`.
84 #
85 # The user can enter as many fields as needed. The call to `git_revision` will be replaced by the short
86 # revision number. If the working tree is dirty, it will append another field with "d" for dirty.
87 private fun as_version(modelbuilder: ModelBuilder): String
88 do
89 var version_fields = new Array[Object]
90
91 var args = n_args
92 if args.length < 1 then
93 modelbuilder.error(self, "Syntax Error: `{name}` expects at least one argument.")
94 return ""
95 else
96 for arg in args do
97 var value
98 value = arg.as_int
99 if value != null then
100 version_fields.add value
101 continue
102 end
103
104 value = arg.as_string
105 if value != null then
106 version_fields.add value
107 end
108
109 value = arg.as_id
110 if value == "git_revision" then
111 # Get Git short revision
112 var proc = new ProcessReader("git", "rev-parse", "--short", "HEAD")
113 proc.wait
114 if proc.status != 0 then
115 # Fallback if this is not a git repository or git bins are missing
116 version_fields.add "0"
117 modelbuilder.warning(self, "git_revision", "Warning: `git_revision` used outside of a git repository or git binaries not available")
118 continue
119 end
120
121 var lines = proc.read_all
122 var revision = lines.split("\n").first
123
124 # Is it dirty?
125 # If not, the return of `git diff --shortstat` is an empty line
126 proc = new ProcessReader("git", "diff-index", "--quiet", "HEAD")
127 proc.wait
128 var dirty = proc.status != 0
129 if dirty then revision += ".d"
130
131 version_fields.add revision
132 continue
133 end
134
135 var format_error = "Syntax Error: `{name}` expects its arguments to be of type Int or a call to `git_revision`."
136 modelbuilder.error(self, format_error)
137 return ""
138 end
139 end
140
141 return version_fields.join(".")
142 end
143
144 # Parse all arguments as paths relative to the declaring module
145 #
146 # If no arguments are given, then use the parent directory of the module.
147 private fun as_relative_paths(modelbuilder: ModelBuilder): Array[String]
148 do
149 var paths = new Array[String]
150
151 var file = location.file
152 if file == null then return paths
153
154 var args = n_args
155 if args.is_empty then
156 paths.add file.filename.dirname
157 else
158 for arg in args do
159 var val = arg.as_string
160 if val != null then
161 paths.add file.filename.dirname/val
162 else modelbuilder.error(arg, "Syntax Error: `app_files` expects String literals as arguments.")
163 end
164 end
165
166 return paths
167 end
168 end